Linux下socket多路复用应用--select函数

2023-11-04

Linux下socket多路复用应用--select函数

Select系统调用是用来让我们的程序监视多个文件描述符(file descriptor)的状态变化的。程序会停在select这里等待,直到被监视的文件描述符有某一个或多个发生了状态改变。

文件描述符在Linux里有很多,如果你man某个函数,在函数返回值部分说到成功后有一个文件描述符被创建,如man socket可以看到“On success,a file descriptor for the new socket is returned.”而man 2 open可以看到“open() and create() return the new file descriptor”,其实文件描述符就是一个整数,看socket函数的声明就明白了:

Int socket(int domain, int type,int protocol);

 

 

当然,我们最熟悉的文件描述符是0,1,2三个,0是标准输入,1是标准输出,2是标准错误输出。0、1、2是整数表示的,对应的FILE*结构的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。

select()的机制中提供一种fd_set的数据结构,实际上是一个long类型的数组,每一个数组元素都能与一个打开的文件描述符(不管是socket,还是其他文件或命名管道或设备描述符)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select的进程哪一个socket或文件可读。

非阻塞式I/O编程有两个特点:

1.如果一个发现I/O有输入,读取的过程中,另外一个也有了输入,这时候不会产生任何反应。这就需要你的程序语句去用到select函数的时候才知道有数据输入。

2.程序调用select的时候,如果没有数据输入,程序会一直等待,直到有数据为止,也就是程序中无需循环和sleep。

select在socket编程中还是比较重要的,可是对于初学socket的人来说都不太爱用select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓非阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果某个事件没有发生,进程或线程就被阻塞,函数不能立即返回)。

可是使用select就可以完成非阻塞(所谓非阻塞方式non_block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映此函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生,则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况--读写或是异常。

 

Select函数介绍

函数名:select

头文件:#include<sys/types.h>

#include<syss/times.h>

#include<sys/select.h>

函数原型:int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout);

函数功能:检测文件状态变化

参数说明:1.ndfs:select监视的文件描述符数,视进程中打开文的文件数而定,一般设定为你要监视各文件中最大文件号加一。

          2.readfds:select监视的可读文件描述符集合。

  3.writefds:select监视的可写文件描述符集合。

  4.exceptfds:select监视的异常文件描述符集合。

  5.timeout:本次select()的超时结束时间。(见/usr/sys/select.h)

  struct timeval

  {

long tv_sec; //秒

long tv_unsec; //微秒

  };(可精确至百万分之一秒)

函数返回值:成功时,返回准备就绪的描述符数,若超时则返回0,失败则返回-1。

 

我们在程序中药申明几个fd_set类型的变量,比如rdfds,wtfds,exfds,然后把这个变量的地址&rdfds,&wtfds,&exfds传递给select函数。这三个参数都是一个描述符的集合,第一个rdfds是用来保存这样的描述符的:当描述符的状态变成可读的时系统就会告诉select函数返回,同理第二个wtfds是指有描述符状态变成可写是系统就会告诉select函数返回,同理第三个参数exfds是特殊情况,即描述符有特殊情况发生时系统就会告诉select函数返回。对socket编程有用的就是readfds。

几个相关的宏解释如下:

FD_ZERO(fd_set* fdset):清空fdset与所有文件描述符的联系。

FD_SET(int fd,fd_set* fdset):建立文件描述符fd与fdset的联系。

FD_CLR(int fd,fd_set* fdset):清除文件描述符fd和fdset的联系。

FD_ISSET(int fd,fd_set* fdset):检查fdset联系的文件描述符fd是否可读写,当>0表示可读写。

(关于fd_set及相关宏的定义见/usr/include/sys/types.h)。

特殊情况比如对方通过一个socket描述符发来了紧急数据。如果我们程序里只是想检测某个socket是否有数据可读,我们可以这样:

 

fd_set rdfds; //先声明一个fd_set集合来保护我们要检测的socket描述符

struct timeval tv; //声明一个时间变量来保存时间

int ret; //保存返回值

FD_ZERO(&rdfds); //用select函数之前先把集合清零

FD_SET(socket,&fdfds); //把要检测的描述符socket加入到集合里

tv.tv_sec = 1;

tv.tv_usec = 500; //设置select等待的最大时间为1秒加500毫秒

ret = select(socket+1,&rdfds,NULL,NULL,&tv); //检测我们上面设置到集合rdfds里的描述符是否有可读信息

If(ret < 0 )perror(“select”); //这说明select函数出错

else if(ret == 0)printf(“超时\n”); //说明在我们设定的时间值1秒加500毫秒内,socket的状态没有发生变化

else //说明等待时间内,socket的状态发生了变化

