服务器无法检测到客户端的异常退出

大智_Unity玩家 2011-11-02 02:56:50
前两天去笔试一个网游公司,其中有一个笔试题是:
服务器在下列哪种情况下无法检测到客户端的退出。
1、剪断网线
2、杀死客户端进程
3、拔掉电源
还有个答案忘了
我的理解是:以根据服务器收到的数据的长度来判断,如果服务器收到的数据长度是0,那么意味着客户端程序已经断开了连接。但是原来做小项目的时候没有考虑客户端异常退出的情况。
请问下什么情况下服务器能接收到客户端发送的0长度的信息?什么情况下会没有?
...全文
316 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq120848369 2011-11-02
  • 打赏
  • 举报
回复
SO_KEEPALIVE
允许在面向连接的套接字上发送 keep-alive 消息的功能.是一个布尔整数.


这个选项基本没用,2小时送一次,太慢了。

情况2服务端照样会recv EOF,没有关系。

情况1,2服务端的确不知道,无论服务端读还是写,服务端都不知情,完全是TCP协议保证不停的重发某些还没ACK的数据,应用层编程根本意识不到。

如果是阻塞套接字,我们可以设置TIMEOUT选项,主动认定对端有问题,主动close。 像web服务器(例如apache传统prefork,worker架构),一般是这样的,你telnet一个网站,如果不赶紧发送数据,对端会主动关闭。

如果是非阻塞套接字,一般用select/epoll模型,它们自身提供了一些很有效的监控参数。例如:

 EPOLLERR
Error condition happened on the associated file descriptor. epoll_wait(2) will always wait for this event; it is not necessary to set it
in events.

EPOLLHUP
Hang up happened on the associated file descriptor. epoll_wait(2) will always wait for this event; it is not necessary to set it in
events。


不过我觉得对于1,3还是没有什么用。

最好的办法还是自己实现keepalive,我也没有见过类似的写法,不过我这样设计应该是合理的。

epoll调用设置一个超时值,每个connection对应一个超时值,维护一个LRU链表以及一个哈希表。

每次epoll返回,无论是connection有事件发生,还是epoll超时,都从LRU链表末尾扫描,对于超时的connection予以close以及清理,停止于一个没有超时的connection。

对于epoll正常返回,走如下流程:

1,获取当前时间T
2,处理所有connection读写事件,并且每个connection处理结束后更新该connection到LRU链表头部,更新其超时时间为T+expire。(对于accept的new connection,同样放倒lru头部,另外加入hash映射。)
3,处理事件结束后,从lru尾部向前扫描,对于超时connection予以close,清理epoll注册,删除hash映射(socket->connection的映射)。 扫描结束于某个未过期connection。

这样就OK了,由于做了LRU,所以扫描量不会很大,另外这个处理不需要实时性,所以epoll的超时时间可以设置的大一些,清理动作也可以选择稀疏一些,比如本次epoll返回时间与上次清理时间差出expire之后才执行一次清理,或者隔几次返回清理一次。
luciferisnotsatan 2011-11-02
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 die654456 的回复:]

2、杀掉客户端进程。操作系统会回收进程,因此建立好的通信连接会关闭。
这种通信连接的建立和关闭是TCP层(网络协议栈)实现的,因此在上层不可见。
服务器端能检测到退出。

1和3应该都无法检测客户端异常退出。
比如剪断网线,服务器调用的read函数依赖TCP层,
TCP具有请求确认和超时重发机制,大概要几十秒或者几分钟才知道对方连接关闭,才把连接断开。
[/Quote]
++

TCP 设置SO_KEEPALIVE选项。这样,每个一段时间,就会发个探测分节,3种情况都能知道对端挂了。
DIE654456 2011-11-02
  • 打赏
  • 举报
回复
2、杀掉客户端进程。操作系统会回收进程,因此建立好的通信连接会关闭。
这种通信连接的建立和关闭是TCP层(网络协议栈)实现的,因此在上层不可见。
服务器端能检测到退出。

1和3应该都无法检测客户端异常退出。
比如剪断网线,服务器调用的read函数依赖TCP层,
TCP具有请求确认和超时重发机制,大概要几十秒或者几分钟才知道对方连接关闭,才把连接断开。

65,203

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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