API及可伸缩性-AcceptEx

对可伸缩的TCP/IP服务器而言,最有用的扩展API也就算AcceptEx了。利用这个函数,服务器能够投递一个异步调用,该调用将接受下一个传入的客户机链接。服务器

  
  
  
  
  1. BOOL AcceptEx( 
  2.   __in          SOCKET sListenSocket, 
  3.   __in          SOCKET sAcceptSocket, 
  4.   __in          PVOID lpOutputBuffer, 
  5.   __in          DWORD dwReceiveDataLength, 
  6.   __in          DWORD dwLocalAddressLength, 
  7.   __in          DWORD dwRemoteAddressLength, 
  8.   __out         LPDWORD lpdwBytesReceived, 
  9.   __in          LPOVERLAPPED lpOverlapped 
  10. ); 

sListenSocket是监听套接字,sAcceptSocket是一个有效的,为绑定的套接字句柄,将被分配到下一个客户机链接上。所以需在投递AcceptEx调用前建立客户机的套接字句柄。由于套接字建立开销比较大,这个步骤很必要,若是一个服务器但愿尽量快的处理客户机链接,它就须要一个已建立的套接字库,以便把新的链接分配进去。app

sAcceptSocket以后紧随的4个参数相互关联。lpOutputBuffer参数含有用于客户机链接的本地或远程地址,还有一个可选的缓冲区,该缓冲区用来接收来自客户机的第一个数据块。dwReceiveDataLength指明所提供的缓冲区须要多少字节数,该缓冲区用来接收客户机发送的数据。应用程序若是不接收数据,可将其置为0。dwLocalAddressLength指定套接字地址结构大小,它至关于客户机套接字的地址族加上16个字节。客户机套接字链接的本地地址放在lpOutputBuffer参数中紧随接收数据以后的地方。dwRemoteAddresslength与lpOutputBuffer参数同样。客户机链接的远程地址将被写入前一个参数中,紧随接收数据及本地地址以后。应注意, dwReceiveDataLength参数能够是0,可是dwLocalAddressLength和 dwRemoteAddresslength参数均不能为0。异步

lpdwBytesReceived指明操做马上成功时,新建的客户机链接上所收到的字节数。lpOverlapped用于这个重叠操做的WSAOVERLAPPED结构,该参数是必须的---若是想执行一个阻塞的接收调用,使用accept或WSAAccept就好了。socket

示例代码,建立一个IPv4套接字并投递一个单一的AcceptEx:ide

  
  
  
  
  1. SOCKET s,sClient; 
  2. HANDLE hComPort; 
  3. LPFN_ACCEPTEX lpfnAcceptEx = NULL; 
  4. GUID GuidAcceptEx = WSAID_ACCEPTEX; 
  5.  
  6. WSAOVERLAPPEDPLUS ol; 
  7. SOCKADDR_IN salocal; 
  8. DWORD dwBytes; 
  9. char buf[1024]; 
  10. int buflen = 1024; 
  11.  
  12. //建立完成端口 
  13. hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,(ULONG_PTR)0,0); 
  14.  
  15. //建立监听套接字 
  16. s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
  17.  
  18. //将套接字和完成端口关联起来 
  19. CreateIoCompletionPort((HANDLE)s,hComPort,(ULONG_PTR)0,0); 
  20.   
  21. salocal.sin_family = AF_INET; 
  22. salocal.sin_port = htons(5050); 
  23. salocal.sin_addr.s_addr = htonl(INADDR_ANY); 
  24. bind(s, (SOCKADDR*)&salocal, sizeof(SOCKADDR_IN)); 
  25.  
  26. listen(s, 200); 
  27.  
  28. //加载AcceptEx函数 
  29. WSAIoctl(s, 
  30.          SIO_GET_EXTENSION_FUNCTION_POINTER, 
  31.          &GuidAcceptEx, 
  32.          sizeof(GuidAcceptEx), 
  33.          &lpfnAcceptEx, 
  34.          sizeof(lpfnAcceptEx), 
  35.          &dwBytes, 
  36.          NULL, 
  37.          NULL); 
  38. //为已接收的链接建立客户机套接字 
  39. sClient = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
  40.  
  41. //初始化扩展的重叠结构 
  42. memset(&ol, 0 ,sizeof(ol)); 
  43. ol.operation = OP_ACCEPTEX; 
  44. ol.client = sClient; 
  45.  
  46. lpfnAcceptEx(s, 
  47.              sClient, 
  48.              buf, 
  49.              buflen-((sizeof(SOCKADDR_IN)+16)*2), 
  50.              sizeof(SOCKADDR_IN)+16, 
  51.              sizeof(SOCKADDR_IN)+16, 
  52.              &dwBytes, 
  53.              &ol.overlapped);  
  54.  
  55. //在完成函数内调用GetQueuedCompletionStatus函数 
  56. //在AcceptEx操做完成后,将已接收的客户机套接字和完成端口关联起来 
  57. ...  

本段代码演示如何加载AcceptEx函数。函数

同时注意到,由于AcceptEx的高性能特性,监听套接字的套接字属性不会自动被客户机套接字继承,要继承属性,服务器必须用SO_UPDATE_ACCEPT_CONTEXT及客户机套接字句柄调用setsockopt。性能

另一点要清楚,若是为AcceptEx指定了一个接收缓冲区,则重叠操做只有在链接上收到至少一个字节的数据以后才能完成。ui

相关文章
相关标签/搜索