{

printf(“ret = %d\n”,ret); //ret这个返回值记录了发生状态变化的描述符的数目,由于这里我们只监视了socket这一个描述符,所以这里一定ret == 1,如果同时有多个描述符发生变化返回的就是描述符的总和了

//这里我们就可以从socket这个描述符里读取数据了,因为select函数已经告诉我们这个描述符里有数据可读

if(FD_ISSET(socket,&rdfds)) //先判断一下socket这被监视的描述符是否真的变成可读的了

{

recv() ;  //读取socket描述符里的数据

}

}

 

注意:select函数的第一个参数,是所有加入集合的描述符值得最大那个值还要加1。比如我们创建了3个描述符:

int sa,sb,sc;

sa = socket(...);

connect(sa,...);

sb = socket(...);

connect(sb,...);

sc = socket(...);

connect(sc,...);

FD_SET(sa,&rdfds);

FD_SET(sb,&rdfds);

FD_SET(sc,&rdfds);

在使用select函数之前,一定要找到3个描述符的最大值,我们一般定义一个变量来保存最大值,取得最大socket值,算法就不用说了吧,求三个数的最大值就OK了。定义最大值变量int maxfd = 0;

。。。

ret = select(maxfd+1,&rdfds,NULL,NULL,&tv);

同样的道理,如果我们要检测用户是否按了键盘进行输入,我们就应该把标准输入0这个描述符放到select里来检测,如下:

FD_ZERO(&rdfds);

FD_SET(0,&rdfds);

tv.tv_sec = 1;

tv.tv_usec = 0;

ret = select(1,&rdfds,NULL,NULL,&tv); //注意最大值还要加1

if(ret < 0)

perror(“select”);

else if(ret == 0)

printf(“超时\n”);

else

scanf(“%s”,buf);

 

