编写大容量和健壮的服务器—正确处理IOCP连接关闭

denglibo 2007-08-16 10:56:55
及时监测连接被动关闭

除非有特别要求,否则你应该总是对每个连接保持一个挂起的接收pending io

(使用WSARecv投递)。如果用户主动关闭连接,你的GetQueuedCompletionStatus调用将返回成功,但接收到的数据长度为0,你能根据这点检测连接是否已被对方关闭。如果连接被重置或者io被取消(如果你调用了CancelIo的话),GetQueuedCompletionStatus将返回失败,注意这时还应该判断GetQueuedCompletionStatus调用返回的lpOverlapped值,如果该值不为NULL,说明iocp已经检测到一个连接已经中断。



安全的关闭连接

很多人写的服务器网络库有一个难以接受的缺陷(包括我曾就职公司的一些同事),当服务器程序主动关闭连接时,刚发往客户端的包有时出现丢失,这时他们推荐的方式往往是发送数据后等待几秒再关闭连接。豪无疑问,这是一种笨拙的实现方式,他们遇到的问题根源是什么呢?

在非IOCP模式网络程序中,你只要简单的调用closesocket函数就可以确保数据在操作系统释放socket之前安全到达对方,但在IOCP模式下,如果调用closesocket时有未决的pending IO将导致socket被重置,所以有时会出现数据丢失。正统的解决方式是使用shutdown函数(指定SD_SEND标志),注意这时可能有未完成的发送pengding IO,所以你应该监测是否该连接的所有是否已完成(也许你要用一个计数器来跟踪这些pending IO),仅在所有send pending IO完成后调用shutdown。

当你调用shutdown时,也许数据仍然停留在操作系统的缓冲,操作系统将在数据发送完后发出一个FIN包来启动关闭进程,客户端接收完数据后,将接受到一个0长度的包,以此判断连接已关闭(你写的客户端肯定有检测连接关闭,不是吗?),然后调用closesocket,这时服务器的GetQueuedCompletionStatus将接收到一个数据长度为0的包,这时你就可以调用closesocket,并释放相关连接资源。

在绝大部分情况下上述的过程连接能完美的关闭。如果你特别注重服务器的安全性和健壮性,可能你还需要做一个“连接关闭队列”,对每个已调用shutdown的连接放到这个队列,然后定时的对这个队列扫描,如果一个连接5秒(你也可以自己调整)还不能关闭,那么就强制关闭它。



处理大并发短连接时如何避免TIME_WAIT状态
......
详细文章请参看 http://libo.deng.blog.163.com
...全文
611 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
54993699 2008-03-22
  • 打赏
  • 举报
回复
楼主好方法。。
bigbook2000 的看法基本上是没有对的。
denglibo 2007-09-15
  • 打赏
  • 举报
回复
楼上基本没理解我的文章
macrosu 2007-09-13
  • 打赏
  • 举报
回复
关于安全问题,不同的业务有不同的实现方法,那个主动那个被动不是固定的。
安全的关闭连接,其实就涉及到一个问题,就是内存资源的分配释放上,遵循的线路是分配,使用完,释放掉,不管你怎样去设计实现你的服务器,你都要考虑刚分配的内存到那里了,谁在用,是不是用完了,用完了我就释放它吧,就这个路线。iocp为了性能考虑,不像send这样的函数,缓冲区由系统负责,而是由用户层负责有效性,所以你必须要有个机制保证你传给系统的资源,确保在释放前系统已经不再用了,能做到这点,就安全了,不需要延迟时间这样的策略来实现,这个是不安全的,收发结果的回馈时间是不能预计的,比如你close一个socket,之前的recv或者send什么的不一定马上就有结果了。
bigbook2000 2007-08-28
  • 打赏
  • 举报
回复
当服务器程序主动关闭连接时,刚发往客户端的包有时出现丢失




---------------------------
从来不考虑这种情况,服务器“主动”关闭,服务器永远都设计成为“被动”关闭。应该将服务器成功发送后关闭连接模式设计成客户端成功收到数据后关闭连接,如果你设计成第一种模式,除非特殊需要否则设计就是错误的。我这么以为。
denglibo 2007-08-28
  • 打赏
  • 举报
回复
楼上果然是牛人,你的自信令我佩服,不过我倒想提醒一下,原则上,任何依赖客户端控制流程的设计都是不安全的,比如按你上面说的做,如果万一出现客户端强制关闭连接(reset包丢失)或者网络中断,服务器的连接应该何时释放呢?你是不是还需要一种连接检测机制,更不用说处理爆发性短连接的场合。
如果楼上还具备一点安全常识的话,你更应该能明白,你的这种依赖客户端的机制极不安全,黑客只需要不断连接你,然后不断“无声无息”的关闭连接(不发出FIN或者RESET),我保证你的服务器不到10分钟内存就消耗光。
redex 2007-08-24
  • 打赏
  • 举报
回复
mark.
DentistryDoctor 2007-08-16
  • 打赏
  • 举报
回复
说得很子,不过blog打不开啊。
denglibo 2007-08-16
  • 打赏
  • 举报
回复
顶一下人气

4,359

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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