IO复用之select

目录

一.select方法介绍

2.1 select 系统调用的原型

2.2 集合的数据结构

2.2.1 fd_set 结构如下:

2.2.2 关于集合fd_set的解析

2.3 select第一个参数

2.4 select方法之超时时间timeout

2.5 select方法的用法简述及返回值

2.6 如何检测集合中有哪些描述符有事件就绪

三.select应用

3.1 select小实例

 3.2 结合tcp编程


一.select方法介绍

select 系统调用的用途是:在一段指定时间内,监听用户感兴趣的文件描述符的可读、可写和异常等事件。

2.1 select 系统调用的原型

select 成功时返回就绪(可读、可写和异常)文件描述符的总数。如果在超时时间内没有任何文件描述符就绪,select将返回 0。select 失败是返回-1.如果在 select 等待期间,程序接收到信号,则select 立即返回-1,并设置errno 为EINTR。

#include <sys/select.h>
int select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • maxfd 参数指定的被监听的文件描述符的总数。它通常被设置为 select 监听的所有文件描述符中的最大值+1。
  • readfds、 writefds 和 exceptfds 参数分别指向可读、可写和异常等事件对应的文件描述符集合。应用程序调用 select 函数时,通过这 3 个参数传入自己感兴趣的文件描述符。
  • select 返回时,内核将修改它们来通知应用程序哪些文件描述符已经就绪

2.2 集合的数据结构

select如何通知应用程序有哪些描述符数据就绪了,用户又是如何将这些描述符添加到select这个集合中?具体看下面关于集合fd_set的解析;

2.2.1 fd_set 结构如下:

#define __FD_SETSIZE 1024
typedef long int fd_mask;
#define __NFDBITS(8*(int)sizeof(__fd_mask))typedef struct
{#ifdef __USE_XOPEN__fd_mask fds_bits[__FD_SETSIZE/__NFDBITS];//这是一个数组,依次是数组类型 数组名[数组个数]# define __FDS_BITS(set)((set)->fds_bits)#else__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];# define __FDS_BITS(set)((set)->__fds_bits)#endif
}fd_set;

2.2.2 关于集合fd_set的解析

select如何通知应用程序有哪些描述符数据就绪了,用户又是如何将这些描述符添加到select这个集合中?我们首先来看关于集合fd_set的解析 :

也就是说这个结构体fd_set实际定义了1024个位。

通过下列宏可以访问 fd_set 结构中的位:

FD_ZERO(fd_set *fdset);// 清除 fdset 的所有位,就是将所有的位都置为0;FD_SET(int fd,fd_set *fdset);// 设置 fdset 的位 fd,就是将某个描述符对应的位设置为1,就是将某个描述符添加到这个集合中;FD_CLR(int fd,fd_set *fdset);// 清除 fdset 的位 fd,就是将某个位清零;int FD_ISSET(int fd,fd_set *fdset);// 测试 fdset 的位 fd 是否被设置,其实就是测试某个描述符对应的位是不是1,如果被设置为1返回值为真,否则返回值为假; 

2.3 select第一个参数

select第一个参数通常被设置为描述符的最大值+1

也就是说书上maxfd是描述符的总数目,其实应该理解为描述符的最大值+1;也就是需要关注的位的总数目,比如上面的例子是8;

2.4 select方法之超时时间timeout

timeout 参数用来设置 select 函数的超时时间。它是一个 timeval 结构类型的指针,采用指针参数是因为内核将修改它以告诉应用程序 select 等待了多久。

timeval结构的定义如下:

struct timeval
{long tv_sec;//秒数long tv_usec;// 微秒数
};

也就是我们能够精确到微秒,实际上它还要看系统能不能达到;

1秒=1000毫秒,1毫秒=1000微秒

如果给 timeout 的两个成员都是 0,则 select 将立即返回。如果 timeout 传递NULL,则 select 将一直阻塞,直到某个文件描述符就绪 

2.5 select方法的用法简述及返回值

我们先将描述符添加到集合中,将集合传参给select,select返回以后我们就要关注它的返回值;

返回值如果等于0,就说明超时了:

如果返回值为n,n>0,那么就说明这个集合中有n(n>0)个描述符有事件就绪;

如果返回值为-1,说明出错了;

2.6 如何检测集合中有哪些描述符有事件就绪

三.select应用

3.1 select小实例