Ok,用法已经讲的很明白了吧,接下来就是select的具体应用了,如果有兴趣的到时候可以看一下我的“TCP套接字编程实例(三)”,里面讲了利用select和TCP套接字实现异步通讯聊天。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下socket多路复用应用--select函数 的相关文章

  • 在 PHP 中对逗号分隔值列表运行选择

    我在数据库上运行选择查询时遇到一些问题 一些数据以逗号分隔值的列表形式保存 例如 Table example tbl Id People Children 1 1 2 3 8 10 3 2 7 6 12 18 19 2 我正在尝试运行的示例
  • 将多个值插入隐藏字段

    我有一个选择列表 您可以在其中选择多个城市 选择城市时 我想将邮政编码添加到隐藏字段 我现在的解决方案将值插入到隐藏字段 但是 当 fx 时它会覆盖该值 单击一个新城市 它应该只附加到值中 例如 value value1 value2 va
  • 将 SELECT DISTINCT ON 查询从 Postgresql 转换为 MySQL

    我一直在使用PostgreSQL现在迁移到MySQL 在我的查询中 我正在使用PostgreSQL s SELECT DISTINCT ON col1 col2 col3 我想知道这句话是否有对应的内容MySQL 没有完全等效的方法可以将使
  • 如何在选择查询中创建新列

    在 MS Access 中 我想将新列插入到选择查询的返回结果中 新列的每一行都具有相同的值 例如 我的选择返回列 A B 我希望 C 成为选择查询创建的新列 A B C a1 b1 c a2 b2 c a3 b3 c select A B
  • jQuery - 选择选择框中的选项[重复]

    这个问题在这里已经有答案了 可能的重复 jQuery 以编程方式选择选择框中的选项 https stackoverflow com questions 1573930 jquery programmatically select an op
  • 为什么 peewee 将“id”列包含到 mysql select 查询中?

    我正在尝试学习如何将 peewee 与 mysql 一起使用 我在 mysql 服务器上有一个现有数据库和一个现有表 该表当前为空 我现在正在测试 gt gt gt db MySQLDatabase nhl user root passwd
  • jQuery - 选择同一级别的div

    我想在单击按钮时选择一个特定的div 唯一的问题是 它必须是buttonClicked的父div的div 示例 div class container div class box h2 Langtidsparkering h2 div cl
  • PostgreSQL 选择结果大小

    我在 PostgreSQL 数据库中有一个表 并从该表中进行一些限制的选择 并且我想知道该选择有多少磁盘空间 我知道有一个postgres函数pg total relation size这给了我数据库中某个表的大小 但是如何找到 子表 的大
  • 如何使用 xslt 选择节点的祖父母

    我所处的情况是 我只能测试子节点 但我必须将标签应用于该子节点的祖节点 我尝试过使用
  • jQuery:如何仅根据表标题从表的列中选择值

    我有一个带有标题 ID 的表 我需要选择此标题下的所有字段 我无权访问源代码 并且该表中没有使用任何类 关于如何完成这件事有什么想法吗 要获取第一列 function var col td nth child 1
  • 选择前 n 个字符相等的行(MySQL)

    我有一张带有玩家句柄的桌子 如下所示 1 N Laka 2 N James 3 nor Brian 4 nor John 5 Player 2 6 Spectator 7 N Joe 从那里我想选择第一个 n 字符匹配的所有玩家 但我不知道
  • MySQL - 选择一行 - 然后相对于所选行的下一个和上一个

    我会尽力澄清这一点 我需要在不使用 id 的情况下选择特定行和该选定行的前一个相对行以及该选定行的下一个相对行 这可能吗 简而言之 上一篇和下一篇 我不能 也许我只是不知道如何 使用 id 的原因是因为它们不是按顺序排列的 正如您从这个相当
  • 针对约 225 万行的单表选择查询的优化技术?

    我有一个在 InnoDB 引擎上运行的 MySQL 表 名为squares大约有 2 250 000 行 表结构如下 squares square id int 7 unsigned NOT NULL ref coord lat doubl
  • 如何使用 MySQL 选择有特定值的 2 个连续行?

    我正在构建一个系统 该系统应该显示学生何时连续缺席两天 例如 此表包含缺勤情况 day id missed 2016 10 6 1 true 2016 10 6 2 true 2016 10 6 3 false 2016 10 7 1 tr
  • AngularJS - 设置下拉列表的选定值不起作用

    我在这里复制了我的问题 http jsfiddle net U3pVM 2840 http jsfiddle net U3pVM 2840 正如标题所示 我无法设置使用 ng options 填充的选择的选定值 我已经搜索并尝试了我找到的所
  • MySQL SELECT OpenCarts 数据库中的重复行

    只是玩一下 OpenCart DB 看看我是否能学到一些东西 如果我使用以下SELECT结果返回重复的行 SELECT DISTINCT p product id AS pid p model AS modelo SUBSTRING p m
  • MySQL select with 语句

    我正在学习更多 SQL 并遇到了一个 问题 我有两个表 如下面的链接http www sqlfiddle com 2 403d4 1 http www sqlfiddle com 2 403d4 1 编辑 由于我这个周末所做的所有 SQL
  • 直接从表中选择和视图之间的区别

    直接从表中选择数据或从视图中选择数据有什么区别 每一种的最佳用途是什么 根据微软的说法 如果你使用的话会有性能优势indexedSQL Server 2000 2005 2008 中的视图 索引视图可以通过以下方式提高查询性能1 可以预先计
  • 查看oracle中重复行的所有数据

    我有一个有 6 列的表 id name type id code lat long 前三个是必需的 ID是私钥 按序列自动插入 我有一些重复的行 正如两者所定义的name and type id是平等的 但我想查看受骗者的所有数据 我可以很
  • jQuery UI 1.8.17 和 selectmenu

    这个问题的答案可能会让我 doh 时刻 但是我在哪里可以找到一个可与较晚 ish jquery ui 版本一起使用的有效 selectmenu 插件 我从所有这些地方尝试过 但似乎都不起作用 http www filamentgroup c

