POLLERR的故事

今天code review时,同事B对我代码中的poll()的处理做法提出了异议。于是做了些研究,还发现了一些好玩的故事。

异议的代码

我的代码是参考manpage写的,类似下面的做法。同事B说没有处理POLLERR、而且应当使用else if

OK。我赞同补充POLLERR的处理,但不赞同使用else if。原因:

  • fd的读事件、写事件可能会同时到达,因此我想同时处理这两个事件;
  • Linux Manpage里面的示例,就是三个if语句独立的。
ret = poll(fds, 2, timeout_msecs);
if (ret > 0) {/* An event on one of the fds has occurred. */for (i=0; i<2; i++) {if (fds[i].revents & POLLIN ) {/* Priority data may be written on device number i. */...}if (fds[i].revents & POLLOUT ) {/* Data may be written on device number i. */...}}
}

诡异的经历

但是同事B举出了他偶然体验到的诡异经历:

POLLIN, POLLOUT, POLLERR同时出现。

在这种异常下,我的代码处理逻辑就会坑爹了。

于是问题变成了,什么情况下会出现这种诡异场景、三个事件同时出现究竟是什么含义?

翻阅《UNIX环境高级编程》、《UNIX网络编程》里面对poll()的讲解,均没有提到信号是否会同时出现的问题(所以也没提到该不该用else if的事情了)。

在Github上查找POLLERR相关的代码,发现大多数人都是用3个if语句处理这三个事件。那真相究竟是啥?

牛人的解答

百般搜索,终于在StackOverflow.com上看到有人提到了一个相似的问题:

Sometimes epoll_wait returns with both POLLOUT & POLLERR events set for the same socket descriptor.

终于下面有大神做了解答:

Here is some good information on non-blocking tcp connect().

When a socket error is detected (i.e. connection closed/refused/timedout), epoll will return the registered interest events POLLIN/POLLOUT with POLLERR. So epoll_wait() will return POLLOUT|POLLERR if you registered POLLOUT, or POLLIN|POLLOUT|POLLERR if POLLIN|POLLOUT was registered.

Just because epoll returns POLLIN doesn't mean there will be data available to read, since recv() may just return the error from the non-blocking connect() call. I think epoll returns all the registered events with POLLERR to make sure the program calls send()/recv()/etc.. and gets the socket error. Some programs never check for POLLERR/POLLHUP and only catch socket errors on the next send()/recv() call.

翻译一下:

这儿有些很赞的关于非阻塞TCP connect()的信息。

当一个socket出现错误时(例如 连接断开/拒绝/超时),epoll()会返回POLLERR加上注册时的POLLIN/POLLOUT事件。所以,如果监听的是POLLOUT,那epoll_wait()会返回POLLOUT|POLLERR;如果监听的是POLLIN,那epoll_wait()会返回POLLIN|POLLERR。

注意epoll()返回POLLIN并不表示会有数据可读,因为recv()会立刻返回前一个错误码(即非阻塞的connect()调用)。我个人认为epoll()返回所有的注册事件加POLLERR,是为了确保程序会调用send()/recv()等等,进而发现socket出错了。毕竟有些代码从来不检测POLLERR/POLLHUP,只折腾send()/recv()等函数的错误码。

呵呵,Github上翻看了这么多代码,的确是大神说的样子。

验证

所以同事B的经历是常见的场景。而且很容易就能够触发。只要在连接上闹些问题,就能达到目的了。例如下面这段代码演示了连接失败时,POLLERR/POLLIN/POLLOUT事件都同时触发了。

示例中使用了getsockopt()来获取错误码;也可以直接使用read()/write()也是能够获取相同的错误码。

深入探究

StackOverflow的大神只做了简要的解答。真正的原因只能自己去翻看代码了。

