C++ 使用WSASend的某些重叠没有使用GetQueuedCompletionStatus及时返回?

C++ 使用WSASend的某些重叠没有使用GetQueuedCompletionStatus及时返回?,c++,windows,iocp,C++,Windows,Iocp,背景:我正在使用CreateIoCompletionPort、WSASend/Recv和GetQueuedCompletionStatus在服务器上执行重叠套接字io。对于流控制,当发送到客户端时,我只允许在IOCP中弹出所有挂起的重叠时调用几个WSASend() 问题:最近,出现了重叠无法返回到IOCP的情况。调用GetQueuedCompletionStatus的线程未获取它们,它们仍保留在本地挂起队列中。我已验证客户端是否从套接字接收数据,并且套接字已连接。进行WSASend()调用时未返

背景:我正在使用CreateIoCompletionPort、WSASend/Recv和GetQueuedCompletionStatus在服务器上执行重叠套接字io。对于流控制,当发送到客户端时,我只允许在IOCP中弹出所有挂起的重叠时调用几个WSASend()

问题:最近,出现了重叠无法返回到IOCP的情况。调用GetQueuedCompletionStatus的线程未获取它们,它们仍保留在本地挂起队列中。我已验证客户端是否从套接字接收数据,并且套接字已连接。进行WSASend()调用时未返回任何错误。如果没有如下所示的外部刺激,重叠“永远”不会回来:

  • 断开套接字与客户端或服务器的连接,会立即允许GetQueuedCompletionStatus线程检索重叠
  • 在所有重叠突然从队列中弹出之前,对WSASend()进行额外调用,有时需要几个
  • 问:有人见过这种行为吗?你知道这是什么原因吗

    谢谢, 如果TCP窗口已满,Geoffrey将无法及时完成WSASend()。在这种情况下,堆栈无法发送更多数据,因此您的
    WSASend()
    会等待,直到TCP堆栈可以发送更多数据,您的完成才会发生

    如果您的客户端和服务器之间有一个协议,该协议本身没有内置流量控制,并且您自己也没有根据写完成情况进行任何流量控制,只是以服务器可以发送的速度发送数据,那么您可能会遇到网络或您的客户端无法跟上TCP的速度的情况流控制开始(当TCP窗口满时)。如果您继续通过对
    WSASend()
    的附加调用异步触发数据,那么最终您将在机器上的所有非分页内存中进行仔细检查,此时所有赌注都已取消(很可能是驱动程序导致方框出现蓝屏)

    因此,总而言之,来自重叠套接字写入的完成可能而且有时需要比预期更长的时间才能恢复。在您的示例中,我希望您在关闭套接字时得到的完成都是失败的

    我在我的博客上更多地讨论了这一点;此处:此处:

    WSASend()
    如果TCP窗口已满,则可能无法及时完成。在这种情况下,堆栈无法发送更多数据,因此您的
    WSASend()
    会等待,直到TCP堆栈可以发送更多数据,您的完成才会发生

    如果您的客户端和服务器之间有一个协议,该协议本身没有内置流量控制,并且您自己也没有根据写完成情况进行任何流量控制,只是以服务器可以发送的速度发送数据,那么您可能会遇到网络或您的客户端无法跟上TCP的速度的情况流控制开始(当TCP窗口满时)。如果您继续通过对
    WSASend()
    的附加调用异步触发数据,那么最终您将在机器上的所有非分页内存中进行仔细检查,此时所有赌注都已取消(很可能是驱动程序导致方框出现蓝屏)

    因此,总而言之,来自重叠套接字写入的完成可能而且有时需要比预期更长的时间才能恢复。在您的示例中,我希望您在关闭套接字时得到的完成都是失败的


    我在我的博客上更多地讨论了这一点;此处:此处:

    您的应用程序是单线程还是多线程?它是多线程的。单线程循环并仅调用GetQueuedCompletionStatus并回收重叠。另一个线程使用WaitForSingleObject(短超时100ms),并在设置事件时调用WSASend()。你的应用程序是单线程还是多线程?它是多线程的。单线程循环并仅调用GetQueuedCompletionStatus并回收重叠。另一个线程使用WaitForSingleObject(短超时为100ms),并在设置事件时调用WSASend()。