我的完成端口设计模式如下:
开两个WorkerThread,收到数据后保存到内存池中,另有一个线程池对收到的数据进行重新组包并分析,然后由调用WSASend把结果送给客户端。今天发现一个问题:连接一个客户端,数据收发N次后,把客户端断开,服务端跟踪到BytesTransferred = 0的事件竟然发生了N次!!如果服务端只发送不接收,N次后,BytesTransferred = 0的事件也还是发生了N次,如果把线程池中的WSASend代码屏蔽,只接收不发送,就不会出现这种情况。那位兄弟知道是什么原因引起的???
开两个WorkerThread,收到数据后保存到内存池中,另有一个线程池对收到的数据进行重新组包并分析,然后由调用WSASend把结果送给客户端。今天发现一个问题:连接一个客户端,数据收发N次后,把客户端断开,服务端跟踪到BytesTransferred = 0的事件竟然发生了N次!!如果服务端只发送不接收,N次后,BytesTransferred = 0的事件也还是发生了N次,如果把线程池中的WSASend代码屏蔽,只接收不发送,就不会出现这种情况。那位兄弟知道是什么原因引起的???
方法 1
shutdown(ClientHandle, SD_SEND); // socket 进入 FN_WAIT_1 状态
Closing := true; // 设半关状态, 还可以收, 只是个自定义状态
这时 select ClientHandle 后发生收到数据为 0 // socket 进入 FN_WAIT_2
调用 CloseSocket(ClientHandle) // 资源立即回收
这个好处是不要系统干与, 资源回收 方法 2
另一种方法是直接调用 Close // socket 进入 CLOSE_WAIT 状态, 由系统回收资源
好处是简单, 但有时 CLOSE_WAIT 会存在很久很久 2 客户机发起的服务端过程
select 时发生收到数据包为 0
立即应调用 shutdown(ClientHandle, SD_RECV) // 还可发
Closing := true
发数据 send... // 发完数据
if Closing then Close(ClientHandle) // 立即关闭 也可以直接关而放弃未发完数据你的情况在第二种
线程池中调用WSASend后,工作者线程GetQueuedCompletionStatus发现有数据发送,发送后我针对该PerIoData又做了次WSARCV,问题就出在这里,这里的PerIoData是线程中创建的,调用了WSARCV就把这个新的Overlpad关联到了IO端口上,所以终端断开时,就触发了该Socket上的所有Overlpad。害我一个晚上没睡好早上上班突然发现。换换脑子常会有种柳暗花明的感觉。
散分