翻阅内核代码(我的系统版本是Linux-2.6.32.57-x86 ),可以看到在tcp_poll()里(net/ipv4/tcp.c的389行,我的场景是TCP),对于所有sock错误都置了POLLERR。而异常情况下,POLLIN/POLLOUT则分别与RCV_SHUTDOWN/SEND_SHUTDOWN有关。换个视角,和连接断开有关的代码在tcp_reset()中(net/ipv4/tcp_input.c的3957行)的处理,里面的tcp_done()(代码)则明确设置了sk->sk_shutdown = SHUTDOWN_MASK——所以,对于关闭的连接,总是会有POLLIN/POLLOUT事件!

研究到此解决。真相大白。

所以啊,我还是听取同事B的建议,加个else if优化一下处理逻辑吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432783.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言内循环,C语言循环控制语句

C语言循环控制语句是一个基于C语言的编程语句&#xff0c;该语句主要有while循环语句、do-while循环语句和for循环语句来实现循环结构。中文名C语言循环控制语句类 别while循环语句&#xff0c;do-while语句等目 地实现循环结构属 于计算机领域归 类编程语句基 …

同步,异步,多线程,你怎么看?

同步&#xff0c;异步&#xff0c;多线程&#xff0c;你怎么看&#xff1f; 原文:同步&#xff0c;异步&#xff0c;多线程&#xff0c;你怎么看&#xff1f;[原创]讲解同步与异步的帖子多如牛毛&#xff0c;个人的理解&#xff0c;简单地说同步就是串行&#xff0c;异步就是并…

openssl-1.0.0b - libssl 移植到ARM Linux

开发环境&#xff1a; ubuntu 10.04 arm-linux-gcc version 4.4.1 目标环境 友善之臂mini6410 linux-2.6.36 移植步骤 1&#xff0e;至官网下载最新的openssl&#xff0c;解压缩 2&#xff0e;cd进入openssl-1.0.0b目录 3&#xff0e;执行./Confiugre linux-elf-arm&#xff0c…

C语言的putpiel函数,C语言graphics.h函数介绍

可编辑(一) 像素函数56. putpiel() 画像素点函数57. getpixel()返回像素色函数(二) 直线和线型函数58. line() 画线函数59. lineto() 画线函数60. linerel() 相对画线函数61. setlinestyle() 设置线型函数62. getlinesettings() 获取线型设置函数63. setwritemode() 设置画线模…

ARM-Linux下交叉编译opessl-1.0.0

本次任务是要完成嵌入式Linux下对openssl程序的支持。 我的开发环境&#xff1a;ARM9开发板 和 嵌入式Linux操作系统。装有Linux系统&#xff08;我的是ubuntu9.04&#xff09;的PC机一台。串口和串口连接线。串口调试软件&#xff1a;minicom。交叉编译工具:arm-unknown-l…

modf函数C语言,C / C ++中的modf()

该函数modf()用于将传递的参数拆分为整数和小数。在“ math.h”头文件中声明该变量以进行数学计算。它返回传递的参数的分数值。这是modf()C语言的语法&#xff0c;double modf(double value, double *integral_pointer);这里&#xff0c;值-分为整数和分数的值。积分指针-分割…

codeforces #236 div2 简洁题解

A:A. Nutstime limit per test1 secondmemory limit per test256 megabytesinputstandard inputoutputstandard outputYou have a nuts and lots of boxes. The boxes have a wonderful feature: if you put x (x ≥ 0)divisors (the spacial bars that can divide a box) to…

南京大学c语言试卷,2007年4月南京大学C语言期中试题.doc

2007年4月南京大学C语言期中试题南京大学《C语言程序设计》期中试卷(2006年4月15日)系科 学号______________姓名_____________成绩_______________注意事项&#xff1a;1、答案均写在答题纸上&#xff0c;写在卷面上无效;2、答题结束后将试卷及答题纸全部交给监考教师;3、闭卷…

web通信 长连接、长轮询

http://www.cnblogs.com/hoojo/p/longPolling_comet_jquery_iframe_ajax.html转载于:https://www.cnblogs.com/kszit/p/3605340.html

V210 SPI驱动分析

