gpt4 book ai didi

c++ - 连接时 IOCP AcceptEx 未创建完成

转载 作者:可可西里 更新时间:2023-11-01 09:41:13 24 4
gpt4 key购买 nike

我目前正在尝试一些用于套接字编程的新库 (IOCP)。我偶然发现了 AcceptEx启用异步连接的功能。

正如文档所说:

The AcceptEx function uses overlapped I/O, unlike the accept function. If your application uses AcceptEx, it can service a large number of clients with a relatively small number of threads. As with all overlapped Windows functions, either Windows events or completion ports can be used as a completion notification mechanism.

但是当客户端连接时我没有收到任何完成。然而,当客户端发送数据时,我确实完成了......

这是我的代码:

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)到完成端口

最佳答案

首先,您在 AcceptEx() 调用上方的堆栈上声明的 WSAOVERLAPPED 和数据缓冲区在完成时将不存在(除非您在同一个函数中调用 GetQueuedCompletionStatus(),这有点奇怪)。您需要动态分配它们或合并它们。

其次,您声明在调用 AcceptEx() 后将套接字关联到完成端口。那是错误的。在调用 AcceptEx() 之前,您需要做这些事情。

  1. 创建一个设置了 WSA_FLAG_OVERLAPPED 的套接字。
  2. 将其绑定(bind)到您要收听的地址。
  3. 用您想要的待办事项调用收听它。
  4. 使用监听套接字动态加载 AcceptEx() 并调用 WSAIoctl(并非绝对必要,您显示的代码应该可以工作,但这样您可以确定您从相同的底层 winsock 提供程序获取您的监听套接字,并且它支持 AcceptEx()。
  5. 以与加载 AcceptEx() 相同的方式加载 GetAcceptExSockaddrs() - 一旦接受完成,您将需要它。
  6. 将监听套接字关联到您的 IOCP。

现在您可以使用监听套接字和您创建的新“接受”套接字发布多个 AcceptEx() 调用:

  1. 创建一个设置了 WSA_FLAG_OVERLAPPED 的套接字。
  2. 将套接字关联到您的 IOCP。

如上所述,您需要确保缓冲区和 OVERLAPPED 每次调用都是唯一的,并且持续到完成为止。

完成后,您必须执行以下操作....

  1. 使用监听套接字作为数据在接受的套接字上使用 SO_UPDATE_ACCEPT_CONTEXT 调用 setsockopt()...
  2. 使用 GetAcceptExSockaddrs() 解锁您的地址。
  3. 处理任何数据(如果您在缓冲区中为数据分配了足够的空间)。

请注意,根据设计,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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com