while (not Terminated) do begin FD_ZERO( fd_read ); FD_SET( MainSock, fd_read ); timeout.tv_sec :=0; timeout.tv_usec :=500; ifselect( 0, @fd_read, nil, nil, @timeout ) >0then//至少有1个等待Accept的connection begin if FD_ISSET( MainSock, fd_read ) then begin for i:=0to fd_read.fd_count-1do//注意,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 事件通知模型和WSAEventSelect模型在实现上非常相似,主要区别在"Overlapped",Overlapped模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个Winsock I/O请求。这些提交的请求完成后,应用程序会收到通知。什么意思呢?就是说,如果你想从socket上接收数据,只需要告诉系统,由系统为你接收数据,而你需要做的只是为系统提供一个缓冲区~~~~~ Listen线程和WSAEventSelect模型一模一样,Recv/Send线程则完全不同: 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;
//创建CPU数*2 + 2个线程 for i:=1 to si.dwNumberOfProcessors*2+2 do begin AThread := TRecvSendThread.Create( false ); AThread.CompletPort := FCompletPort;//告诉这个线程,你要去这个IOCP去访问数据 end;
procedure TRecvSendThread.Execute; var ...... begin while (not self.Terminated) do begin //查询IOCP状态(数据读写操作是否完成) GetQueuedCompletionStatus( CompletPort, BytesTransd, CompletKey, POVERLAPPED(pPerIoDat), TIME_OUT );