HanDs
管理员

[Delphi文章] TCP转发服务器的例子 



这几种机器用事件模型应该够用了。
下面是一个TCP转发服务器的例子,他的作用是有一些客户端连到服务器后,任何一个客户端发给服务器的数据都被服务器原封不动的转发到所有客户端,类似于多人聊天的概念。
program EventSelectServer;

{$APPTYPE CONSOLE}

uses
 SysUtils, WinSock2;

const
 Port = 5150;
 MaxConnection = 63;
 BufSize = 1024;

var
 wsaData: TWSAData;
 Connection: array [0..MaxConnection] of TSocket;
 Events: array [0..MaxConnection] of WSAEvent;
 ConnectionNum: Integer;
 Index: Integer;
 i, j: Integer;
 NetworkEvent: TWSANetworkEvents;
 ServerAddr: TSockAddrIn;
 ClientAddr: TSockAddrIn;
 ClientAddrLen: Integer;
 Buf: string;
 Ret: Integer;

begin
 Ret:=WSAStartup($202, wsaData);
 if Ret<>0 then
 begin
   WriteLn('WSAStartup failed with error ', Ret);
   ReadLn;
   Exit
 end;

 ConnectionNum:=1;

 Connection[0]:=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if Connection[0]=INVALID_SOCKET then
 begin
   WriteLn('socket failed with error ', WSAGetLastError);
   ReadLn;
   Exit
 end;

 ServerAddr.sin_family:=AF_INET;
 ServerAddr.sin_port:=htons(Port);
 ServerAddr.sin_addr.S_addr:=htonl(INADDR_ANY);
 if bind(Connection[0], @ServerAddr, SizeOf(ServerAddr))=SOCKET_ERROR then
 begin
   WriteLn('bind failed with error ', WSAGetLastError);
   ReadLn;
   Exit
 end;

 Events[0]:=WSACreateEvent;
 if Events[0]=WSA_INVALID_EVENT then
 begin
   WriteLn('WSACreateEvent failed with error ', WSAGetLastError);
   ReadLn;
   Exit
 end;

 if WSAEventSelect(Connection[0], Events[0], FD_ACCEPT)=SOCKET_ERROR then
 begin
   WriteLn('WSAEventSelect failed with error ', WSAGetLastError);
   ReadLn;
   Exit
 end;

 if listen(Connection[0], 5)=SOCKET_ERROR then
 begin
   WriteLn('listen failed with error ', WSAGetLastError);
   ReadLn;
   Exit
 end;

 while True do
 begin
   Ret:=WSAWaitForMultipleEvents(ConnectionNum, @Events[0], False, WSA_INFINITE, False);
   Index:=Ret-WSA_WAIT_EVENT_0;

   for i:=Index to ConnectionNum-1 do
   begin
     Ret:=WSAWaitForMultipleEvents(1, @Events[i], True, 0, False);
     if (Ret=WSA_WAIT_FAILED) or (Ret=WSA_WAIT_TIMEOUT) then
       Continue;

     if WSAEnumNetworkEvents(Connection[i], Events[i], @NetworkEvent)=SOCKET_ERROR then
       Continue;

     if (NetworkEvent.lNetworkEvents and FD_ACCEPT)<>0 then
     begin
       if NetworkEvent.iErrorCode[FD_ACCEPT_BIT]<>0 then
       begin
         WriteLn('FD_ACCEPT failed with error ', NetworkEvent.iErrorCode[FD_ACCEPT_BIT]);
         Continue
       end;
       if ConnectionNum<=MaxConnection then
       begin
         ClientAddrLen:=SizeOf(ClientAddr);
         Connection[ConnectionNum]:=accept(Connection[i], ClientAddr, ClientAddrLen);
         if Connection[ConnectionNum]=INVALID_SOCKET then
         begin
           WriteLn('accept failed with error ', WSAGetLastError);
           Continue
         end;

         Events[ConnectionNum]:=WSACreateEvent;
         if Events[ConnectionNum]=WSA_INVALID_EVENT then
         begin
           WriteLn('WSACreateEvent failed with error ', WSAGetLastError);
           if closesocket(Connection[ConnectionNum])=SOCKET_ERROR then
             WriteLn('closesocket failed with error ', WSAGetLastError);
           Continue
         end;

         if WSAEventSelect(Connection[ConnectionNum], Events[ConnectionNum], FD_READ or FD_CLOSE)=SOCKET_ERROR then
         begin
           WriteLn('WSAEventSelect failed with error ', WSAGetLastError);
           if closesocket(Connection[ConnectionNum])=SOCKET_ERROR then
             WriteLn('closesocket failed with error ', WSAGetLastError);
           if not WSACloseEvent(Events[ConnectionNum]) then
             WriteLn('WSACloseEvent failed with error ', WSAGetLastError);
           Continue
         end;

         WriteLn('accetp ', inet_ntoa(ClientAddr.sin_addr), ':', ntohs(ClientAddr.sin_port));
         Inc(ConnectionNum)
       end
     end;
     if (NetworkEvent.lNetworkEvents and FD_READ)<>0 then
     begin
       if NetworkEvent.iErrorCode[FD_READ_BIT]<>0 then
       begin
         WriteLn('FD_READ failed with error ', NetworkEvent.iErrorCode[FD_READ_BIT]);
         Continue
       end;

       SetLength(Buf, BufSize);
       Ret:=recv(Connection[i], Buf[1], BufSize, 0);
       if Ret=SOCKET_ERROR then
       begin
         WriteLn('recv failed with error ', WSAGetLastError);
         Continue
       end;
       SetLength(Buf, Ret);

       ClientAddrLen:=SizeOf(ClientAddr);
       if getpeername(Connection[i], ClientAddr, ClientAddrLen)=SOCKET_ERROR then
       begin
         WriteLn('getpeername failed with error ', WSAGetLastError);
         Continue
       end;
       Buf:='来自'+inet_ntoa(ClientAddr.sin_addr)+':'+IntToStr(ntohs(ClientAddr.sin_port))+' '+Buf;
       Buf:=TimeToStr(Time)+' '+Buf;

       for j:=1 to ConnectionNum do
         if send(Connection[j], Buf[1], Length(Buf), 0)=SOCKET_ERROR then
         begin
           WriteLn('send failed with error ', WSAGetLastError);
           Continue
         end;

       WriteLn(Buf)
     end;
     if (NetworkEvent.lNetworkEvents and FD_CLOSE)<>0 then
     begin
       if NetworkEvent.iErrorCode[FD_CLOSE_BIT]<>0 then
       begin
         WriteLn('FD_CLOSE failed with error ', NetworkEvent.iErrorCode[FD_CLOSE_BIT]);
         Continue
       end;

       ClientAddrLen:=SizeOf(ClientAddr);
       if getpeername(Connection[i], ClientAddr, ClientAddrLen)=SOCKET_ERROR then
       begin
         WriteLn('getpeername failed with error ', WSAGetLastError);
         Continue
       end;
       Buf:='closesocket '+inet_ntoa(ClientAddr.sin_addr)+':'+IntToStr(ntohs(ClientAddr.sin_port));
       WriteLn(Buf);

       if closesocket(Connection[i])=SOCKET_ERROR then
         WriteLn('closesocket failed with error ', WSAGetLastError);

       if not WSACloseEvent(Events[i]) then
         WriteLn('WSACloseEvent failed with error ', WSAGetLastError);

       if ConnectionNum>1 then
       begin
         Connection[i]:=Connection[ConnectionNum-1];
         Events[i]:=Events[ConnectionNum-1];
         Dec(ConnectionNum)
       end
     end
   end
 end;

 for i:=0 to ConnectionNum do
   if closesocket(Connection[i])=SOCKET_ERROR then
   begin
     WriteLn('closesocket failed with error ', WSAGetLastError);
     ReadLn;
     Exit
   end;

 if WSACleanup=SOCKET_ERROR then
 begin
   WriteLn('WSCleanup failed with error ', WSAGetLastError);
   ReadLn;
   Exit
 end
end.  


学习中请遵守法律法规,本网站内容均来自于互联网,本网站不负担法律责任
TCP 转发服务器的例子
#1楼
发帖时间:2016-7-9   |   查看数:0   |   回复数:0
游客组
快速回复