Linux下epoll的EPOLLHUP事件

2013年5月31日 由 Creater 留言 »

当客户端使用ctrl+c强制中断或者强制退出时,服务器端希望能够检测到这一变化,我一般是使用检测read是否返回0来判断。但是会出现这样的情况,当使用ctrl+c时,epoll可以收到EPOLLIN事件,并用read返回0;但是当客户端正常退出时,则检测不到该变化。tcpip

有人试图使用EPOLLHUP来完成这一检测,实际上EPOLLHUP不能用于服务器来检测客户端出现的异常,但EPOLLRDHUP是可以的。

在使用 epoll 时,对端正常断开连接(调用 close()),在服务器端会触发一个 epoll 事件。在低于 2.6.17 版本的内核中,这个 epoll 事件一般是 EPOLLIN,即 0x1,代表连接可读。连接池检测到某个连接发生 EPOLLIN 事件且没有错误后,会认为有请求到来,将连接交给上层进行处理。这样一来,上层尝试在对端已经 close() 的连接上读取请求,只能读到 EOF,会认为发生异常,报告一个错误。
因此在使用 2.6.17 之前版本内核的系统中,我们无法依赖封装 epoll 的底层连接库来实现对对端关闭连接事件的检测,只能通过上层读取数据时进行区分处理。不过,2.6.17 版本内核中增加了 EPOLLRDHUP 事件,代表对端断开连接,。
在使用 2.6.17 之后版本内核的服务器系统中,对端连接断开触发的 epoll 事件会包含 EPOLLIN | EPOLLRDHUP,即 0x2001。有了这个事件,对端断开连接的异常就可以在底层进行处理了,不用再移交到上层。重现这个现象的方法很简单,首先 telnet 到 server,然后什么都不做直接退出,查看在不同系统中触发的事件码。注意,在使用 2.6.17 之前版本内核的系统中,sys/epoll.h 的 EPOLL_EVENTS 枚举类型中是没有 EPOLLRDHUP 事件的,所以带 EPOLLRDHUP 的程序无法编译通过。

广告位

发表评论

你必须 登陆 方可发表评论.