| 
 | 
 
 
 楼主 |
发表于 2005-7-22 07:16:58
|
显示全部楼层
 
 
 
三:WSAEventSelect模型
    后来,微软的信箱非常畅销,购买微软信箱的人以百万计数......以至于盖茨每天24小时给客户打电话,累得腰酸背痛,喝蚁力神都不好使。微软改进了他们的信箱:在客户的家中添加一个附加装置,这个装置会监视客户的信箱,每当新的信件来临,此装置会发出“新信件到达”声,提醒老陈去收信。盖茨终于可以睡觉了。
    同样要使用线程:
  
procedure TListenThread.Execute; var  hEvent : WSAEvent;  ret : Integer;  ne : TWSANetworkEvents;  sock : TSocket;  adr : TSockAddrIn;  sMsg : String;  Index,  EventTotal : DWORD;  EventArray : Array [0..WSA_MAXIMUM_WAIT_EVENTS-1] of WSAEVENT; begin  ...socket...bind...  hEvent := WSACreateEvent();  WSAEventSelect( ListenSock, hEvent, FD_ACCEPT or FD_CLOSE );  ...listen...
   while ( not Terminated ) do  begin   Index := WSAWaitForMultipleEvents( EventTotal, @EventArray[0], FALSE, WSA_INFINITE, FALSE );   FillChar( ne, sizeof(ne), 0 );   WSAEnumNetworkEvents( SockArray[Index-WSA_WAIT_EVENT_0], EventArray[Index-WSA_WAIT_EVENT_0], @ne );
    if ( ne.lNetworkEvents and FD_ACCEPT ) > 0 then   begin    if ne.iErrorCode[FD_ACCEPT_BIT] <> 0 then     continue;
     ret := sizeof(adr);    sock := accept( SockArray[Index-WSA_WAIT_EVENT_0], adr, ret );    if EventTotal > WSA_MAXIMUM_WAIT_EVENTS-1 then//这里WSA_MAXIMUM_WAIT_EVENTS同样是64    begin     closesocket( sock );     continue;    end;
     hEvent := WSACreateEvent();    WSAEventSelect( sock, hEvent, FD_READ or FD_WRITE or FD_CLOSE );    SockArray[EventTotal] := sock;    EventArray[EventTotal] := hEvent;    Inc( EventTotal );   end;
    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 事件通知模型
    后来,微软通过调查发现,老陈不喜欢上下楼收发信件,因为上下楼其实很浪费时间。于是微软再次改进他们的信箱。新式的信箱采用了更为先进的技术,只要用户告诉微软自己的家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的信件已经放到你的家中了!老陈很高兴,因为他不必再亲自收发信件了!
    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;
    WSAResetEvent( FLinks.Events[Index] );   WSAGetOverlappedResult( FLinks.Sockets[Index], FLinks.pOverlaps[Index], @dwTemp, FALSE,FLinks.pdwFlags[Index]^ );
    if dwTemp = 0 then //连接已经关闭   begin    ......    continue;   end else  begin   fmMain.ListBox1.Items.Add( FLinks.pBufs[Index]^.buf );  end;
   //初始化缓冲区  FLinks.pdwFlags[Index]^ := 0;  FillChar( FLinks.pOverlaps[Index]^, sizeof(WSAOVERLAPPED), 0 );  FLinks.pOverlaps[Index]^.hEvent := FLinks.Events[Index];  FillChar( FLinks.pBufs[Index]^.buf^, BUFFER_SIZE, 0 );
   //递一个接收数据请求  WSARecv( FLinks.Sockets[Index], FLinks.pBufs[Index], 1, FLinks.pdwRecvd[Index]^, FLinks.pdwFlags[Index]^, FLinks.pOverlaps[Index], nil ); end; end; |    |   
 
 
 
 |