while (not Terminated) do begin FD_ZERO( fd_read ); FD_SET( MainSock, fd_read ); timeout.tv_sec := 0; timeout.tv_usec := 500; if select( 0, @fd_read, nil, nil, @timeout ) > 0 then {//至少有1个等待Accept的connection} begin if FD_ISSET( MainSock, fd_read ) then begin for i:=0 to fd_read.fd_count-1 do {//注意,fd_count <= 64,也就是说select只能同时管理最多64个连接} begin len := sizeof(addr); ASock := accept( MainSock, addr, len ); if ASock <> INVALID_SOCKET then .{//为ASock创建一个新的线程,在新的线程中再不停地select} end; end; end; end; {//while (not self.Terminated)}
if ( ne.lNetworkEvents and FD_READ ) > 0 then begin if ne.iErrorCode[FD_READ_BIT] <> 0 then continue; FillChar( RecvBuf[0], PACK_SIZE_RECEIVE, 0 ); ret := recv( SockArray[Index-WSA_WAIT_EVENT_0], RecvBuf[0], PACK_SIZE_RECEIVE, 0 );
end; end; end; 四:Overlapped I/O 事件通知模型
Code Code procedure TOverlapThread.Execute; var dwTemp : DWORD; ret : Integer; Index : DWORD; begin
while ( not Terminated ) do begin Index := WSAWaitForMultipleEvents( FLinks.Count, @FLinks.Events[0], FALSE, RECV_TIME_OUT, FALSE ); Dec( Index, WSA_WAIT_EVENT_0 ); if Index > WSA_MAXIMUM_WAIT_EVENTS-1 then {//超时或者其他错误} continue;
Code Code while ( not Terminated ) do{//这就是一个Recv/Send线程要做的事情什么都不用做啊!!!} begin if SleepEx( RECV_TIME_OUT, True ) = WAIT_IO_COMPLETION then {//} begin ; end else begin continue; end; end;
{创建CPU数*2 + 2个线程} for i:=1 to si.dwNumberOfProcessors*2+2 do begin AThread := TRecvSendThread.Create( false ); AThread.CompletPort := FCompletPort;{//告诉这个线程,你要去这个IOCP去访问数据} end; OK,就这么简单,我们要做的就是建立一个IOCP,把远程连接的socket句柄绑定到刚才创建的IOCP上,最后创建n个线程,并告诉这n个线程到这个IOCP上去访问数据就可以了。
再看一下TRecvSendThread线程都干些什么:
Code Code procedure TRecvSendThread.Execute; var
begin while (not self.Terminated) do begin {查询IOCP状态(数据读写操作是否完成)} GetQueuedCompletionStatus( CompletPort, BytesTransd, CompletKey, POVERLAPPED(pPerIoDat), TIME_OUT );