免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3985 | 回复: 7

[C] [抛砖引玉]epoll模型下一些问题思考 [复制链接]

论坛徽章:
0
发表于 2009-08-27 11:36 |显示全部楼层
近来在学epoll,遇到些问题,总结思考了一下,放在这里,一起讨论讨论,当作抛砖引玉,希望有经验的朋友不吝赐教。


epoll模型有两种工作模式,ET和LT,两种模式下都有一些细节值得注意,以下是一些思考:

一、ET模式下
Q1: 调用accept时,到底TCP完成队列里有多少个已经建立好的连接?
这里又得分情况来说:
  • 没有连接。这种情况发生在TCP连接被客户端夭折,即在服务端调用accept之前客户端给出一个RST。该RST导致刚刚建立好的连接从服务器端的TCP完成队列中被移出。源自berkeley的实现会在内核处理该事件,并不会将该事件通知给服务程序,如果套接口被设置为阻塞模式,就会导致accept函数被阻塞,程序挂起,一直要等到下一个连接到来,这也是为什么采用非阻塞的accept的原因;其他的实现通常会返回ECONNABORTED或EPROTO错误。
解决方法: 采用非阻塞的accept,在accept返回后处理ECONNABORTED、EPROTO、EINTR错误。
  • 一个以上的连接。一个连接很容易理解,多个连接的情况出现在有多个连接请求同时到达的情况,由于是边缘触发,epoll_wait只返回一次,然后调用accept处理一个请求。这会导致TCP完成队列中依然存在连接未被处理。
解决办法: 1):将该套接口设置为非阻塞模式,然后将accept用while循环包住,处理完TCP完成队列中的所有连接再跳出循环。2): 将accept放入一个单独的线程中,这样还可以采用阻塞模式。
Q2: read函数应当如何处理?
read函数有可能不能够一次将内核缓冲的数据读完,由于采用的ET模式,epoll_wait不会因为内核缓冲区还有数据而继续返回。这就会导致内核数据不能及时、完全地读到服务程序。
解决办法: 将套接口设置为非阻塞,再用while循环包住read一直读到产生EAGAIN错误,采用非阻塞套接口的原因在于防止read被阻塞住。网上看见有的朋友说也可以采用阻塞套接口,判断read的返回值是否小于期望值,小于就证明数据读完,但是个人认为这里存在一个临界情况,比如内核缓冲有2048字节,期望读1024字节,读完第二次后read返回的是1024,等于期望值,于是再读,但此时内核已经没有数据,于是read被阻塞(自个的思考,不知有务否)。
Q3: 写缓冲区什么时候可以导致epoll_wait函数返回可写状态?
个人对这个问题不是很清楚,按资料说法是该缓冲区从不可写变为可写则返回,那么该套接口刚创建的时候处于可写状态,是否会导致一直返回不了可写状态,也就是说第一次永远返回不了,因为没有任何调用会使该套接口从不可写变为可写。
另外,写的时候还有些什么要注意的么?
二、LT模式下
Q1: accept函数
accept函数同样存在连接被夭折的情况,和ET模式下类似。但这种模式下不会存在处理不完多个请求的情况。因为只要有连接存在TCP完成队列中,epoll_wait就会一直返回。
Q2: read函数
同样可以避免因为一次读不完内核缓冲区的数据的情况。
Q3: 当内核写缓冲空闲时,可写状态会一直返回,如何处理?(这个曾是tencent的一个面试题)
A1: 不将可写条件加入epoll集中,采用非阻塞I/O,有数据可写时,直接写,如果返回是EAGAIN,则将可写加入epoll集中,写完后移出。
其他方法,欢迎讨论。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2009-08-27 15:54 |显示全部楼层
en. 你总结的已经很好了,

我想讨论一个问题
如果我在LT 模式下, 把recv 套在while(1)中直到EAGAIN,跟ET模式有什么区别,底层会高效很多吗?

论坛徽章:
0
发表于 2009-08-27 17:21 |显示全部楼层
搜索一下,坛子里之前有很多讨论的帖子,不过还要说lz总结的很好~~

论坛徽章:
0
发表于 2009-08-27 20:34 |显示全部楼层
mark

论坛徽章:
0
发表于 2009-08-28 09:23 |显示全部楼层

回复 #2 cookis 的帖子

个人感觉通过while(1)会高效一些吧,通过epoll_wait来毕竟绕了个大圈子,这个问题该如何证明?

论坛徽章:
0
发表于 2009-08-28 09:43 |显示全部楼层
原帖由 cookis 于 2009-8-27 15:54 发表
en. 你总结的已经很好了,

我想讨论一个问题
如果我在LT 模式下, 把recv 套在while(1)中直到EAGAIN,跟ET模式有什么区别,底层会高效很多吗?


这种情况应该跟epoll没啥关系了

论坛徽章:
0
发表于 2009-08-28 09:45 |显示全部楼层
既然要用epoll,就要用非阻塞模式,包括主socket,这样处理问题就简单了。
从设计上,要给每个连接设计一系列状态,以便在读写数据时,能方便地寻找“协议解析边界”以及进行任务状态跟踪

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2009-08-28 10:45 |显示全部楼层
我的意思是 LT 和ET 两者在使用区别上主要在 ET要在 recv/send 直到EAGAIN的时候,那如果LT模式下,一个fd可读了,我也一直读,读到EAGAIN, 至少在应用层上这两者没区别了,那二者在底层实现上有什么大的区别呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP