这几种机器用事件模型应该够用了。
下面是一个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, True, 0, False);
if (Ret=WSA_WAIT_FAILED) or (Ret=WSA_WAIT_TIMEOUT) then
Continue;
if WSAEnumNetworkEvents(Connection, Events, @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, 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, 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, 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, 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)=SOCKET_ERROR then
WriteLn('closesocket failed with error ', WSAGetLastError);
if not WSACloseEvent(Events) then
WriteLn('WSACloseEvent failed with error ', WSAGetLastError);
if ConnectionNum>1 then
begin
Connection:=Connection[ConnectionNum-1];
Events:=Events[ConnectionNum-1];
Dec(ConnectionNum)
end
end
end
end;
for i:=0 to ConnectionNum do
if closesocket(Connection)=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.