IOCP AcceptEx在连接时未创建完成

时间:2013-11-13 14:23:03

标签: c++ windows winsock iocp

我目前正在尝试一些用于套接字编程的新库(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绑定到完成端口

1 个答案:

答案 0 :(得分:10)

首先,当您完成调用时,您在WSAOVERLAPPED调用之上在堆栈上声明的AcceptEx()和数据缓冲区将不存在(除非您在GetQueuedCompletionStatus()调用AcceptEx()相同的功能,这将是一个奇怪的事情)。您需要动态分配它们或将它们集中在一起。

其次,您声明在调用AcceptEx()后将套接字与完成端口关联。那是错的。在致电WSA_FLAG_OVERLAPPED之前,您需要执行这些操作。

  1. 创建一个AcceptEx()设置的套接字。
  2. 将其绑定到您想要收听的地址。
  3. 用你想要的积压电话听取它。
  4. 使用侦听套接字和对WSAIoctl的调用动态加载GetAcceptExSockaddrs()(不是绝对必要的,您显示的代码应该可以工作,但这样您可以确保从同一个底层获取侦听套接字winsock提供程序,它支持AcceptEx()。
  5. 加载AcceptEx()的方式与加载AcceptEx()的方式相同 - 一旦接受完成,您将需要它。
  6. 将侦听套接字与IOCP关联。
  7. 现在,您可以使用侦听套接字和您创建的新“接受”套接字发布大量WSA_FLAG_OVERLAPPED个调用,如下所示:

    1. 创建一个setsockopt()设置的套接字。
    2. 将套接字与IOCP关联。
    3. 如上所述,您需要确保每次调用缓冲区和OVERLAPPED都是唯一的,并且一直持续到完成为止。

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

      1. 使用侦听套接字作为数据,在接受的套接字上使用SO_UPDATE_ACCEPT_CONTEXT调用GetAcceptExSockaddrs() ...
      2. 使用AcceptEx()解锁您的地址。
      3. 处理任何数据(如果您在缓冲区中为数据分配了足够的空间)。
      4. 请注意,设计AcceptEx()可用于接受新连接并在一次操作中从该连接返回初始数据(在您知道之前总是需要某些数据的情况下,这会带来稍微好一点的性能你可以开始做事但管理起来非常复杂,如果你想要通过连接和不发送数据来启动拒绝服务攻击 - 我写了关于这个here)。

        如果您不希望AcceptEx()等待数据到达,那么只需提供一个足够大的数据缓冲区,以便返回地址,并将0作为“缓冲区大小”传递。这将导致accept()像重叠的outBufLen - ((sizeof (sockaddr_in) + 16) * 2)一样运行,并在建立连接后立即返回。

        请注意,Martin James对您问题的初步评论实际上就是您正在寻找的答案。不要通过0,通过{{1}}。

相关问题