我目前正在尝试一些用于套接字编程的新库(IOCP)。我偶然发现了AcceptEx功能来启用异步连接。
正如文件所说:
与accept函数不同,AcceptEx函数使用重叠的I / O.如果您的应用程序使用AcceptEx,它可以使用相对较少的线程为大量客户端提供服务。与所有重叠的Windows功能一样,Windows事件或完成端口都可以用作完成通知机制。
但是当客户端连接时我没有收到任何完成。但是,当客户端发送数据时,我会完成...
这是我的代码:
DWORD dwBytes;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
int iResult = WSAIoctl(m_hSocket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx, sizeof (GuidAcceptEx),
&m_lpfnAcceptEx, sizeof (m_lpfnAcceptEx),
&dwBytes, NULL, NULL);
if (iResult == SOCKET_ERROR)
{
CloseSocket();
}
然后:
WSAOVERLAPPED olOverlap;
memset(&olOverlap, 0, sizeof (olOverlap));
char lpOutputBuf[1024];
int outBufLen = 1024;
DWORD dwBytes;
BOOL bRet = m_lpfnAcceptEx( m_hSocket, hSocket, lpOutputBuf,
outBufLen - ((sizeof (sockaddr_in) + 16) * 2),
sizeof (sockaddr_in) + 16, sizeof (sockaddr_in) + 16,
&dwBytes, &olOverlap);
if ( bRet == FALSE )
{
DWORD dwRet = WSAGetLastError();
if( dwRet != WSA_IO_PENDING )
{
return dwRet;
}
}
有关接受完成的建议吗?
编辑: 我在m_lpfnAcceptEx()
之后将hSocket绑定到完成端口答案 0 :(得分:10)
首先,当您完成调用时,您在WSAOVERLAPPED
调用之上在堆栈上声明的AcceptEx()
和数据缓冲区将不存在(除非您在GetQueuedCompletionStatus()
调用AcceptEx()
相同的功能,这将是一个奇怪的事情)。您需要动态分配它们或将它们集中在一起。
其次,您声明在调用AcceptEx()
后将套接字与完成端口关联。那是错的。在致电WSA_FLAG_OVERLAPPED
之前,您需要执行这些操作。
AcceptEx()
设置的套接字。WSAIoctl
的调用动态加载GetAcceptExSockaddrs()
(不是绝对必要的,您显示的代码应该可以工作,但这样您可以确保从同一个底层获取侦听套接字winsock提供程序,它支持AcceptEx()。AcceptEx()
的方式与加载AcceptEx()
的方式相同 - 一旦接受完成,您将需要它。现在,您可以使用侦听套接字和您创建的新“接受”套接字发布大量WSA_FLAG_OVERLAPPED
个调用,如下所示:
setsockopt()
设置的套接字。如上所述,您需要确保每次调用缓冲区和OVERLAPPED都是唯一的,并且一直持续到完成为止。
完成后,您必须执行以下操作....
SO_UPDATE_ACCEPT_CONTEXT
调用GetAcceptExSockaddrs()
... AcceptEx()
解锁您的地址。请注意,设计AcceptEx()
可用于接受新连接并在一次操作中从该连接返回初始数据(在您知道之前总是需要某些数据的情况下,这会带来稍微好一点的性能你可以开始做事但管理起来非常复杂,如果你想要通过连接和不发送数据来启动拒绝服务攻击 - 我写了关于这个here)。
如果您不希望AcceptEx()
等待数据到达,那么只需提供一个足够大的数据缓冲区,以便返回地址,并将0作为“缓冲区大小”传递。这将导致accept()
像重叠的outBufLen - ((sizeof (sockaddr_in) + 16) * 2)
一样运行,并在建立连接后立即返回。
请注意,Martin James对您问题的初步评论实际上就是您正在寻找的答案。不要通过0
,通过{{1}}。