随机推荐

  • java特殊时间批量转化

    1 spring中添加配置 1 yml文件 spring jackson date format yyyy MM dd HH mm ss time zone GMT 8 serialization 格式化输出 indent output t
  • STM32F103ZET6【标准库函数开发】---04.1 五个串口的时钟以及重映射应该如何配置

    一 硬件介绍 正点原子战舰开发板 STM32F103ZET6有5个串口 USART1 USART2 USART3 UART4 UART5 模式总览 引脚位置 二 引脚功能 打开STM32F103ZET6数据手册IO介绍可以看到IO口功能有三
  • 百万前端之js倒计时功能

    js实现倒计时的方法很简单 基本的方法就是倒计时的结束时间减当前时间就是倒计时的时间了 通过js的内置函数获取时间并对时间进行处理 最后进行拼接插入就实现简单的倒计时功能了 demo的css参考 body position relative
  • DP--线性DP--【整理】【经典入门例题】

    每种类型仅有一个经典的例题 复习一下之前的知识 在学习新知识 不过会推荐一些博客 虽然我也没看过 只是挑一个经典题看看 1 最长上升子序列 LIS问题 大佬博客 最长上升子序列题目大合集 问题描述 给定一个长度n的数列A 求单调递增的子序列
  • 通达信交易系统接口实现自动交易策略的方法分享

    在通达信交易系统接口中 有着比较独特的交易系统 在这个交易系统中 也有各种各样的自动交易策略 可以通过交易接口来实现预先设定好的策略来进行自动交易 从而提高交易者的投资效率 下面向大家介绍其中几种自动交易策略 追踪卖出算法 追踪卖出算法说明
  • 使用pcl库处理点云数据,如何给点云的指定字段赋值?

    1 不同字段的两个点云之间存在相同字段时 如何给对应的相同字段赋值 pcl PointCloud
  • c语言编写经验逐步积累3

    寥寥数笔 记录我的C语言盲点笔记 只为曾经经历过 亦有误 可交流 1 typedef来定义一个函数指针类型的方法 定义一个新的函数指针类型 建立一个类型别名的方法很简单 在传统的变量声明表达式里用类型名替代变量名 然后把关键字typedef
  • 代码重构技巧之重复代码

    在我们项目开发的过程中 有时写着写着顺手了 对于一些业务代码 重复编写 导致后来需要修改的时候 得整个项目到处找这些重复代码 这真是一件糟糕的事 一 重复代码 定义 重复代码并不是指的完全一模一样的代码 只要在一段代码 业务处理上 有相识之
  • Maven 学习笔记二十一:Maven仓库(快照版本)

    Maven仓库 快照版本 在Maven的世界中 任何一个项目或者构件都必须有自己的版本 版本的值可能是1 0 0 1 3 alpha 4 2 0 2 1 SNAPSHOT或者2 1 20091214 221414 13 其中 1 0 1 3
  • Cef 模式下,Vue @click 事件偶尔无效问题

    Cef 模式下 Vue 项目 click 事件偶尔无效问题 Cef 模式 使用 C 创建的一个浏览器 有它自己的浏览器内核版本 在 Cef Web 壳子中开发时候 发现 Vue 项目 的 click 偶尔就无效 一开始还以为电脑卡了 具体分
  • 华为OD机试真题 Java 实现【非严格递增连续数字序列】【2022Q4 100分】

    一 题目描述 输入一个字符串仅包含大小写字母和数字 求字符串中包含的最长的非严格递增连续数字序列的长度 比如122889属于非严格递增连续数字序列 二 输入描述 输入一个字符串仅包含大小写字母和数字 输入的字符串最大不超过255个字符 三
  • Linux_4 消息队列

    1 基础概念 消息队列 Unix的通信机制之一 可以理解为是一个存放消息 数据 容器 将消息写入消息队列 然后再从消息队列中取消息 一般来说是先进先出的顺序 消息队列本质上是位于内核空间的链表 链表的每个节点都是一条消息 每一条消息都有自己
  • 多图预警!Ubuntu18.04全套安装流程

    1 Ubuntu系统下载 Ubuntu18 04LTS下载地址 点击跳转 对于软件开发人员 建议下载Ubuntu18 04LTS 支持相对较多较稳定 2 下载软碟通软件 UltraISO UltralISO下载链接 点击跳转 3 安装使用
  • 三目运算符判断多个条件的使用方法

    写项目的时候数据状态有三种 给三种不同的样式 然后发现可以简单地使用三目运算符 就可以实现多个条件的判断 span scope row status span 也就是这个用法 key 1 第一种 key 2 第二种 key 3 第三种 第四
  • 总结一下query中ajax的几种方法

    1 ajax ajax type POST 提交数据的类型 POST GET url testLogin aspx 提交的网址 提交的数据 data Name sanmao Password sanmaoword 返回数据的格式 datat
  • opencv-python帧差法

    代码如下 import cv2 import numpy as np cap cv2 VideoCapture E chinese ocr master xinwen 3 avi Check if camera opened success
  • 第11课 微信小程序多种弹窗提示样式

    第11课 微信小程序弹窗提示样式 消息提示 wx showToast Object object 关闭消息提示 wx hideToast Object object 弹窗选框提示 wx showModal Object object 加载提
  • 2017阿里笔试 用模板库中的vector解决笔试中的兔子繁殖问题

    问题介绍 1 猎人把一对兔子婴儿 一公一母称为一对 放到一个荒岛上 两年之后 它们生下一对小兔 之后开始每年都 会生下一对小兔 生下的小兔又会以同样的方式继续繁殖 2 兔子的寿命都是x x gt 3 年 并且生命的最后一年不繁殖 3 如果岛
  • R语言学习笔记:从零开始?数据结构和基础知识

    R语言是一种数学编程语言 主要用于统计分析 绘图 数据挖掘 其在生物信息大数据分析处理过程中扮演着重要角色 笔者从今天开始分享R语言学习笔记 环境安装 Windows 官方地址 https cloud r project org bin w
  • Linux下socket多路复用应用--select函数

    Linux下socket多路复用应用 select函数 Select系统调用是用来让我们的程序监视多个文件描述符 file descriptor 的状态变化的 程序会停在select这里等待 直到被监视的文件描述符有某一个或多个发生了状态改