在对系统问题进行排查时,我发现了一个奇怪的现象:明明是对方断开请求,系统却报告一个查询失败的错误,但从用户角度来看请求的结果正常返回,没有任何问题。
对这个现象深入分析后发现,这是一个基于 epoll 的连接池实现上的问题,或者说是特性 :)
首先解释一下导致这个现象的原因。
在使用 epoll 时,对端正常断开连接(调用 close()),在服务器端会触发一个 epoll 事件。在低于 2.6.17 版本的内核中,这个 epoll 事件一般是 EPOLLIN,即 0x1,代表连接可读。
连接池检测到某个连接发生 EPOLLIN 事件且没有错误后,会认为有请求到来,将连接交给上层进行处理。这样一来,上层尝试在对端已经 close() 的连接上读取请求,只能读到 EOF,会认为发生异常,报告一个错误。
因此在使用 2.6.17 之前版本内核的系统中,我们无法依赖封装 epoll 的底层连接库来实现对对端关闭连接事件的检测,只能通过上层读取数据时进行区分处理。
不过,2.6.17 版本内核中增加了 EPOLLRDHUP 事件,代表对端断开连接,关于添加这个事件的理由可以参见 “
[Patch][RFC] epoll and half closed TCP connections
”。
在使用 2.6.17 之后版本内核的服务器系统中,对端连接断开触发的 epoll 事件会包含 EPOLLIN | EPOLLRDHUP,即 0x2001。有了这个事件,对端断开连接的异常就可以在底层进行处理了,不用再移交到上层。
重现这个现象的方法很简单,首先 telnet 到 server,然后什么都不做直接退出,查看在不同系统中触发的事件码。
注意,在使用 2.6.17 之前版本内核的系统中,sys/epoll.h 的 EPOLL_EVENTS 枚举类型中是没有 EPOLLRDHUP 事件的,所以带 EPOLLRDHUP 的程序无法编译通过。
EPOLL
RDHUP
是从Linux内核2.6.17开始由GNU引入的
事件
。
当socket接收到对方关闭连接时的请求之后触发,有可能是TCP连接被对方关闭,也有可能是对方关闭了写操作。
如果不适用
EPOLL
RDHUP
事件
,我们也可以单纯的使用
EPOLL
IN
事件
然后根据recv函数的返回值来判断socket上收到的是有效数据还是对方关闭连接的请求。
游戏服务器中很多平台都会要求进行数据上报,数据上报都是使用http协议。我们游戏服务器的网络都是自己实现的,没有使用第三方网络库,所以在进行数据上报的时候也就自己用c++实现简单的http请求。由于网络一直都是使用
EPOLL
RDHUP
作为断开网络处理,该
事件
会比使用
EPOLL
IN和
EPOLL
OUT高效,但是在http协议中使用的时候可能会存在问题。
EPOLL
RDHUP
表示的是对方读挂起,可能对方还...
问题场景是:客户端关闭了连接,然后会不断收到标题里的信号
问题原因是:收到
EPOLL
RDUP
事件
时,没有执行close(events[i].data.fd),也就是没有客户端关闭连接后,服务端没有及时关闭对应的socket连接
这两个
事件
其实是一个东西,分别对应poll和
epoll
,通常用来判断对端是否关闭,但是当你对某个socket注册POLLIN和POLL
RDHUP
(
EPOLL
IN和
EPOLL
RDHUP
)时,在对端关闭时,对于poll来说会一直触发POLLIN + POLL
RDHUP
事件
,
epoll
也会触发
EPOLL
IN +
EPOLL
RDHUP
事件
,是否一直触发要看
epoll
是工作在LT模式下还是ET模式下。
所以,当我们使用POLL
RDHUP
(
EPOLL
RDHUP
)
事件
来判断对端是否关闭时,POLL
RDHUP
(
EPOLL
R
在内核2.6.17(不含)以前版本,要想知道对端是否关闭socket,上层应用只能通过调用recv来进行判断,在2.6.17以后,这种场景上层只需要简单处理即可。
一、未使用
EPOLL
RDHUP
服务端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <s...
epoll
事件
之
EPOLL
RDHUP
| Solrex² - 杨文博的博客,记录我的生活、思想、技术和梦想You are here: Home » 开源 » Linux »
epoll
事件
之
EPOLL
RDHUP
epo...
在对系统问题进行排查时,我发现了一个奇怪的现象:明明是对方断开连接,系统却报告一个查询失败的错误,但从用户角度来看请求的结果正常返回,没有任何问题。
对这个现象深入分析后发现,这是一个基于
epoll
的连接池实现上的问题,或者说是特性。
首先解释一下导致这个现象的原因。
在使用
epoll
时,对端正常断开连接(调用close()),在服务器端会触发一个
epoll
事件
。在低于2.6.17版本的内核
1、对端发送 FIN (对端调用close 或者 shutdown(SHUT_WR)).
2、本端调用 shutdown(SHUT_RD). 当然,关闭 SHUT_RD 的场景很少。
测试环境为 Linux localhost.localdomain 3.10.0-957.el7.x86_64 #1 SMP.........
原来的操作是代码层操作,即 触发
EPOLL
IN,recv返回0,关闭套接字即可。
现在,使用
EPOLL
RDHUP
状态,当客户端发送数据后立马关闭,(调用close(sockfd)),服务器无法接受数据,直接关闭。
代码如下:
if(events[i].events &
EPOLL
RDHUP
|| events[i].event...
1、listen fd,有新连接请求,对端发送普通数据 触发
EPOLL
IN。
2、带外数据,只触发
EPOLL
PRI。
3、对端正常关闭(程序里close(),shell下kill或ctr+c),触发
EPOLL
IN和
EPOLL
RDHUP
,但是不触发
EPOLL
ERR 和
EPOLL
HUP。
再man
epoll
_ctl看下后两个
事件
的说明,这两个应该是本端(server端)出错才触发的