最近在写一个demo程序,调用select()来监听socket状态,流程如下:

r_set 初始化

timeout 初始化3秒超时

loop{

  select(ntfs, &r_set, null, null, &timeout)

}

然后我惊奇的发现当对端发送消息时select()只会触发一次,当下一次再有消息传递过来的时候不会被触发,后来在网上搜索了一下说是要每一次循环都要初始化一次r_set,就可以完成多次触发了:

timeout 初始化3秒超时

loop{

  r_set 初始化

  select(ntfs, &r_set, null, null, &timeout)

}

同时超时也只有在第一次循环阻塞三秒,之后的循环完全不会阻塞,我打日志调试发现在第一次阻塞超时之后timeout 重置为 0... ...

loop{

  r_set 初始化

  timeout 初始化3秒超时

  select(ntfs, &r_set, null, null, &timeout)

}

这才是正确姿势,但是我在网上看到很多例子并没有重复初始化timeout,难道是我用了假select()?本着实事求是的原则我查看了一下man文档,上面写了这么一句话:

On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this.  (POSIX.1 permits either behavior.)  This  causes  problems  both  when Linux  code which reads timeout is ported to other operating systems, and when code is ported to Linux that reuses a struct timeval for multiple select()s in a loop without reinitializing it. Consider timeout to be undefined after select() returns.

好吧,确实很任性,但作用类似的C library 中的pselect()就不用这么做:

C library/kernel differences
       The pselect() interface described in this page is implemented by glibc.  The underlying Linux system call is named pselect6().  This system call has somewhat different behavior from the glibc
       wrapper function.

       The Linux pselect6() system call modifies its timeout argument.  However, the glibc wrapper function hides this behavior by using a local variable for the timeout argument that is  passed  to
       the system call.  Thus, the glibc pselect() function does not modify its timeout argument; this is the behavior required by POSIX.1-2001.

       The final argument of the pselect6() system call is not a sigset_t * pointer, but is instead a structure of the form:

           struct {
               const sigset_t *ss;     /* Pointer to signal set */
               size_t          ss_len; /* Size (in bytes) of object pointed
                                          to by 'ss' */
           };

       This allows the system call to obtain both a pointer to the signal set and its size, while allowing for the fact that most architectures support a maximum of 6 arguments to a system call

它的意思是,pselect()在传入时间参数的时候会付给一个参数temp,然后把temp传进去,这样就不会修改timeout参数了。

ps:

POSIX表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003,而国际标准名称为ISO/IEC 9945。
POSIX标准意在期望获得源代码级别的软件可移植性。换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。
POSIX 并不局限于 UNIX。许多其它的操作系统,例如 DEC OpenVMS 支持 POSIX 标准,尤其是 IEEE Std. 1003.1-1990(1995 年修订)或 POSIX.1,POSIX.1 提供了源代码级别的 C 语言应用编程接口(API)给操作系统的服务程序,例如读写文件。POSIX.1 已经被国际标准化组织(International Standards Organization,ISO)所接受,被命名为 ISO/IEC 9945-1:1990 标准。
 
最后,还有一点,在select监听的socket,在其他线程被close()掉,select是不会收到消息的:
Multithreaded applications
       If a file descriptor being monitored by select() is closed in another thread, the result is unspecified.  On some UNIX systems, select() unblocks and returns, with an indication that the file
       descriptor  is ready (a subsequent I/O operation will likely fail with an error, unless another the file descriptor reopened between the time select() returned and the I/O operations was per‐
       formed).  On Linux (and some other systems), closing the file descriptor in another thread has no effect on select().  In summary, any application that relies on a particular behavior in this
       scenario must be considered buggy.

