DM5314_USimpleTCP.pas
上传用户:hndmjx
上传日期:2014-09-16
资源大小:3369k
文件大小:32k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*************************************************************}
  2. {            SimpleTCP components for Delphi and C++ Builder  }
  3. { Version:   2.0                                              }
  4. { E-Mail:    info@utilmind.com                                }
  5. { WWW:       http://www.utilmind.com                          }
  6. { Created:   July 8, 2000                                     }
  7. { Modified:  January 17, 2002                                 }
  8. { Legal:     Copyright (c) 2000-2002, UtilMind Solutions      }
  9. {*************************************************************}
  10. { SimpleTCP is pack of two components (TSimpleTCPServer and   }
  11. { TSimpleTCPClient) for working with Asynchronous TCP sockets.}
  12. {*************************************************************}
  13. { Please see demo program for more information.               }
  14. {*************************************************************}
  15. {                     IMPORTANT NOTE:                         }
  16. { This software is provided 'as-is', without any express or   }
  17. { implied warranty. In no event will the author be held       }
  18. { liable for any damages arising from the use of this         }
  19. { software.                                                   }
  20. { Permission is granted to anyone to use this software for    }
  21. { any purpose, including commercial applications, and to      }
  22. { alter it and redistribute it freely, subject to the         }
  23. { following restrictions:                                     }
  24. { 1. The origin of this software must not be misrepresented,  }
  25. {    you must not claim that you wrote the original software. }
  26. {    If you use this software in a product, an acknowledgment }
  27. {    in the product documentation would be appreciated but is }
  28. {    not required.                                            }
  29. { 2. Altered source versions must be plainly marked as such,  }
  30. {    and must not be misrepresented as being the original     }
  31. {    software.                                                }
  32. { 3. This notice may not be removed or altered from any       }
  33. {    source distribution.                                     }
  34. {*************************************************************}
  35. {$IFNDEF VER80}          {Delphi 1}
  36.  {$IFNDEF VER90}         {Delphi 2}
  37.   {$IFNDEF VER93}        {BCB 1}
  38.    {$DEFINE D3}          {* Delphi 3 or higher}
  39.    {$IFNDEF VER100}      {Delphi 3}
  40.     {$IFNDEF VER110}     {BCB 3}
  41.      {$DEFINE D4}        {* Delphi 4 or higher}
  42.     {$ENDIF}
  43.    {$ENDIF}
  44.   {$ENDIF}
  45.  {$ENDIF}
  46. {$ENDIF}
  47. unit DM5314_USimpleTCP;
  48. interface
  49. uses
  50.   Windows, Messages, Classes, WinSock;
  51. const
  52.   UM_TCPASYNCSELECT = WM_USER + $0001;
  53. type
  54.   TSimpleTCPClient = class;
  55.   TSimpleTCPAcceptEvent = procedure(Sender: TObject; Client: TSimpleTCPClient; var Accept: Boolean) of object;
  56.   TSimpleTCPServerEvent = procedure(Sender: TObject; Client: TSimpleTCPClient) of object;
  57.   TSimpleTCPServerDataAvailEvent = procedure(Sender: TObject; Client: TSimpleTCPClient; DataSize: Integer) of object;
  58.   TSimpleTCPClientDataAvailEvent = procedure(Sender: TObject; DataSize: Integer) of object;
  59.   TSimpleTCPServerIOEvent = procedure(Sender: TObject; Client: TSimpleTCPClient; Stream: TStream) of object;
  60.   TSimpleTCPClientIOEvent = procedure(Sender: TObject; Stream: TStream) of object;
  61.   TSimpleTCPErrorEvent = procedure(Sender: TObject; Socket: TSocket; ErrorCode: Integer; ErrorMsg: String) of object;
  62.   TCustomSimpleSocket = class(TComponent)
  63.   private
  64.     FAllowChangeHostAndPortOnConnection: Boolean;
  65.     FHost: String;
  66.     FPort: Word;
  67.     FSocket: TSocket;
  68.     FOnError: TSimpleTCPErrorEvent;
  69.     // For internal use
  70.     FConnections: TList;
  71.     SockAddrIn: TSockAddrIn;
  72.     HostEnt: PHostEnt;
  73.     WSAData: TWSAData;
  74.     WindowHandle: hWnd;
  75.     procedure WndProc(var Message: TMessage); virtual;
  76.     procedure UMTCPSelect(var Msg: TMessage); message UM_TCPASYNCSELECT;
  77.     function  SendBufferTo(Socket: TSocket; Buffer: PChar; BufLength: Integer): Integer; // returns N of bytes sent
  78.     function  SendStreamTo(Socket: TSocket; Stream: TStream): Integer; // returns N of bytes sent
  79.     function  ReceiveFrom(Socket: TSocket; Buffer: PChar; BufLength: Integer; ReceiveCompletely: Boolean): Integer; // returns N of bytes read
  80.     function  ReceiveStreamFrom(Socket: TSocket; Stream: TStream; DataSize: Integer; ReceiveCompletely: Boolean): Integer; // returns N of bytes read
  81.   protected
  82.     procedure SocketError(Socket: TSocket; ErrorCode: Integer); virtual;
  83.     procedure SetHost(Value: String); virtual; abstract;
  84.     procedure SetPort(Value: Word); virtual; abstract;
  85.     procedure DoAccept; virtual; abstract;
  86.     procedure DoConnect; virtual; abstract;
  87.     procedure DoClose(Socket: TSocket); virtual; abstract;
  88.     procedure DoDataAvailable(Client: TSimpleTCPClient; DataSize: Integer; var Handled: Boolean); virtual; abstract;
  89.     procedure DoRead(Client: TSimpleTCPClient; Stream: TStream); virtual; abstract;
  90.   public
  91.     constructor Create(aOwner: TComponent); override;
  92.     destructor Destroy; override;
  93.     property AllowChangeHostAndPortOnConnection: Boolean read FAllowChangeHostAndPortOnConnection write FAllowChangeHostAndPortOnConnection default False;
  94.     property Host: String read FHost write SetHost;
  95.     property Port: Word read FPort write SetPort default 0;
  96.     property Socket: TSocket read FSocket write FSocket;
  97.     property OnError: TSimpleTCPErrorEvent read FOnError write FOnError;
  98.   end;
  99.   { TSimpleTCPServer }
  100.   TSimpleTCPServer = class(TCustomSimpleSocket)
  101.   private
  102.     FListen: Boolean;
  103.     FOnAccept: TSimpleTCPAcceptEvent;
  104.     FOnClientConnected: TSimpleTCPServerEvent;
  105.     FOnClientDisconnected: TSimpleTCPServerEvent;
  106.     FOnClientDataAvailable: TSimpleTCPServerDataAvailEvent;
  107.     FOnClientRead: TSimpleTCPServerIOEvent;
  108.     function GetLocalHostName: String;
  109.     function GetLocalIP: String;
  110.     procedure SetNoneStr(Value: String);
  111.   protected
  112.     procedure SocketError(Socket: TSocket; ErrorCode: Integer); override;
  113.     procedure SetListen(Value: Boolean); virtual;
  114.     procedure SetPort(Value: Word); override;
  115.     procedure DoAccept; override;
  116.     procedure DoClose(Socket: TSocket); override;
  117.     procedure DoDataAvailable(Client: TSimpleTCPClient; DataSize: Integer; var Handled: Boolean); override;    
  118.     procedure DoRead(Client: TSimpleTCPClient; Stream: TStream); override;
  119.   public
  120.     constructor Create(aOwner: TComponent); override;
  121.     destructor Destroy; override;
  122.     function  Send(Client: TSimpleTCPClient; Buffer: PChar; BufLength: Integer): Integer; // returns N of bytes sent
  123.     function  SendStream(Client: TSimpleTCPClient; Stream: TStream): Integer; // returns N of bytes sent
  124.     procedure Broadcast(Buffer: PChar; BufLength: Integer);
  125.     procedure BroadcastStream(Stream: TStream);
  126.     function  Receive(Client: TSimpleTCPClient; Buffer: PChar; BufLength: Integer; ReceiveCompletely: Boolean): Integer;
  127.     function  ReceiveStream(Client: TSimpleTCPClient; Stream: TStream; DataSize: Integer; ReceiveCompletely: Boolean): Integer;
  128.     property Connections: TList read FConnections;
  129.   published
  130.     property Listen: Boolean read FListen write SetListen stored False;
  131.     property LocalHostName: String read GetLocalHostName write SetNoneStr stored False;
  132.     property LocalIP: String read GetLocalIP write SetNoneStr stored False;    
  133.     property OnAccept: TSimpleTCPAcceptEvent read FOnAccept write FOnAccept;
  134.     property OnClientConnected: TSimpleTCPServerEvent read FOnClientConnected write FOnClientConnected;
  135.     property OnClientDisconnected: TSimpleTCPServerEvent read FOnClientDisconnected write FOnClientDisconnected;
  136.     property OnClientDataAvailable: TSimpleTCPServerDataAvailEvent read FOnClientDataAvailable write FOnClientDataAvailable;
  137.     property OnClientRead: TSimpleTCPServerIOEvent read FOnClientRead write FOnClientRead;
  138.     property AllowChangeHostAndPortOnConnection;
  139.     property Port;
  140.     property OnError;
  141.   end;
  142.   TSimpleTCPClient = class(TCustomSimpleSocket)
  143.   private
  144.     FAutoTryReconnect: Boolean;
  145.     FConditionallyConnected, FConnected: Boolean;
  146.     FOnConnected: TNotifyEvent;
  147.     FOnDisconnected: TNotifyEvent;
  148.     FOnDataAvailable: TSimpleTCPClientDataAvailEvent;
  149.     FOnRead: TSimpleTCPClientIOEvent;
  150.     function  GetIP: LongInt;
  151.     procedure SetIP(Value: LongInt);
  152.   protected
  153. //    procedure WndProc(var Message: TMessage); override;
  154.     procedure SocketError(Socket: TSocket; ErrorCode: Integer); override;
  155.     procedure SetConnected(Value: Boolean); virtual;    
  156.     procedure SetHost(Value: String); override;
  157.     procedure SetPort(Value: Word); override;
  158.     procedure DoConnect; override;
  159.     procedure DoClose(Socket: TSocket); override;
  160.     procedure DoDataAvailable(Client: TSimpleTCPClient; DataSize: Integer; var Handled: Boolean); override;    
  161.     procedure DoRead(Client: TSimpleTCPClient; Stream: TStream); override;
  162.   public
  163.     destructor Destroy; override;
  164.     function Send(Buffer: PChar; BufLength: Integer): Integer; // returns N of bytes sent
  165.     function SendStream(Stream: TStream): Integer; // returns N of bytes sent
  166.     function Receive(Buffer: PChar; BufLength: Integer; ReceiveCompletely: Boolean): Integer;
  167.     function ReceiveStream(Stream: TStream; DataSize: Integer; ReceiveCompletely: Boolean): Integer;
  168.     property IP: LongInt read GetIP write SetIP;
  169.   published
  170.     property AutoTryReconnect: Boolean read FAutoTryReconnect write FAutoTryReconnect default False;
  171.     property Connected: Boolean read FConnected write SetConnected stored False;
  172.     property OnConnected: TNotifyEvent read FOnConnected write FOnConnected;
  173.     property OnDisconnected: TNotifyEvent read FOnDisconnected write FOnDisconnected;
  174.     property OnDataAvailable: TSimpleTCPClientDataAvailEvent read FOnDataAvailable write FOnDataAvailable;
  175.     property OnRead: TSimpleTCPClientIOEvent read FOnRead write FOnRead;
  176.     property AllowChangeHostAndPortOnConnection;
  177.     property Host;
  178.     property Port;
  179.     property OnError;
  180.   end;
  181. procedure Register;
  182. implementation
  183. uses SysUtils, Forms;
  184. const
  185.   PROTO_TCP = 'tcp';
  186. {$IFNDEF D4}
  187. type
  188.   SunB = packed record
  189.     s_b1, s_b2, s_b3, s_b4: Char;
  190.   end;
  191.   SunW = packed record
  192.     s_w1, s_w2: Word;
  193.   end;
  194.   in_addr = record
  195.     case Integer of
  196.       0: (S_un_b: SunB);
  197.       1: (S_un_w: SunW);
  198.       2: (S_addr: LongInt);
  199.   end;
  200. {$ENDIF}
  201. { Internal utilities }
  202. function IPToStr(IP: Integer): String;
  203. var
  204.   Addr: in_addr;
  205. begin
  206.   Addr.S_addr := IP;
  207.   Result := IntToStr(Byte(Addr.S_un_b.s_b1)) + '.' +
  208.             IntToStr(Byte(Addr.S_un_b.s_b2)) + '.' +
  209.             IntToStr(Byte(Addr.S_un_b.s_b3)) + '.' +
  210.             IntToStr(Byte(Addr.S_un_b.s_b4));
  211. end;
  212. function StrToIP(Host: String): LongInt;
  213. begin
  214.   Result := inet_addr(PChar(Host))  
  215. end;
  216. { TCustomSimpleSocket }
  217. constructor TCustomSimpleSocket.Create(aOwner: TComponent);
  218. begin
  219.   inherited Create(aOwner);
  220.   FSocket := INVALID_SOCKET;
  221.   WindowHandle := AllocateHWnd(WndProc);
  222.   if WSAStartup($0101, WSAData) <> 0 then
  223.     raise Exception.Create('Can not start socket session');
  224. end;
  225. destructor TCustomSimpleSocket.Destroy;
  226. begin
  227.   if WSACleanup <> 0 then
  228.     raise Exception.Create('Can not clean socket session');
  229.   DeallocateHWnd(WindowHandle);
  230.   inherited Destroy;
  231. end;
  232. procedure TCustomSimpleSocket.WndProc(var Message: TMessage);
  233. begin
  234.   with Message do
  235.    try
  236.      if Msg = WM_QUERYENDSESSION then
  237.        Result := 1 // Correct shutdown
  238.      else
  239.        Dispatch(Msg);
  240.    except
  241.      Application.HandleException(Self);
  242.    end;
  243. end;
  244. procedure TCustomSimpleSocket.UMTCPSelect(var Msg: TMessage);
  245. var
  246.   tmpSocket: TSocket;
  247.   tmpTCPClient: TSimpleTCPClient;
  248.   SelectEvent, I: Integer;
  249.   MS: TMemoryStream;
  250.   Handled: Boolean;
  251.   DataAvail: LongInt;
  252. begin
  253.   I := WSAGetSelectError(Msg.LParam);
  254.   if I > WSABASEERR then
  255.     SocketError(Msg.wParam, I)
  256.   else
  257.    begin
  258.     SelectEvent := WSAGetSelectEvent(Msg.lParam);
  259.     case SelectEvent of
  260.       FD_READ: begin
  261.                 tmpSocket := Msg.wParam;
  262.                 { if this is the server }
  263.                 tmpTCPClient := nil;
  264.                 if Assigned(FConnections) then
  265.                  begin
  266.                   I := FConnections.Count;
  267.                   if I <> 0 then
  268.                    for I := 0 to I - 1 do
  269.                     begin
  270.                      tmpTCPClient := FConnections[I];
  271.                      if tmpTCPClient.FSocket = tmpSocket then Break;
  272.                     end;
  273.                  end;
  274.                 MS := TMemoryStream.Create;
  275.                 with MS do
  276.                  try
  277.                    while True do
  278.                     begin
  279.                      { check whether data available }
  280.                      if IoctlSocket(tmpSocket, FIONREAD, DataAvail) = SOCKET_ERROR then
  281.                       begin
  282.                        SocketError(tmpSocket, WSAGetLastError);
  283.                        Exit;
  284.                       end;
  285.                      if DataAvail = 0 then Break;
  286.                      Handled := False;
  287.                      DoDataAvailable(tmpTCPClient, DataAvail, Handled);
  288.                      if not Handled then
  289.                        ReceiveStreamFrom(tmpSocket, MS, DataAvail, False);
  290.                     end;
  291.                    if not Handled and (MS.Size <> 0) then
  292.                     begin
  293.                      Seek(0, soFromBeginning); { to beginning of stream }
  294.                      DoRead(tmpTCPClient, MS);
  295.                     end; 
  296.                  finally
  297.                    Free;
  298.                  end;
  299.                end;
  300.       FD_CLOSE: DoClose(Msg.wParam);
  301.       FD_ACCEPT: DoAccept;
  302.       FD_CONNECT: DoConnect;            
  303.      end;
  304.    end;
  305. end;
  306. procedure TCustomSimpleSocket.SocketError(Socket: TSocket; ErrorCode: Integer);
  307. var
  308.   ErrorMsg: String;
  309. begin
  310.   case ErrorCode of
  311.     WSAEINTR: ErrorMsg := 'Interrupted system call';
  312.     WSAEBADF: ErrorMsg := 'Bad file number';
  313.     WSAEACCES: ErrorMsg := 'Permission denied';
  314.     WSAEFAULT: ErrorMsg := 'Bad address';
  315.     WSAEINVAL: ErrorMsg := 'Invalid argument';
  316.     WSAEMFILE: ErrorMsg := 'Too many open files';
  317.     WSAEWOULDBLOCK: ErrorMsg := 'Operation would block';
  318.     WSAEINPROGRESS: ErrorMsg := 'Operation now in progress';
  319.     WSAEALREADY: ErrorMsg := 'Operation already in progress';
  320.     WSAENOTSOCK: ErrorMsg := 'Socket operation on non-socket';
  321.     WSAEDESTADDRREQ: ErrorMsg := 'Destination address required';
  322.     WSAEMSGSIZE: ErrorMsg := 'Message too long';
  323.     WSAEPROTOTYPE: ErrorMsg := 'Protocol wrong type for socket';
  324.     WSAENOPROTOOPT: ErrorMsg := 'Protocol not available';
  325.     WSAEPROTONOSUPPORT: ErrorMsg := 'Protocol not supported';
  326.     WSAESOCKTNOSUPPORT: ErrorMsg := 'Socket type not supported';
  327.     WSAEOPNOTSUPP: ErrorMsg := 'Operation not supported on socket';
  328.     WSAEPFNOSUPPORT: ErrorMsg := 'Protocol family not supported';
  329.     WSAEAFNOSUPPORT: ErrorMsg := 'Address family not supported by protocol family';
  330.     WSAEADDRINUSE: ErrorMsg := 'Address already in use';
  331.     WSAEADDRNOTAVAIL: ErrorMsg := 'Can''t assign requested address';
  332.     WSAENETDOWN: ErrorMsg := 'Network is down';
  333.     WSAENETUNREACH: ErrorMsg := 'Network is unreachable';
  334.     WSAENETRESET: ErrorMsg := 'Network dropped connection on reset';
  335.     WSAECONNABORTED: ErrorMsg := 'Software caused connection abort';
  336.     WSAECONNRESET: ErrorMsg := 'Connection reset by peer';
  337.     WSAENOBUFS: ErrorMsg := 'No buffer space available';
  338.     WSAEISCONN: ErrorMsg := 'Socket is already connected';
  339.     WSAENOTCONN: ErrorMsg := 'Socket is not connected';
  340.     WSAESHUTDOWN: ErrorMsg := 'Can''t send after socket shutdown';
  341.     WSAETOOMANYREFS: ErrorMsg := 'Too many references: can''t splice';
  342.     WSAETIMEDOUT: ErrorMsg := 'Connection timed out';
  343.     WSAECONNREFUSED: ErrorMsg := 'Connection refused';
  344.     WSAELOOP: ErrorMsg := 'Too many levels of symbolic links';
  345.     WSAENAMETOOLONG: ErrorMsg := 'File name too long';
  346.     WSAEHOSTDOWN: ErrorMsg := 'Host is down';
  347.     WSAEHOSTUNREACH: ErrorMsg := 'No route to host';
  348.     WSAENOTEMPTY: ErrorMsg := 'Directory not empty';
  349.     WSAEPROCLIM: ErrorMsg := 'Too many processes';
  350.     WSAEUSERS: ErrorMsg := 'Too many users';
  351.     WSAEDQUOT: ErrorMsg := 'Disk quota exceeded';
  352.     WSAESTALE: ErrorMsg := 'Stale NFS file handle';
  353.     WSAEREMOTE: ErrorMsg := 'Too many levels of remote in path';
  354.     WSASYSNOTREADY: ErrorMsg := 'Network sub-system is unusable';
  355.     WSAVERNOTSUPPORTED: ErrorMsg := 'WinSock DLL cannot support this application';
  356.     WSANOTINITIALISED: ErrorMsg := 'WinSock not initialized';
  357.     WSAHOST_NOT_FOUND: ErrorMsg := 'Host not found';
  358.     WSATRY_AGAIN: ErrorMsg := 'Non-authoritative host not found';
  359.     WSANO_RECOVERY: ErrorMsg := 'Non-recoverable error';
  360.     WSANO_DATA: ErrorMsg := 'No Data';
  361.     else ErrorMsg := 'Not a WinSock error ?';
  362.   end;
  363.   
  364.   if Assigned(FOnError) then
  365.     FOnError(Self, Socket, ErrorCode, ErrorMsg)
  366.   else
  367.     //raise Exception.Create(ErrorMsg);
  368. end;
  369. function TCustomSimpleSocket.SendBufferTo(Socket: TSocket; Buffer: PChar; BufLength: Integer): Integer; // bytes sent
  370. begin
  371.   Result := 0;
  372.   if (Socket <> INVALID_SOCKET) and (BufLength <> 0) then
  373.    begin
  374.     Result := WinSock.Send(Socket, Buffer^, BufLength, 0);
  375.     if Result = SOCKET_ERROR then
  376.       SocketError(Socket, WSAGetLastError);
  377.    end;
  378. end;
  379. function  TCustomSimpleSocket.SendStreamTo(Socket: TSocket; Stream: TStream): Integer; // returns N of bytes sent
  380. var
  381.   Buffer: Pointer;
  382.   SavePosition: LongInt;
  383. begin
  384.   Result := 0;
  385.   if (Socket <> INVALID_SOCKET) and (Stream <> nil) then
  386.    begin
  387.     { save position in stream and go to beginning }
  388.     SavePosition := Stream.Position;
  389.     Stream.Seek(0, soFromBeginning);
  390.     try
  391.       { allocate memory for swap buffer }
  392.       GetMem(Buffer, Stream.Size);
  393.       try
  394.         { filling the buffer from stream }
  395.         Stream.Read(Buffer^, Stream.Size);
  396.         { SENDING! }
  397.         Result := WinSock.Send(Socket, Buffer^, Stream.Size, 0);
  398.         if Result = SOCKET_ERROR then { process the error if occurs }
  399.           SocketError(Socket, WSAGetLastError);
  400.       finally
  401.         { release memory taken for buffer }
  402.         FreeMem(Buffer);
  403.       end;  
  404.     finally
  405.       { restore position in stream }
  406.       Stream.Seek(SavePosition, soFromBeginning);
  407.     end;  
  408.    end;
  409. end;
  410. function TCustomSimpleSocket.ReceiveFrom(Socket: TSocket; Buffer: PChar; BufLength: Integer; ReceiveCompletely: Boolean): Integer;
  411. var
  412.   p: Pointer;
  413.   DataAvail: LongInt;
  414. begin
  415.   Result := recv(Socket, Buffer^, BufLength, 0);
  416.   if Result = SOCKET_ERROR then
  417.    begin
  418.     SocketError(Socket, WSAGetLastError);
  419.     Exit;
  420.    end;
  421.   if ReceiveCompletely then
  422.    while Result < BufLength do
  423.     begin
  424.      if IoctlSocket(Socket, FIONREAD, DataAvail) = SOCKET_ERROR then
  425.       begin
  426.        SocketError(Socket, WSAGetLastError);
  427.        Exit;
  428.       end;
  429.      if DataAvail = 0 then Continue;
  430.      p := Pointer(Integer(Buffer) + Result);
  431.      DataAvail := recv(Socket, p^, BufLength - Result, 0);
  432.      if DataAvail = SOCKET_ERROR then
  433.       begin
  434.        SocketError(Socket, WSAGetLastError);
  435.        Exit;
  436.       end;
  437.      inc(Result, DataAvail);
  438.     end;
  439. end;
  440. function  TCustomSimpleSocket.ReceiveStreamFrom(Socket: TSocket; Stream: TStream; DataSize: Integer; ReceiveCompletely: Boolean): Integer;
  441. var
  442.   Buf: Pointer;
  443. begin
  444.   Result := 0;
  445.   if DataSize <= 0 then Exit;
  446.   
  447.   GetMem(Buf, DataSize);
  448.   try
  449.     Result := ReceiveFrom(Socket, Buf, DataSize, ReceiveCompletely);
  450.     if Result <> 0 then
  451.       Stream.Write(Buf^, Result);
  452.   finally
  453.     FreeMem(Buf);
  454.   end;
  455. end;
  456. {------------------------------------------------------------}
  457. { TSimpleTCPServer }
  458. constructor TSimpleTCPServer.Create(aOwner: TComponent);
  459. begin
  460.   inherited Create(aOwner);
  461.   FConnections := TList.Create;
  462. end;
  463. destructor TSimpleTCPServer.Destroy;
  464. begin
  465.   Listen := False;  // cancel listening
  466.   FConnections.Free;
  467.   inherited Destroy;
  468. end;
  469. procedure TSimpleTCPServer.SocketError(Socket: TSocket; ErrorCode: Integer);
  470. begin
  471.   Listen := true;  // cancel listening
  472.   inherited;
  473. end;
  474. procedure TSimpleTCPServer.DoAccept;
  475. var
  476.   Tmp: Integer;
  477.   tmpSocket: TSocket;
  478.   tmpTCPClient: TSimpleTCPClient;
  479.   IsAccept: Boolean;
  480. begin
  481.   Tmp := SizeOf(SockAddrIn);
  482.   {$IFNDEF D3}
  483.   tmpSocket := WinSock.Accept(FSocket, SockAddrIn, Tmp);
  484.   {$ELSE}
  485.   tmpSocket := WinSock.Accept(FSocket, @SockAddrIn, @Tmp);
  486.   {$ENDIF}
  487.   if tmpSocket = SOCKET_ERROR then
  488.     SocketError(tmpSocket, WSAGetLastError);
  489. {$WARNINGS OFF}
  490.   tmpTCPClient := TSimpleTCPClient.Create(nil);
  491. {$WARNINGS ON}
  492.   tmpTCPClient.FSocket := tmpSocket;
  493.   tmpTCPClient.FHost := inet_ntoa(SockAddrIn.SIn_Addr);
  494.   tmpTCPClient.FPort := FPort;
  495.   tmpTCPClient.FConnected := True;
  496.   if Assigned(FOnAccept) then
  497.    begin
  498.     IsAccept := True;
  499.     FOnAccept(Self, tmpTCPClient, IsAccept);
  500.     if IsAccept then
  501.       Connections.Add(tmpTCPClient)
  502.     else
  503.       tmpTCPClient.Free;
  504.    end
  505.   else
  506.    Connections.Add(tmpTCPClient);
  507.   if Assigned(FOnClientConnected) then
  508.     FOnClientConnected(Self, tmpTCPClient);
  509. end;
  510. procedure TSimpleTCPServer.DoClose(Socket: TSocket);
  511. var
  512.   I: Integer;
  513.   tmpTCPClient: TSimpleTCPClient;
  514. begin
  515.   tmpTCPClient := nil;
  516.   I := FConnections.Count;
  517.   if I <> 0 then
  518.    for I := 0 to I - 1 do
  519.     begin
  520.      tmpTCPClient := FConnections[I];
  521.      if tmpTCPClient.FSocket = Socket then
  522.       begin
  523.        FConnections.Delete(I);
  524.        Break;
  525.       end;
  526.     end;
  527.   if Assigned(tmpTCPClient) then
  528.    begin
  529.     if Assigned(FOnClientDisconnected) and not (csDestroying in ComponentState) then
  530.       FOnClientDisconnected(Self, tmpTCPClient);
  531.       
  532.     tmpTCPClient.Free;
  533.    end;
  534. end;
  535. procedure TSimpleTCPServer.DoDataAvailable(Client: TSimpleTCPClient; DataSize: Integer; var Handled: Boolean);
  536. begin
  537.   Handled := Assigned(FOnClientDataAvailable);
  538.   if Handled then
  539.     FOnClientDataAvailable(Self, Client, DataSize);
  540. end;
  541. procedure TSimpleTCPServer.DoRead(Client: TSimpleTCPClient; Stream: TStream);
  542. begin
  543.   if Assigned(FOnClientRead) then
  544.     FOnClientRead(Self, Client, Stream);
  545. end;
  546. function TSimpleTCPServer.Send(Client: TSimpleTCPClient; Buffer: PChar; BufLength: Integer): Integer; // bytes sent
  547. begin
  548.   Result := SendBufferTo(Client.Socket, Buffer, BufLength);
  549. end;
  550. function  TSimpleTCPServer.SendStream(Client: TSimpleTCPClient; Stream: TStream): Integer; // returns N of bytes sent
  551. begin
  552.   Result := SendStreamTo(Client.FSocket, Stream);
  553. end;
  554. procedure TSimpleTCPServer.Broadcast(Buffer: PChar; BufLength: Integer);
  555. var
  556.   I: Integer;
  557. begin
  558.   I := FConnections.Count;
  559.   if I <> 0 then
  560.    for I := 0 to I - 1 do
  561.     with TSimpleTCPClient(FConnections[I]) do
  562.      SendBufferTo(FSocket, Buffer, BufLength);
  563. end;
  564. procedure TSimpleTCPServer.BroadcastStream(Stream: TStream);
  565. var
  566.   I: Integer;
  567. begin
  568.   I := FConnections.Count;
  569.   if I <> 0 then
  570.    for I := 0 to I - 1 do
  571.     with TSimpleTCPClient(FConnections[I]) do
  572.      SendStreamTo(FSocket, Stream);
  573. end;
  574. function TSimpleTCPServer.Receive(Client: TSimpleTCPClient; Buffer: PChar; BufLength: Integer; ReceiveCompletely: Boolean): Integer;
  575. begin
  576.   Result := ReceiveFrom(Client.FSocket, Buffer, BufLength, ReceiveCompletely);
  577. end;
  578. function TSimpleTCPServer.ReceiveStream(Client: TSimpleTCPClient; Stream: TStream; DataSize: Integer; ReceiveCompletely: Boolean): Integer;
  579. begin
  580.   Result := ReceiveStreamFrom(Client.FSocket, Stream, DataSize, ReceiveCompletely);
  581. end;
  582. procedure TSimpleTCPServer.SetPort(Value: Word);
  583. begin
  584.   if not (csDesigning in ComponentState) then
  585.    if FPort <> Value then
  586.     if FListen then
  587.      if FAllowChangeHostAndPortOnConnection then
  588.       begin
  589.        Listen := False;
  590.        FPort := Value;
  591.        Listen := True;
  592.       end
  593.      else
  594.       raise Exception.Create('Can not change Port while listening')
  595.     else FPort := Value
  596.    else
  597.   else FPort := Value;
  598. end;
  599. procedure TSimpleTCPServer.SetListen(Value: Boolean);
  600. var
  601.   I: Integer;
  602.   tmpTCPClient: TSimpleTCPClient;
  603. begin
  604.   if not (csDesigning in ComponentState) then
  605.    if FListen <> Value then
  606.     begin
  607.      if Value then
  608.       begin
  609.        FSocket := WinSock.Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  610.        if FSocket = SOCKET_ERROR then
  611.         begin
  612.          SocketError(INVALID_SOCKET, WSAGetLastError);
  613.          Exit;
  614.         end;
  615.        SockAddrIn.sin_family := AF_INET;
  616.        SockAddrIn.sin_addr.s_addr := INADDR_ANY;
  617.        SockAddrIn.sin_port := htons(FPort);
  618.        if Bind(FSocket, SockAddrIn, SizeOf(SockAddrIn)) <> 0 then
  619.         begin
  620.          SocketError(FSocket, WSAGetLastError);
  621.          Exit;
  622.         end;
  623.        if WinSock.Listen(FSocket, SOMAXCONN) <> 0 then
  624.         begin
  625.          SocketError(FSocket, WSAGetLastError);
  626.          Exit;
  627.         end;
  628.        if WSAAsyncSelect(FSocket, WindowHandle, UM_TCPASYNCSELECT,
  629.                          FD_READ or FD_ACCEPT or FD_CLOSE) <> 0 then
  630.         begin
  631.          SocketError(FSocket, WSAGetLastError);
  632.          Exit;
  633.         end;
  634.       end
  635.      else
  636.       begin
  637.       
  638.        // Closing all connections first
  639.        I := FConnections.Count;
  640.        if I <> 0 then
  641.         for I := I - 1 downto 0 do
  642.          begin
  643.           tmpTCPClient := FConnections[I];
  644.           tmpTCPClient.Connected := False;
  645.           FConnections.Delete(I);
  646.           closesocket( tmpTCPClient.Socket);
  647.          end;
  648.        // Cancel listening
  649.        WSAASyncSelect(FSocket, WindowHandle, UM_TCPASYNCSELECT, 0);
  650.        Shutdown(FSocket, 2);
  651.        if CloseSocket(FSocket) <> 0 then
  652.         begin
  653.          SocketError(FSocket, WSAGetLastError);
  654.          Exit;
  655.         end;
  656.        FSocket := INVALID_SOCKET;
  657.       end;
  658.       FListen := Value;
  659.     end
  660.    else
  661.   else
  662.    FListen := Value;
  663. end;
  664. function TSimpleTCPServer.GetLocalHostName: String;
  665. var
  666.   HostName: Array[0..MAX_PATH] of Char;
  667. begin
  668.   if GetHostName(HostName, MAX_PATH) = 0 then
  669.     Result := HostName
  670.   else
  671.     SocketError(FSocket, WSAGetLastError);
  672. end;
  673. function TSimpleTCPServer.GetLocalIP: String;
  674. var
  675.   SockAddrIn: TSockAddrIn;
  676.   HostEnt: PHostEnt;
  677.   HostName: Array[0..MAX_PATH] of Char;
  678. begin
  679.   if GetHostName(HostName, MAX_PATH) = 0 then
  680.    begin
  681.     HostEnt:= GetHostByName(HostName);
  682.     if HostEnt = nil then
  683.       Result := ''
  684.     else
  685.      begin
  686.       SockAddrIn.sin_addr.S_addr := LongInt(PLongInt(HostEnt^.h_addr_list^)^);
  687.       Result := inet_ntoa(SockAddrIn.sin_addr);
  688.      end;
  689.    end
  690.   else
  691.    SocketError(FSocket, WSAGetLastError);
  692. end;
  693. procedure TSimpleTCPServer.SetNoneStr(Value: String); begin end;
  694. {------------------------------------------------------------}
  695. { TSimpleTCPClient }
  696. destructor TSimpleTCPClient.Destroy;
  697. begin
  698.   Connected := False;
  699.   inherited Destroy;
  700. end;
  701. {procedure TSimpleTCPClient.WndProc(var Message: TMessage);
  702. begin
  703.   inherited WndProc(Message);
  704. end;}
  705. procedure TSimpleTCPClient.SocketError(Socket: TSocket; ErrorCode: Integer);
  706. begin
  707.   Connected := False; // broke connection
  708.   inherited;
  709. end;
  710. procedure TSimpleTCPClient.DoConnect;
  711. begin
  712.   FConnected := True; { definitely connected! }
  713.   if Assigned(FOnConnected) then
  714.     FOnConnected(Self);
  715. end;
  716. procedure TSimpleTCPClient.DoClose(Socket: TSocket);
  717. begin
  718.   Connected := False;
  719.   if not (csDestroying in ComponentState) then
  720.    begin
  721.     if Assigned(FOnDisconnected) then
  722.       FOnDisconnected(Self);
  723.     if FAutoTryReconnect then
  724.       Connected := True;
  725.    end;   
  726. end;
  727. procedure TSimpleTCPClient.DoDataAvailable(Client: TSimpleTCPClient; DataSize: Integer; var Handled: Boolean);
  728. begin
  729.   Handled := Assigned(FOnDataAvailable);
  730.   if Handled then
  731.     FOnDataAvailable(Self, DataSize);
  732. end;
  733. procedure TSimpleTCPClient.DoRead(Client: TSimpleTCPClient; Stream: TStream);
  734. begin
  735.   if Assigned(FOnRead) then
  736.     FOnRead(Self, Stream);
  737. end;
  738. function TSimpleTCPClient.Send(Buffer: PChar; BufLength: Integer): Integer; // bytes sent
  739. begin
  740.   Result := SendBufferTo(FSocket, Buffer, BufLength);
  741. end;
  742. function TSimpleTCPClient.SendStream(Stream: TStream): Integer; // returns N of bytes sent
  743. begin
  744.   Result := SendStreamTo(FSocket, Stream);
  745. end;
  746. function TSimpleTCPClient.Receive(Buffer: PChar; BufLength: Integer; ReceiveCompletely: Boolean): Integer;
  747. begin
  748.   Result := ReceiveFrom(FSocket, Buffer, BufLength, ReceiveCompletely);
  749. end;
  750. function TSimpleTCPClient.ReceiveStream(Stream: TStream; DataSize: Integer; ReceiveCompletely: Boolean): Integer;
  751. begin
  752.   Result := ReceiveStreamFrom(FSocket, Stream, DataSize, ReceiveCompletely);
  753. end;
  754. procedure TSimpleTCPClient.SetConnected(Value: Boolean);
  755. var
  756.   lin: TLinger;
  757.   linx: Array[0..3] of Char absolute lin;
  758.   ErrorCode: Integer;
  759. begin
  760.   if not (csDesigning in ComponentState) then
  761.    if FConditionallyConnected <> Value then
  762.     begin
  763.      FConditionallyConnected := Value;
  764.      if Value then
  765.       begin
  766.        SockAddrIn.sin_family := AF_INET;
  767.        SockAddrIn.sin_port := htons(FPort);
  768.        SockAddrIn.sin_addr.s_addr := inet_addr(PChar(Host));
  769.        if SockAddrIn.sin_addr.s_addr = -1 then
  770.         begin
  771.          HostEnt := GetHostByName(PChar(Host));
  772.          if HostEnt = nil then
  773.           begin
  774.            SocketError(INVALID_SOCKET, WSAEFAULT);
  775.            Exit;
  776.           end;
  777.          SockAddrIn.sin_addr.S_addr := LongInt(PLongInt(HostEnt^.h_addr_list^)^);
  778.         end;
  779.        FSocket := WinSock.Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  780.        if FSocket = SOCKET_ERROR then
  781.         begin
  782.          SocketError(INVALID_SOCKET, WSAGetLastError);
  783.          Exit;
  784.         end;
  785.        ErrorCode := WSAASyncSelect(FSocket, WindowHandle, UM_TCPASYNCSELECT,
  786.                                    FD_READ or FD_CONNECT or FD_CLOSE);
  787.        if ErrorCode <> 0 then
  788.         begin
  789.          SocketError(FSocket, WSAGetLastError);
  790.          Exit;
  791.         end;
  792.        ErrorCode := WinSock.Connect(FSocket, SockAddrIn, SizeOf(SockAddrIn));
  793.        if ErrorCode <> 0 then
  794.         begin
  795.          ErrorCode := WSAGetLastError;
  796.          if ErrorCode <> WSAEWOULDBLOCK then
  797.           begin
  798.            SocketError(FSocket, WSAGetLastError);
  799.            Exit;
  800.           end;
  801.         end;
  802.       end
  803.      else
  804.       begin
  805.        WSAASyncSelect(FSocket, WindowHandle, UM_TCPASYNCSELECT, 0);
  806.        Shutdown(FSocket, 2);
  807.        lin.l_onoff := 1;
  808.        lin.l_linger := 0;
  809.        SetSockOpt(FSocket, SOL_SOCKET, SO_LINGER, linx, SizeOf(Lin));
  810.        ErrorCode := CloseSocket(FSocket);
  811.        if ErrorCode <> 0 then
  812.         begin
  813.          SocketError(FSocket, WSAGetLastError);
  814.          Exit;
  815.         end;
  816.        FSocket := INVALID_SOCKET;
  817.        FConnected := False;
  818.        if Assigned(FOnDisconnected) and not (csDestroying in ComponentState) then
  819.          FOnDisconnected(Self);
  820.       end;
  821.     end
  822.    else
  823.   else
  824.    if Value then
  825.     raise Exception.Create('Can not connect at design-time');
  826. end;
  827. procedure TSimpleTCPClient.SetHost(Value: String);
  828. begin
  829.   if not (csDesigning in ComponentState) then
  830.    if FHost <> Value then
  831.     if FConnected then
  832.      if FAllowChangeHostAndPortOnConnection then
  833.       begin
  834.        Connected := False;
  835.        FHost := Value;
  836.        Connected := True;
  837.       end
  838.      else
  839.       raise Exception.Create('Can not change Host while connected')
  840.     else
  841.      FHost := Value
  842.    else
  843.   else FHost := Value;   
  844. end;
  845. procedure TSimpleTCPClient.SetPort(Value: Word);
  846. begin
  847.   if not (csDesigning in ComponentState) then
  848.    if FPort <> Value then
  849.     if FConnected then
  850.      if FAllowChangeHostAndPortOnConnection then
  851.       begin
  852.        Connected := False;
  853.        FPort := Value;
  854.        Connected := True;
  855.       end
  856.      else
  857.       raise Exception.Create('Can not change Port while connected')
  858.     else
  859.      FPort := Value
  860.    else
  861.   else
  862.    FPort := Value;
  863. end;
  864. function  TSimpleTCPClient.GetIP: LongInt;
  865. begin
  866.   Result := StrToIP(Host);
  867. end;
  868. procedure TSimpleTCPClient.SetIP(Value: LongInt);
  869. begin
  870.   Host := IPToStr(Value);
  871. end;
  872. procedure Register;
  873. begin
  874.   RegisterComponents('UtilMind', [TSimpleTCPServer, TSimpleTCPClient]);
  875. end;
  876. end.