Epoll实验总结
一、超时实验
1. 安装后的第一步
建立一个阻塞模式的tcp连接到一个没有监听的服务端口(肯定连不上,然后等待超时),然后将这个socket描述符,交由epoll管理。注册的epoll事件为:
-
event = EPOLLIN EPOLLOUT EPOLLRDHUP EPOLLERR EPOLLET EPOLLPRI EPOLLHUP
结果:当tcp连接超时的时候,触发的事件有EPOLLIN 、 EPOLLOUT 、EPOLLRDHUP 、 EPOLLERR、EPOLLHUP,也就是只有紧急数据的事件没有发生。
二、调用read(),返回0时,继续write()
建立一个阻塞模式的tcp连接到有监听的服务器端口上,然后将这个socket描述符,交由epoll管理。注册的epoll事件为:
-
event = EPOLLIN EPOLLOUT EPOLLRDHUP EPOLLERR EPOLLET EPOLLPRI EPOLLHUP
当该描述符可写时,写10字节的数据到服务端;当该描述符可读时,读10字节的数据;服务端读10字节的数据,然后休眠5秒,之后close连接。 实验结果,总结如下:
- tcp三次握手一旦完成,该socket描述符的EPOLLOUT触发,即可写
- 服务端休眠5秒后,关闭连接。触发的事件有EPOLLIN 、 EPOLLOUT 、EPOLLRDHUP 、 EPOLLERR、EPOLLHUP。此时read返回0,write仍然可写
- 之后又触发了EPOLLIN 、 EPOLLOUT事件。此时read仍然返回0,write出错,错误为SIGPIPE。这次触发的原因是,在2中的write了一个closed的连接,由于非阻塞,造成write成功的假象,所以这儿epoll又接到了通知,弥补上一步的错误。
三、调用read,返回0,不再write
建立一个阻塞模式的tcp连接到有监听的服务器端口上,然后将这个socket描述符,交由epoll管理。注册的epoll事件为:
-
event = EPOLLIN EPOLLOUT EPOLLRDHUP EPOLLERR EPOLLET EPOLLPRI EPOLLHUP
当read返回0后,不再write数据到服务端;服务端读10字节的数据,然后休眠5秒,之后close连接。
实验结果:
- tcp三次握手一旦完成,该socket描述符的EPOLLOUT触发,即可写
- 触发EPOLLIN 、 EPOLLOUT 、EPOLLRDHUP 、 EPOLLERR、EPOLLHUP。此时read返回0。之后不再有事件触发
四、在ET模式下,只需注册EPOLLIN | EPOLLOUT就可以了,如果有错误发生,这两个事件也被能触发,然后判断错误类型就可以了
EPOLLIN , EPOLLOUT , EPOLLPRI, EPOLLERR 和 EPOLLHUP事件
- listen fd,有新连接请求,[b]对端发送普通数据 触发EPOLLIN。
- 带外数据,只触发EPOLLPRI。
- 对端正常关闭(程序里close(),shell下kill或ctr+c),触发EPOLLIN和EPOLLRDHUP,但是不触发EPOLLERR 和EPOLLHUP
- 再man epoll_ctl看下后两个事件的说明,这两个应该是本端(server端)出错才触发的。
- 对端异常断开连接(只测了拔网线),没触发任何事件。 附man EPOLLIN 连接到达;有数据来临; The associated file is available for read(2) operations. EPOLLOUT 有数据要写 The associated file is available for write(2) operations. EPOLLRDHUP 这个好像有些系统检测不到,可以使用EPOLLIN,read返回0,删除掉事件,关闭close(fd);如果有EPOLLRDHUP,检测它就可以直到是对方关闭;否则就用上面方法。 Stream socket peer closed connection, or shut down writing half of connection. (This flag is especially useful for writing simple code to detect peer shutdown when using Edge Triggered monitoring.) EPOLLPRI 外带数据 There is urgent data available for read(2) operations. EPOLLERR 只有采取动作时,才能知道是否对方异常。即对方突然断掉,是不可能有此事件发生的。只有自己采取动作(当然自己此刻也不知道),read,write时,出EPOLLERR错,说明对方已经异常断开。 EPOLLERR 是服务器这边出错(自己出错当然能检测到,对方出错你咋能知道啊) 关于 EPOLLERR: socket能检测到对方出错吗?目前为止,好像我还不知道如何检测。但是,在给已经关闭的socket写时,会发生EPOLLERR,也就是说,只有在采取行动(比如读一个已经关闭的socket,或者写一个已经关闭的socket)时候,才知道对方是否关闭了。这个时候,如果对方异常关闭了,则会出现EPOLLERR,出现Error把对方DEL掉,close就可以了。
各类事件
- 监听的fd,此fd的设置等待事件 EPOLLIN;或者EPOLLET |EPOLLIN 由于此socket只监听有无连接,谈不上写和其他操作。 故只有这两类。(默认是LT模式,即EPOLLLT |EPOLLIN)。 说明:如果在这个socket上也设置EPOLLOUT等,也不会出错,只是这个socket不会收到这样的消息。
- 客户端正常关闭 client 端close()联接server 会报某个sockfd可读,即epollin来临。 然后recv一下 , 如果返回0再掉用epoll_ctl 中的EPOLL_CTL_DEL , 同时close(sockfd)。有些系统会收到一个EPOLLRDHUP,当然检测这个是最好不过了。只可惜是有些系统,上面的方法最保险;如果能加上对EPOLLRDHUP的处理那就是万能的了
- 客户端异常关闭 客户端异常关闭,并不会通知服务器(如果会通知,以前的socket当然会有与此相关的api)。正常关闭时read到0后,异常断开时检测不到的。服务器再给一个已经关闭的socket写数据时,会出错,这时候,服务器才明白对方可能已经异常断开了(读也可以)。Epoll中就是向已经断开的socket写或者读,会发生EPollErr,即表明已经断开
- EpollIn
- 监听的skocket只需要EpollIn就足够了,EpollErr和EpollHup会自动加上 监听的socket又不会写,一个EpollIn足矣。
补充 EpollErr
当客户端的机器在发送“请求”前,就崩溃了(或者网络断掉了),则服务器一端是无从知晓的。按照你现在的这个“请求响应方式”,无论是否使用epoll,都必须要做超时检查。因此,这个问题与epoll无关。EpollErr这种错误必须是有动作才能检测出来。服务器不可能经常的向客户端写一个东西,依照有没有EpollErr来判断客户端是不是死了。因此,服务器中的超时检查是很重要的。这也是以前服务器中作死后确认的原因。新的代码里也是时间循环,时间循环….!!!服务器 中的超时检查!!!很重要
转载: Epoll实验总结