Linux Select之坑的更多相关文章

  1. linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例

    除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnblogs.com/Anker/p/3265058.html 最简单的select示例: #incl ...

  2. linux—select具体解释

    linux—select具体解释 select系统调用时用来让我们的程序监视多个文件句柄的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变. 关于文件句柄,事 ...

  3. linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例【转】

    转自:https://www.cnblogs.com/welhzh/p/4950341.html 除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnb ...

  4. linux select函数详解

    linux select函数详解 在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核: •我们所关心的文件描述符 •对每个描述符,我们所关心的状 ...

  5. Linux select 机制深入分析

    Linux select 机制深入分析            作为IO复用的实现方式.select是提高了抽象和batch处理的级别,不是传统方式那样堵塞在真正IO读写的系统调用上.而是堵塞在sele ...

  6. Linux select TCP并发服务器与客户端编程

    介绍:运行在ubuntu linux系统,需要先打开一个终端运行服务端代码,这时,可以打开多个终端同时运行多个客户端代码(注意客户端数目要小于MAX_FD);在客户端输入数据后回车,可以看见服务器收到 ...

  7. Linux select I/O 复用

    用途 在处理多个socket套接字的时候,会很自然的遇到一个问题:某个套接字什么时候可读?什么时候可写?哪些套接字是需要关闭的?我们可以回忆一下,一般我们在最开始编写socket程序的时候,send, ...

  8. Linux使用踩坑记

    Ubuntu安装坑: 1.对于新手第一次安装ubuntu,特殊情况会出现因为分辨率问题导致安装界面不全,无法进行下一步操作. 解决方案:使用alt+鼠标左键拖动屏幕Linux文件名乱码问题: 2.因为 ...

  9. 从U盘安装linux(前人踩坑后人乘凉)

    今天踩了一个大坑,网上的教程从u盘安装linux少了一个关键步骤导致我挣扎了两个小时 废话不多说,开始需要准备一些东西 1.从官网下载一个Ubuntu 10.04的镜像 2.一个大于等于1G的支持启动 ...

随机推荐

  1. Python爬虫(二十一)_Selenium与PhantomJS

    本章将介绍使用Selenium和PhantomJS两种工具用来加载动态数据,更多内容请参考:Python学习指南 Selenium Selenium是一个Web的自动化测试工具,最初是为网站自动化测试 ...

  2. SSI学习(二)

    1.SSI指令 #config:指定返回到client浏览器的错误消息.日期和文件大小所使用的格式. #echo:在 HTML 页中插入环境变量的值. #exec:执行一个应用程序或一条 shell ...

  3. BZOJ 1032 JSOI2007 祖码Zuma 动态规划

    题目大意:给定一个祖玛序列,任选颜色射♂出珠子,问最少射♂出多少珠子 输入法近期越来越奇怪了0.0 首先我们把连续同样的珠子都缩在一起 令f[i][j]表示从i開始的j个珠子的最小消除次数 初值 f[ ...

  4. Centos 7 安装 PostgreSQL

    本文只讲PostgreSQL在CentOS 7.x 下的安装,其他系统请查看:https://www.postgresql.org/download PostgreSQL 所用版本为:PostgreS ...

  5. scrapy爬虫框架setting模块解析

    平时写爬虫的时候并不需要设置setting里所有的参数,今天心血来潮,花了点时间查了一下setting模块创建后自动写入的所有参数的含义,记录一下. 模块相关说明信息 # -*- coding: ut ...

  6. .net core系列之初识asp.net core

    .net core已经发布了2.0版本,相对于1.0的有了很大的完善,最近准备在项目中尝试使用asp.net core,所以就进行了一些简单的研究. 初识asp.net core分为以下几个部分: 1 ...

  7. 【HTML】HTML基础知识

    <!DOCTYPE html>表示HTML5文档申明,不区别大小写,通常这么写. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 ...

  8. Python 集体智慧编程PDF

    集体智慧编程PDF 1.图书思维导图http://www.pythoner.com/183.html p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12. ...

  9. Fiori缓存与它的清除

    最近在修改已有的Fiori应用,遇到了缓存上的一点问题,导致对Fiori应用的代码修改不能在前端页面生效.现将自己查到的一篇好资料翻译过来,以供参考.以下为正文. 2017.12.19更新:最近又遇到 ...

  10. CDH的安装

    环境5台装有centos 6.9系统的服务器 1.网络配置 sudo vi /etc/sysconfig/network修改hostname: NETWORKING=yes HOSTNAME=ZXXS ...