2017-10-12 58 views
0

我目前正在使用C++编写服务器应用程序。我的主要启示有这些例子:closesocket()未完成IOCP的挂起操作

Windows SDK IOCP Excample

The I/O Completion Port IPv4/IPv6 Server Program Example

我的应用程序是强烈类似于这些(socketobj,packageobj,...)。

一般来说,我的应用程序运行没有问题。仍然导致我麻烦的唯一的事情是半开放的连接。

我的策略是:我在一段时间内检查每个连接的客户端,并计算一个“空闲计数器”。如果发生一次完成,我重置这个计时器。如果空闲计数器变得太高,我设置一个布尔值来防止其他线程发布操作,然后致电closesocket()

我的假设是,现在套接字已关闭,挂起的操作将完成(可能不会立即但一段时间后)。这也是MSDN文档描述的行为(提示,第二段)。我需要这个,因为只有在所有操作完成后才可以释放资源。

长话短说:这不适合我。我用我的testclient应用程序和一些cout和断点调试做了一些测试,发现关闭套接字的挂起操作没有完成(即使在等待10分钟后)。我也已经尝试在closesocket()之前拨打shutdown(),并且都没有返回任何错误。

我在做什么错?其他人也有遇到同样的状况吗? MSDN文档是否错误?有什么选择?

我目前想的“苟延残喘”的功能,或与CancelIoEx()功能明确取消每个操作

编辑:(谢谢你的回复)

昨天晚上我为每个sockedobj添加了一个链接列表来保存待处理操作的每个io obj。有了这个,我尝试了CancelIOEx()函数。对于大多数操作,函数返回0和GetLastError()返回ERROR_NOT_FOUND

在这种情况下释放每个Io Obj是否安全?

我还发现,当我在同一台机器上运行我的服务器应用程序和客户端应用程序时,发生这种情况的频率更高。它偶尔会发生,服务器不能完成写入操作。我认为这是因为客户端接收缓冲区已满而发生的。 (客户端不会停止接收数据!)。

尽快切断代码。

+0

请提供[mcve]。 –

+0

如果接收方没有收到,*当然*发送方将阻塞,除非他处于非阻塞模式,哪个IOCP不是。您测试无效。 – EJP

+0

@EJP这是否意味着,我不可能事先检测到这一点?看起来'WSASend()'可以发布,但它永远不会完成。我该如何改进测试? – Woife

回答

0
  • “逗留”设置可用于重置连接,但这样您将(a)丢失数据和(b)向对等体提供重置,这可能会使其感到恐惧。
  • 如果你正在考虑积极的持续超时,它并没有真正的帮助。
  • 关闭读取应该终止读取操作,但关闭写入只在挂起写入后排队,因此根本没有任何帮助。
  • 如果挂起的写入是问题,而没有完成,则必须将其取消。
+0

感谢您的支持回答。我不会在意dataloss。我的应用程序的意图是,客户端应该通常连接到“永远”并周期性地发送相同的数据,所以如果客户端丢失连接并留下半开放的套接字,我就没有问题了。对我来说什么是重要的:应用程序应该能够恢复内存和一切,以便正常进行。 “害怕同伴”是什么意思? – Woife

+0

挂上。如果客户端关闭连接,服务器的'read()'将返回-1,于是关闭该通道。你根本不需要采取任何特别的措施:它只是网络编程的一个正常部分。 '骇人听闻'意味着它将得到一个连接重置,而不是像刚刚描述的通常的流结束:但是如果它是正在进行关闭的客户端,那当然不适用。在我看来,你的I/O操作不能完成的唯一方法就是如果它们正在等待写入。现在看来你的读取代码中有一个bug。 – EJP

+0

对不起,这很长的响应时间。最后,它就像你所有的建议:我是问题所在。 'closesocket()'的功能正如预期的那样。我有一次这个问题是一个连接没有正常结束,但我无法复制它。我将此标记为答案,因为它认为这是对所提及可能性的一个很好的总结。 我想补充的一件事是:如果你开发一个IOCP应用程序,你还应该照顾部分发送(因为它们通常不应该发生),并在发生这种情况时终止连接。在大多数例子中,没有人关心这个,但它很重要。 – Woife