有关完成端口客户端断开的问题

xwchena 2006-11-09 11:10:32
我的完成端口设计模式如下:
开两个WorkerThread,收到数据后保存到内存池中,另有一个线程池对收到的数据进行重新组包并分析,然后由调用WSASend把结果送给客户端。

今天发现一个问题:连接一个客户端,数据收发N次后,把客户端断开,服务端跟踪到BytesTransferred = 0的事件竟然发生了N次!!如果服务端只发送不接收,N次后,BytesTransferred = 0的事件也还是发生了N次,如果把线程池中的WSASend代码屏蔽,只接收不发送,就不会出现这种情况。。。。那位兄弟知道是什么原因引起的???
...全文
329 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
xwchena 2006-11-10
  • 打赏
  • 举报
回复
找到原因了,是这样的
线程池中调用WSASend后,工作者线程GetQueuedCompletionStatus发现有数据发送,发送后我针对该PerIoData又做了次WSARCV,问题就出在这里,这里的PerIoData是线程中创建的,调用了WSARCV就把这个新的Overlpad关联到了IO端口上,所以终端断开时,就触发了该Socket上的所有Overlpad。

害我一个晚上没睡好。。。早上上班突然发现。换换脑子常会有种柳暗花明的感觉。
散分
xwchena 2006-11-09
  • 打赏
  • 举报
回复
江湖规矩,自己先顶
xwchena 2006-11-09
  • 打赏
  • 举报
回复
我做了一下测试,如果在WorkerThread中收到数据后不写内存,直接返回给客户端,这时客户端断开就不会出现上面的现象。看来是在线程池中发送WSASend引起的。。。但还不知道怎么解决。。。。。
comanche 2006-11-09
  • 打赏
  • 举报
回复
没第二种呵, 你的情况是 客户机发起关闭服务端对应过程
comanche 2006-11-09
  • 打赏
  • 举报
回复
完成端口一般不用, 原理相同, 说说无防吧

socket 在一方 close 发生时, select 确认是否有包时是立即返回, 并且收发的字节为0, 完成端口在后面也跑不了用这个函数确认有没动作发生

正常情况下 Close 是双向的(shutdown), 可以由服务端发生也可以由客户端发起, 发起的一方只是不再发送数据, 连接并没关闭, 进入半连接状态(单向数据流), 直到另一方也关闭, 就是说有4个状态, FN_WAIT_1, FN_WAIT_2, CLOSE_WAIT, CLOSEING(这个太快发生可能是看不到的)

因此这样问题要分2头4方面去看, 客户机代码不严格, 也不可靠, 随时可能断线, 反正是重起就能用, 所以没什么说, 大多数都是直接调用 Close 去结束 socket

服务器主动发起关闭连接, 服务端对应一般过程
方法 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) // 立即关闭

也可以直接关而放弃未发完数据

你的情况在第二种
xwchena 2006-11-09
  • 打赏
  • 举报
回复
没人啊???

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