icrosoft扩展函数,它是从Mswsock.lib库中导出的,为了能够直接调用它而不链接到Mswsock.lib库(因为直接链接到这个库的话会将程序绑定在MicrosoftWinsock提供者上),需要使用WSAIoctl()将AcceptEx()加载到内存。WSAIoctl()是ioctlsocket()的扩展,它可以使用重叠I/O,函数的第3个到第6个参数是输入和输出缓冲区,在这里传递AcceptEx()函数的指针。具体如下:
// 加载扩展函数AcceptEx
DWORD dwBytes;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
LPFN_ACCEPTEX lpfnAcceptEx = NULL;
int iResult = WSAIoctl(ListenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&lpfnAcceptEx,
sizeof(lpfnAcceptEx),
&dwBytes,
NULL,
NULL);
if (iResult == SOCKET_ERROR) {
printf("WSAIoctl failed with error: %u\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
......
//调用AcceptEx
BOOL bRetVal = lpfnAcceptEx(ListenSocket,
AcceptSocket,
lpOutputBuf,
outBufLen - ((sizeof(sockaddr_in) + 16) * 2),
sizeof(sockaddr_in) + 16,
sizeof(sockaddr_in) + 16,
&dwBytes,
&olOverlap);
if (bRetVal == FALSE) {
printf(L"AcceptEx failed with error: %u\n", WSAGetLastError());
closesocket(AcceptSocket);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
2、GetAcceptExSockaddrs()
GetAcceptExSockaddrs()是专为AcceptEx()准备的,它粘贴从AcceptEx()获得的数据,将本地和远程地址传递到sockaddr结构。
void GetAcceptExSockaddrs(
_In_ PVOID lpOutputBuffer, //指向传递给AcceptEx()接收客户第一块数据的缓冲区, 与AcceptEx()的lpOutputBuffer参数相同
_In_ DWORD dwReceiveDataLength, //上一个参数的大小,应与AcceptEx()的dwReceiveDataLength参数一致
_In_ DWORD dwLocalAddressLength, //为本地地址预留的空间大小,应与AcceptEx()的
dwLocalAddressLength参数一致
_In_ DWORD dwRemoteAddressLength,//为远程地址预留的空间大小,应与AcceptEx()的
dwRemoteAddressLength参数一致
_Out_ LPSOCKADDR *LocalSockaddr, //用来获得连接的本地地址
_Out_ LPINT LocalSockaddrLength, //用来获得连接的本地地址长度
_Out_ LPSOCKADDR *RemoteSockaddr,//用来获得连接的远程地址
_Out_ LPINT RemoteSockaddrLength ////用来获得连接的远程地址长度
);
当使用AcceptEx时,必须使用GetAcceptExSockaddrs函数将输出缓冲区的内容解析到三个不同部分的缓冲区 (data,
local socket address, and remote socket address)。 在windows XP 及随后版本中,当 AcceptEx函数完成操
作并且SO_UPDATE_ACCEPT_CONTEXT选项在被接受的socket中被设置时, 与被接受socket相关的本地地址(local
address )可以使用getsockname函数获得,类似的,与被接受socket相关的远程端地址(the remote address)可
以使用getpeername函数获得。
使用WSAIoctl()加载GetAcceptExSockaddrs():
DWORD dwBytes;
GUID GuidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockaddrs = NULL;
int Result = WSAIoctl(ListenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidGetAcceptExSockaddrs,
sizeof(GuidGetAcceptExSockaddrs),
&lpfnGetAcceptExSockaddrs,
sizeof(lpfnGetAcceptExSockaddrs),
&dwBytes,
NULL,
NULL);
3、TransmitFile
TransmitFile()函数使用操作系统的缓存管理器来发送文件数据,它避免了循环调用ReadFile() 和WSASend ()产生的多重用户模式到内核模式的切换,提高了文件传输的性能,linux的sendfile()、sendfile64()与其类似:
BOOL PASCAL TransmitFile(
SOCKET hSocket, //连接套接字,不能是SOCK_DGRAM或SOCK_RAM类型
HANDLE