select检查键盘是否有数据

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>#define STDIN 0
int main()
{int fd=STDIN;fd_set fdset;while(1){FD_ZERO(&fdset);FD_SET(fd,&fdset);struct timeval tv={5,0};int n=select(fd+1,&fdset,NULL,NULL,&tv);if(n==-1){printf("select error!\n");continue;}else if(n==0){printf("time out!\n");continue;}else{if(FD_ISSET(fd,&fdset)){char buff[128]={0};read(fd,buff,127);printf("read:%s\n",buff);}}}
}

 3.2 实现select的tcp服务器端

 #include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <assert.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <fcntl.h>#include <sys/select.h>#include <sys/time.h>#define MAXFD 100int create_socket(){int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));if(res==-1){return -1;}res=listen(sockfd,5);if(res==-1){return -1;}return sockfd;}void fds_init(int fds[]){for(int i=0;i<MAXFD;i++){fds[i]=-1;}}void fds_add(int fds[],int fd){for(int i=0;i<MAXFD;i++){if(fds[i]==-1){fds[i]=fd;break;}}}void fds_del(int fds[],int fd){for(int i=0;i<MAXFD;i++){if(fds[i]==fd){fds[i]=-1;break;}}}int main(){int sockfd=create_socket();assert(sockfd!=-1);int fds[MAXFD];fds_init(fds);fds_add(fds,sockfd);fd_set fdset;while(1){FD_ZERO(&fdset);int maxfd=-1;for(int i=0;i<MAXFD;i++){if(fds[i]!=-1){FD_SET(fds[i],&fdset);if(maxfd<fds[i]){maxfd=fds[i];}}}struct timeval tv={5,0};int n=select(maxfd+1,&fdset,NULL,NULL,&tv);if(n==-1){printf("select error!\n");continue;}else if(n==0){printf("time out!\n");continue;}else{for(int i=0;i<MAXFD;i++){if(fds[i]==-1){continue;}if(FD_ISSET(fds[i],&fdset)){if(fds[i]==sockfd){//accept;struct sockaddr_in caddr;int len=sizeof(caddr);int c=accept(sockfd,(struct sockaddr*)&caddr,&len);if(c==-1){continue;}printf("accept c=%d\n",c);fds_add(fds,c);}else{//recvchar buff[128]={0};int res=recv(fds[i],buff,127,0);if(res<=0){close(fds[i]);fds_del(fds,fds[i]);printf("one client over!\n");}else{printf("buff(c=%d)=%s\n",fds[i],buff);send(fds[i],"ok",2,0);}}}}}}exit(0);}

封装函数版(跟上面的代码作用是一样的) 

