winsock完成端口套接字重用注意事项
刚申请到博客,第一篇随笔(๑•̀ㅂ•́)و✧
关于DisconnectEx的一个问题,目前主要发现在windows10中出现了这个问题,winserver2008 win7都没有这个问题。
被DisconnectEx成功重用后的套接字,再次被AcceptEx事件返回之后,会有可能出现一种明明已经投递了WSARecv,客户端也确实正在WSASend,但是无法收到通知。
所有日志都符合预期的结果。
产生这个bug时,调用WSARecv明显的返回了ERROR_IO_PENDING,证明代码是没有问题的。
我使用了一个定时器检查投递标志,也确实是正在处理WSARecv投递,并没有返回。
并且,我把服务端设置为单线程,只有一个套接字,也就是完全不存并发因素在里面,也依旧是这样子。
服务端同一时间只存在一个投递事件,并且所有事件使用的重叠结构都是不同的,也就是证明了逻辑绝对没有问题。
我找出了重现这个bug的方法(不太确定是否真的如此):
服务端只投递1个套接字进行AcceptEx,
客户端使用4,5个线程去进行发送数据,一个线程负责接收数据,也就是将客户端的IO行为当成异步模式来写,目的是实现让服务端大部分时候,都在处理WSASend,也即是让服务端处于高并发状态,单线程不处理业务,随便发送点数据给客户端,能达到10万+IO并发(我的CPU默认频率4g)。
然后,只要在服务端处于WSASend时,关闭掉客户端,让服务端调用WSASend时,返回错误代码WSAECONNRESET (10054)。
然后服务端会顺利的DisconnectEx,并在收到通知之后AcceptEx。
此时重新开启客户端再去连接时,AcceptEx事件会正常返回,然后接着服务端调用WSARecv,也正常。
但此时客户端发送数据,就一直卡着了,客户端处于WSASend处理中,服务端处于WSARecv处理中,大家都不返回完成通知,但是此时再次关闭客户端时,WSARecv返回通知了,能正常重用套接字之后一系列的操作,再次连上,还是一样,WSARecv不能返回通知。
然后我感觉可能在重用套接字后,需要重新将套接字添加到完成端口,也就是要再次CreateIoCompletionPort,但事实证明这其实是我的感觉。
这中间,经历了差不多两天的纠结,我仔细检查校对过所有代码,并没有问题,之后把服务端丢到不同的操作系统去,也没有问题,就是用来写代码的win10专业版,产生了这个bug,希望有相同经历的朋友可以分享下关于这个问题的具体问题到底是如何导致的。虽然我目前的测试结果是只在win10有这个问题,但实际上,其他系统都是虚拟机,并发量达不到物理机的级别,所以并不好说到底是不是系统的原因。