对于总线设备驱动&#xff0c;是需要分别创建设备和驱动两个结构体&#xff0c;然后根据name&#xff0c;互相匹配&#xff0c;匹配成功后&#xff0c;调用 驱动的probe函数&#xff0c;然后创建设备文件&#xff0c;实现驱动的业务逻辑。 因此&#xff0c;我们就以设备和驱动…

android 有值代码,Android:如何在代码中获取“listPreferredItemHeight”属性的值?

这样做&#xff1a;TypedValue value new TypedValue();((Activity)context).getTheme().resolveAttribute(android.R.attr.listPreferredItemHeight, value, true);编辑&#xff1a;由于尚未正确初始化DisplayMetrics实例&#xff0c;因此您将获得零值。它需要一个参考框架(显…

android 多个按钮响应,处理Android Recyclerview中的多个按钮单击并将响应存储在Array或ArrayList中...

我正在设计在线测验App。我设计了PlayQuiz.java文件如下&#xff1a;public class PlayQuiz extends AppCompatActivity {private RecyclerView recyclerView;DataBaseHelper database;private List quizList;private QuizAdapter adapter;Overrideprotected void onCreate(Bun…

密码学中的“盐值 Salt”

盐&#xff08;Salt&#xff09; 在密码学中&#xff0c;是指通过在密码任意固定位置插入特定的字符串&#xff0c;让散列后的结果和使用原始密码的散列结果不相符&#xff0c;这种过程称之为“加盐”。 以上这句话是维基百科上对于 Salt 的定义&#xff0c;但是仅凭这句话还是…

android 主线程调用,Android 主线程和线程之间相互发送消息

通过分析Activity源码&#xff0c;我们知道每个Activity都有一个Looper&#xff0c;所以主线程在接收Message是不需要调用Looper.prepare()和Looper.loop()&#xff0c;但是线程是不带Looper的&#xff0c;当线程要接收来自主线程的消息是就需要调用Looper.prepare()和Looper.l…

10 个十分难得的 javascript 开发经验

Javascript 的很多扩展的特性是的它变得更加的犀利&#xff0c; 同时也给予程序员机会创建更漂亮并且更让用户喜欢的网站。 尽管很多的开发人员都乐于颂扬 javascript&#xff0c;但是仍旧有人看到它的阴暗面。 使用很多 javascript 代码的 web 页面会加载很慢&#xff0c;过多…

简单的UTF8编码生成

用记事本建一个文件&#xff0c;用editplus打开&#xff0c;并转成UTF8格式 然后写中文字符 然后用ultraEdit打开&#xff0c;切换到16机制模式即可

android unzip file,Unzip File in Android Assets

可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效&#xff0c;请关闭广告屏蔽插件后再试):问题:I put a zip file in the android assets. How do i extract the file in the android internal storage? I know how to get the file, but i dont know how t…

Eclipse安装ADT失败解决办法

Eclipse的版本是3.5.2&#xff0c;配置Android的开发环境时遇到问题…… 按照Android官方文档一步步安装&#xff0c;到了安装Eclipse的ADT插件时&#xff0c;提示“requires org.eclipse.gef 0.0.0 but it could not be found” 缺少GEF&#xff0c;Eclipses Graphic Editing …

DM3730 LCD控制器驱动框架

一般来说&#xff0c;linux的LCD控制器驱动是分两个层次 1) fbmem.c 一个linux内核通用的LCD控制器层&#xff0c;没有任何硬件信息&#xff0c;而且不创建设备文件。 它提供的最重要的接口函数是register_framebuffer 2) 特定芯片的LCD控制器硬件驱动代码&#xff0c;他来调…

html仿qq最小化怎么实现,JS仿QQ好友列表展开、收缩功能(第一篇)

JS仿QQ好友列表展开、收缩功能(第一篇)发布时间&#xff1a;2020-10-17 14:20:03来源&#xff1a;脚本之家阅读&#xff1a;96作者&#xff1a;erdouzhang效果图如下所示&#xff1a;html:我的好友张三李四...企业好友小明小红...黑名单哈哈...css&#xff1a;ul,h3 {padding: …