對可伸縮的TCP/IP服務器而言,最有用的擴展API也就算AcceptEx了。利用這個函數,服務器能夠投遞一個異步調用,該調用將接受下一個傳入的客戶機鏈接。服務器
- BOOL AcceptEx(
- __in SOCKET sListenSocket,
- __in SOCKET sAcceptSocket,
- __in PVOID lpOutputBuffer,
- __in DWORD dwReceiveDataLength,
- __in DWORD dwLocalAddressLength,
- __in DWORD dwRemoteAddressLength,
- __out LPDWORD lpdwBytesReceived,
- __in LPOVERLAPPED lpOverlapped
- );
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
- SOCKET s,sClient;
- HANDLE hComPort;
- LPFN_ACCEPTEX lpfnAcceptEx = NULL;
- GUID GuidAcceptEx = WSAID_ACCEPTEX;
- WSAOVERLAPPEDPLUS ol;
- SOCKADDR_IN salocal;
- DWORD dwBytes;
- char buf[1024];
- int buflen = 1024;
- //建立完成端口
- hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,(ULONG_PTR)0,0);
- //建立監聽套接字
- s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- //將套接字和完成端口關聯起來
- CreateIoCompletionPort((HANDLE)s,hComPort,(ULONG_PTR)0,0);
- salocal.sin_family = AF_INET;
- salocal.sin_port = htons(5050);
- salocal.sin_addr.s_addr = htonl(INADDR_ANY);
- bind(s, (SOCKADDR*)&salocal, sizeof(SOCKADDR_IN));
- listen(s, 200);
- //加載AcceptEx函數
- WSAIoctl(s,
- SIO_GET_EXTENSION_FUNCTION_POINTER,
- &GuidAcceptEx,
- sizeof(GuidAcceptEx),
- &lpfnAcceptEx,
- sizeof(lpfnAcceptEx),
- &dwBytes,
- NULL,
- NULL);
- //爲已接收的鏈接建立客戶機套接字
- sClient = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- //初始化擴展的重疊結構
- memset(&ol, 0 ,sizeof(ol));
- ol.operation = OP_ACCEPTEX;
- ol.client = sClient;
- lpfnAcceptEx(s,
- sClient,
- buf,
- buflen-((sizeof(SOCKADDR_IN)+16)*2),
- sizeof(SOCKADDR_IN)+16,
- sizeof(SOCKADDR_IN)+16,
- &dwBytes,
- &ol.overlapped);
- //在完成函數內調用GetQueuedCompletionStatus函數
- //在AcceptEx操做完成後,將已接收的客戶機套接字和完成端口關聯起來
- ...
本段代碼演示如何加載AcceptEx函數。函數
同時注意到,由於AcceptEx的高性能特性,監聽套接字的套接字屬性不會自動被客戶機套接字繼承,要繼承屬性,服務器必須用SO_UPDATE_ACCEPT_CONTEXT及客戶機套接字句柄調用setsockopt。性能
另一點要清楚,若是爲AcceptEx指定了一個接收緩衝區,則重疊操做只有在鏈接上收到至少一個字節的數據以後才能完成。ui