我目前正在尝试一些用于套接字编程的新库(IOCP)。而且我偶然发现了AcceptEx功能来启用异步连接。
如文档所述:
但是,当客户端连接时,我不会获得任何完成。但是,当客户端发送数据时,我确实完成了操作。
这是我的代码:
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绑定(bind)到完成端口
最佳答案
首先,当完成完成时,您在对WSAOVERLAPPED
的调用上方要在堆栈上声明的AcceptEx()
和数据缓冲区将不存在(除非您在同一函数中调用GetQueuedCompletionStatus()
,这有点小怪异)。您需要动态分配它们或将它们合并。
其次,您声明在调用AcceptEx()
之后将套接字与完成端口相关联。错了在调用AcceptEx()
之前,需要做这些事情。
WSA_FLAG_OVERLAPPED
的套接字。 AcceptEx()
的调用来动态加载WSAIoctl
(并非绝对必要,并且您显示的代码应该可以工作,但是通过这种方式,您可以确保从同一基础winsock提供程序获取监听套接字,并且它支持AcceptEx()。 GetAcceptExSockaddrs()
的方式与加载AcceptEx()
的方式相同-接受完成后将需要它。 现在,您可以使用监听套接字和新创建的“accept”套接字发布许多
AcceptEx()
调用,如下所示:WSA_FLAG_OVERLAPPED
的套接字。 如上所述,您需要确保每个调用的缓冲区和OVERLAPPED都是唯一的,并且持续到完成为止。
完成时,您必须执行以下操作。
setsockopt()
调用SO_UPDATE_ACCEPT_CONTEXT
... GetAcceptExSockaddrs()
阻止您的地址。 请注意,根据设计,
AcceptEx()
可用于接受新连接并通过一次操作从该连接返回初始数据(在您知道在开始做事之前总是需要一些数据的情况下,这会导致性能略有提高,但是如果要防御拒绝服务攻击,这非常复杂,只需通过连接而不发送数据就可以发起拒绝服务攻击-我写了有关here的文章。如果您不希望
AcceptEx()
等待数据到达,则只需提供一个数据缓冲区,该缓冲区必须足够大以返回地址,并将0作为“缓冲区大小”传递。这将导致AcceptEx()
像重叠的accept()
一样操作,并在建立连接后立即返回。请注意,马丁·詹姆斯(Martin James)对您问题的最初评论实际上是您正在寻找的答案。不要传递
outBufLen - ((sizeof (sockaddr_in) + 16) * 2)
,传递0
。关于c++ - IOCP AcceptEx在连接时未创建完成,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19956186/