//select_ser.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>#define MAX_FD  128
#define DATALEN 1024//初始化服务器端的sockfd套接字
int InitSocket()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));if(res==-1){return -1;}res=listen(sockfd,5);if(res==-1){return -1;}return sockfd;  
}//初始化记录服务器套接字的数组
void InitFds(int fds[],int n)
{int i=0;for(;i<n;++i){fds[i]=-1;}
}//将套接字描述符添加到数组中
void AddFdToFds(int fds[],int fd,int n)
{int i=0;for(;i<n;++i){if(fds[i]==-1){fds[i]=fd;break;}}
}//删除数组中的套接字描述符
void DelFdFromFds(int fds[],int fd,int n)
{int i=0;for(;i<n;++i){if(fds[i]==fd){fds[i]=-1;break;}}
}//将数组中的套接字描述符设置到fd_set变量中,并返回当前最大的文件描述符值
int SetFdToFdset(fd_set *fdset,int fds[],int n)
{FD_ZERO(fdset);int i=0,maxfd=fds[0];for(;i<n;++i){if(fds[i]!=-1){FD_SET(fds[i],fdset);if(fds[i]>maxfd){maxfd=fds[i];}}}return maxfd;
}void GetClientLink(int sockfd,int fds[],int n)
{struct sockaddr_in caddr;memset(&caddr,0,sizeof(caddr));socklen_t len=sizeof(caddr);int c=accept(sockfd,(struct sockaddr *)&caddr,&len);if(c<0){return ;}printf("A client connection was successful\n");AddFdToFds(fds,c,n);//新的链接套接字c添加进去集合中
}//处理客户端数据
void DealClientData(int fds[],int n,int clifd)
{char data[DATALEN]={0};int num=recv(clifd,data,DATALEN-1,0);if(num<=0){DelFdFromFds(fds,clifd,n);close(clifd);printf("A client disconnected\n");}else{printf("%d:%s\n",clifd,data);send(clifd,"Ok",2,0);}
}//处理select返回的就绪事件
void DealReadyEvent(int fds[],int n,fd_set*fdset,int sockfd)
{int i=0;for(;i<n;++i){if(fds[i]!=-1&& FD_ISSET(fds[i],fdset)){if(fds[i]==sockfd){GetClientLink(sockfd,fds,n);}else{DealClientData(fds,n,fds[i]);}}}
}int main()
{int sockfd=InitSocket();assert(sockfd!=-1);fd_set readfds;int fds[MAX_FD];InitFds(fds,MAX_FD);AddFdToFds(fds,sockfd,MAX_FD);while(1){int maxfd=SetFdToFdset(&readfds,fds,MAX_FD);struct timeval timeout;timeout.tv_sec=5;//秒数timeout.tv_usec=0;//微秒int n=select(maxfd+1,&readfds,NULL,NULL,&timeout);if(n<0){printf("select error\n");break;}else if(n==0){printf("time  out\n");continue;}DealReadyEvent(fds,MAX_FD,&readfds,sockfd);}exit(0);}

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

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

相关文章

【建议收藏】大气颗粒物与VOCs PMF源解析

查看原文>>>最新大气颗粒物与VOCs PMF源解析实践技术应用 目前&#xff0c;大气颗粒物和臭氧污染成为我国亟待解决的环境问题。颗粒物和臭氧污染不仅对气候和环境有重要影响&#xff0c;而且对人体健康有严重损害。而臭氧的前体物之一为挥发性有机物&#xff08;VOCs&…

Orange3数据预处理(离散化组件)

离散化&#xff1a;将数值属性转换为分类属性。 输出 数据&#xff1a;具有离散化值的数据集 设置离散化的默认方法。 选择变量以为每个变量设置特定的离散化方法。将鼠标悬停在变量上显示区间。 离散化方法Keep numeric(保持数值)&#xff1a;保持变量不变。Remove (移除)&a…

罐头鱼AI短视频矩阵获客|AI视频批量生成

罐头鱼AI传单功能操作说明&#xff0c;智能化提升您的视频营销效率&#xff01; 在这个信息爆炸的时代&#xff0c;短视频已成为企业营销的重要方式之一。而为了更高效地进行视频营销&#xff0c;罐头鱼AI传单功能应运而生&#xff0c;为您提供全方位的视频管理和发布服务。 首…

【最全最详细】微信第三方平台开发 —— 接收公众号事件/消息

文章目录 1. 整体流程2. 成为服务商2.1. 首先打开微信开放平台&#xff0c;注册并登录你的账号2.2. 进行开发者资质认证2.3. 创建第三方平台并提交审核 3. 搭建第三方平台后端服务3.1. 管理员设置 和 权限集设置3.2. 开发资料设置3.3. 进行商家授权操作3.3.0. 加密解密操作3.3.…

新零售SaaS架构:什么是线上商城系统?

零售商家为什么要建设线上商城 传统的实体门店服务范围有限&#xff0c;只能吸引周边500米内的消费者。因此&#xff0c;如何拓展服务范围&#xff0c;吸引更多消费者到店&#xff0c;成为了店家迫切需要解决的问题。 缺乏忠实顾客&#xff0c;客户基础不稳&#xff0c;往往是…

IEEE802.11v协议介绍

IEEE802.11v协议简介 协议全称:无线网络管理(Wireless Network Management) 批准日期:2011年2月 协议状态:并入802.11-2012 协议别名:BSS过渡管理 主要功能 支持AP和STA间交换:关于RF环境和拓扑状态的信息,以协助STA进行漫游决策支持STA之间交换:关于RF环境状态的信…

【Python】random库

专栏文章索引&#xff1a;Python 原文章&#xff1a;Python中random函数用法整理_python random-CSDN博客 目录 1.random.random() 2.random.uniform(a, b) 3.random.randint(a, b) 4.random.randrange([start], stop[, step]) 5. random.choice() 6. random.shuffle(x[,…

四川尚熠电子商务有限公司领航抖音电商新纪元

随着互联网的飞速发展&#xff0c;电子商务已经成为现代商业的重要组成部分。在这个变革的时代&#xff0c;四川尚熠电子商务有限公司凭借其敏锐的市场洞察力和创新精神&#xff0c;专注于抖音电商服务&#xff0c;为广大品牌商家提供了一站式的电商解决方案&#xff0c;成为行…

从菜鸟到大师!年薪20W的c++ QT开发工程师需要懂哪些技术?

如今Qt的知识也变得非常广泛和复杂&#xff0c;学习起来同样具有一定的挑战。对于Qt从业者来说&#xff0c;有两个主要层面&#xff1a;一个是深入理解Qt框架和基础知识&#xff0c;另一个是具备丰富的工程经验。 还不熟悉的朋友&#xff0c;这里可以先领取一份Qt开发必备技术…

基于 onsemi 汽车前置大灯设计之 PCB 设计注意事项

一、 基本介绍 Blitz Fly 方案是世平集团推出的基于 onsemi NCV7802 & NCV78723 的汽车前置大灯方案。该方案针对汽车前照灯设计&#xff0c;主要分为四个部分&#xff1a; 1. LED 驱动&#xff1a; 以 onsemi NCV78702 以及 onsemi NCV78723 为核心。NCV78702 是一款用于…

查询IPv4归属地信息的几种方式

查询IPv4归属地信息是一个在网络管理和安全领域常见的需求。IPv4地址是互联网协议第四版中定义的网络层地址&#xff0c;它允许计算机和网络设备在全球范围内进行通信。而查询IPv4归属地信息&#xff0c;即是指确定该IPv4地址所在的地理位置或注册的网络服务提供商&#xff0c;…

【HTML】1px边框与1px分割线

对比图 箭头标注的是处理过的 1px分割线 使用transform的scaleY进行缩小 码 <div class"mini-heriz"></div><br><div style"border: solid 1px black; width: 300px;height: 1px;"></div> <style> .mini-heriz {wi…

操作系统:进程控制(上)

目录 1.进程创建 1.1.fork()函数 1.2.写时拷贝 2.进程终止 2.1.进程的退出场景 2.1.1.退出码和错误码&#xff08;正常终止&&任务失败&#xff09; 2.1.2.异常终止 1.进程创建 1.1.fork()函数 在linux中&#xff0c;fork函数时非常重要的函数&#xff0c;它从已…

力扣爆刷第93天之hot100五连刷51-55

力扣爆刷第93天之hot100五连刷51-55 文章目录 力扣爆刷第93天之hot100五连刷51-55一、200. 岛屿数量二、994. 腐烂的橘子三、207. 课程表四、208. 实现 Trie (前缀树)五、46. 全排列 一、200. 岛屿数量 题目链接&#xff1a;https://leetcode.cn/problems/number-of-islands/d…

tigramite教程(五)使用TIGRAMITE 进行自助聚合和链接置信度量化

使用TIGRAMITE 进行自助聚合和链接置信度量化 自助聚合&#xff08;Bagging&#xff09;和置信度估计例子数据生成模型基本的PCMCIBagged-PCMCI使用优化后的pc_alpha进行自举聚合使用优化的pc_alpha进行CMIknn的自举聚合 TIGRAMITE是一个用于时间序列分析的Python模块。它基于P…

【Spring】学习Spring框架那点小事儿

Spring作者&#xff1a;Rod Johnson Rod Johnson 是一位软件开发人员和作家&#xff0c;他在软件开发领域有着广泛的影响力。他出生于澳大利亚&#xff0c;拥有计算机科学和音乐双学位&#xff08;能写出有优雅的代码一定有艺术细胞&#xff09;。 Rod Johnson 在 2002 年出版…

【Python】python实现Apriori算法和FP-growth算法(附源代码)

使用一种你熟悉的程序设计语言&#xff0c;实现&#xff08;1&#xff09;Apriori算法和&#xff08;2&#xff09;FP-growth算法。 目录 1、Apriori算法2、F-Growth算法3、两种算法比较 1、Apriori算法 def item(dataset): # 求第一次扫描数据库后的 候选集&#xff0c;&am…

深圳服务器托管-优质的BGP机房

服务器只需要设置一个IP地址&#xff0c;最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的&#xff0c;不会占用服务器的任何系统资源。服务器的上行路由与下行路由都能选择最优的路径&#xff0c;所以能真正实现高速的单IP高速访问。 BGP协议本身具有冗…

OpenCV实战--利用级联分类器检测眼睛、行人、车牌等等

1、前言 opencv 提供级联分类器除了识别人脸外,还可以检测其他的物体 级联分类器的介绍:OpenCV实战--人脸跟踪(级联分类器) 检测人脸,戴上眼镜的演示: 这里只演示几个,更多的级联分类器文件可以百度自行查看 2、眼睛跟踪 haarcascade_eye.xml 检测眼睛的级联分类器文…

C#、C++、Java、Python 选择哪个好?

作者&#xff1a;网博汇智 链接&#xff1a;https://www.zhihu.com/question/298323023/answer/2789627224 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 一个好的程序员不能把自己绑定在一种语言上&#xff0c;不…