26-LINUX--I/O复用-select

一.I/O复用概述

        /O复用使得多个程序能够同时监听多个文件描述符,对提高程序的性能有很大帮助。以下情况适用于I/O复用技术:

TCP 服务器同时要处理监听套接字和连接套接字。
服务器要同时处理 TCP 请求和 UDP 请求。
程序要同时处理多个套接字。
客户端程序要同时处理用户输入和网络连接。
服务器要同时监听多个端口
        需要指出的是,I/O 复用虽然能同时监听多个文件描述符,但它本身是阻塞的。并且当
多个文件描述符同时就绪时,如果不采取额外的措施,程序就只能按顺序依处理其中的每一
个文件描述符,这使得服务器看起来好像是串行工作的。如果要提高并发处理的能力,可以
配合使用多线程或多进程等编程方法

二.select机制

1.select接口介绍

        select 系统调用的用途是:在一段指定时间内,监听用户感兴趣的文件描述符的可读、
可写和异常等事件。
        select 系统调用的原型如下:
 #include <sys/select.h>int select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct ti
meval *timeout);/*select 成功时返回就绪(可读、可写和异常)文件描述符的总数。如果在超时时间内
没有任何文件描述符就绪,select 将返回 0。select 失败是返回-1.如果在 select 等待
期间,程序接收到信号,则 select 立即返回-1,并设置 errno 为 EINTR。maxfd 参数指定的被监听的文件描述符的总数。它通常被设置为 select 监听的所
有文件描述符中的最大值+1readfds、writefds 和 exceptfds 参数分别指向可读、可写和异常等事件对应的文件
描述符集合。应用程序调用 select 函数时,通过这 3 个参数传入自己感兴趣的文件
描述符。select 返回时,内核将修改它们来通知应用程序哪些文件描述符已经就绪
fd_set 结构如下:#define __FD_SETSIZE 1024typedef 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;通过下列宏可以访问 fd_set 结构中的位:FD_ZERO(fd_set *fdset); // 清除 fdset 的所有位FD_SET(int fd, fd_set *fdset); // 设置 fdset 的位 fdFD_CLR(int fd, fd_set *fdset); // 清除 fdset 的位 fdint FD_ISSET(int fd, fd_set *fdset);// 测试 fdset 的位 fd 是否被设置timeout 参数用来设置 select 函数的超时时间。它是一个 timeval 结构类型的指针,采用指针参数是因为内核将修改它以告诉应用程序 select 等待了多久。timeval结构的定义如下:struct timeval{long tv_sec; //秒数long tv_usec; // 微秒数};//struct timeval tv = {5,0};如果给 timeout 的两个成员都是 0,则 select 将立即返回。如果 timeout 传递
NULL,则 select 将一直阻塞,直到某个文件描述符就绪*/

2.设计思路图解

3.测试代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/select.h>
#include<time.h>#define STDIN 0
int main()
{int fd = STDIN;//键盘fd_set fdset;//集合,收集描述符while(1)//因为不止检测一次{FD_ZERO(&fdset);//清空集合,每个位置0:FD_ZEROFD_SET(fd,&fdset);//将描述符fd添加到集合fdsetstruct timeval tv = {5,0};//超时时间int n = select(fd+1,&fdset,NULL,NULL,&tv);//可能阻塞if(n ==-1)//select执行失败{printf("select err\n");}else if(n==0)//超市,没有找到可用事件描述符{printf("tme out\n");}else{if(FD_ISSET(fd,&fdset)){char buff[128]={0};int num = read(fd,buff,127);printf("num=%d,buff=%s\n",num,buff);}}}
}
~                                                                                                                                                                                            
~                                                                                                                                                                                            
~                         

4.tcp通过select实现并发连接

SER.C

#include<stdio.h>      // 标准输入输出库
#include<stdlib.h>     // 标准库,提供一些函数如malloc, free, rand等
#include<string.h>    // 字符串操作库
#include<unistd.h>    // UNIX标准函数库
#include<sys/select.h>// 选择库,提供select函数
#include<time.h>      // 时间库
#include<sys/socket.h>// 套接字库
#include<arpa/inet.h> // 提供inet_addr等函数
#include<netinet/in.h>// 提供一些网络相关的宏#define MAXFD 10       // 定义最大文件描述符数量// 初始化socket函数
int socket_init();// 初始化文件描述符数组
void fds_init(int fds[]){for(int i=0; i<MAXFD; i++){fds[i] = -1; // 将所有文件描述符初始化为-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;   // 将其设置为-1,表示未使用break;         // 退出循环}}
}// 接受客户端连接请求并添加到文件描述符数组
void accept_client(int sockfd, int fds[]){int c = accept(sockfd, NULL, NULL); // 接受连接if(c < 0){return; // 如果返回-1,表示出错}printf("accept c = %d\n", c);fds_add(fds, c); // 添加到文件描述符数组
}// 接收客户端发送的数据
void recv_date(int c, int fds[]){char buff[128] = {0}; // 创建缓冲区int n = recv(c, buff, 127, 0); // 接收数据if(n < 0){printf("cli close\n");close(c);          // 如果接收失败,关闭连接fds_del(fds, c);   // 从数组中删除该文件描述符return;}if(n == 0){printf("time out(%d)\n", n); // 如果超时}printf("buff(c=%d)=%s\n", c, buff); // 打印接收到的数据send(c, "ok", 2, 0);             // 发送确认消息
}// 主函数
int main(){int sockfd = socket_init(); // 初始化socketif(sockfd == -1){exit(1); // 如果初始化失败,退出程序}int fds[MAXFD]; // 文件描述符数组fds_init(fds);  // 初始化数组fds_add(fds, sockfd); // 将监听的socket添加到数组fd_set fdset; // 创建文件描述符集合while(1){ // 无限循环等待事件FD_ZERO(&fdset); // 清空文件描述符集合int maxfd = -1; // 存储最大的文件描述符// 遍历文件描述符数组,将所有文件描述符添加到集合中for(int i=0; i<MAXFD; i++){if(fds[i] == -1){continue; // 如果文件描述符未使用,跳过}FD_SET(fds[i], &fdset); // 添加到集合if(fds[i] > maxfd){ // 更新最大文件描述符maxfd = fds[i];}}struct timeval tv = {5,0}; // 设置超时时间// 使用select等待直到有文件描述符准备好IO操作或超时int n = select(maxfd+1, &fdset, NULL, NULL, &tv);if(n == -1){printf("select err\n"); // 错误} else if(n == 0){printf("time out\n"); // 超时} else{// 遍历文件描述符数组,检查哪些文件描述符准备好了IO操作for(int i=0; i<MAXFD; i++){if(fds[i] == -1){continue; // 如果文件描述符未使用,跳过}if(FD_ISSET(fds[i], &fdset)){ // 检查文件描述符是否被设置if(fds[i] == sockfd){ // 如果是监听的socketaccept_client(sockfd, fds); // 接受新的连接} else{ // 如果是已连接的客户端recv_date(fds[i], fds); // 接收数据}}}}}
}// 创建socket并绑定到端口
int socket_init(){int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建socketif(sockfd == -1){return -1; // 创建失败返回-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"); // IP地址int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)); // 绑定if(res == -1){printf("bind err\n");return -1; // 绑定失败返回-1}if(listen(sockfd, 5) == -1){ // 开始监听,设置队列长度为5return -1; // 监听失败返回-1}return sockfd; // 返回socket文件描述符
}

CLI.C

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){exit(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 = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res == -1){printf("connct err\n");exit(1);}while(1){printf("input: ");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("buff=%s\n",buff);}close(sockfd);exit(0);
}

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

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

相关文章

使用 Django 构建动态网页

文章目录 创建 Django 项目和应用程序创建 HTML 模板创建视图函数配置 URL 路由运行 Django 服务器使用 Django 模板语言 Django 是一个流行的 Python Web 框架&#xff0c;它能够帮助开发人员快速构建强大的 Web 应用程序。在 Django 中&#xff0c;HTML 是用于呈现网页内容的…

1. 计算机系统概述

1. 计算机系统概述 文章目录 1. 计算机系统概述1.1 计算机的发展硬件的发展软件的发展 1.2.1 计算机硬件的基本组成早期冯诺依曼的结构现代计算机的结构 1.2.2 各个硬件的工作原理主存储器运算器控制器计算机工作过程 1.2.3 计算机系统的多级层次结构1.3 计算机的性能指标存储器…

GD32如何配置中断优先级分组以及中断优先级

使用GD32 MCU的过程中&#xff0c;大家可能会有以下疑问&#xff1a;中断优先级如何配置和使用&#xff1f; 本文将会为大家解析中断优先级分组以及中断优先级的配置使用&#xff1a; 中断优先级分组配置 一个GD32 MCU系统需要大家明确系统中使用的中断优先级分组&#xff0…

代驾公司在市场竞争中如何保持优势?

在竞争激烈的市场中&#xff0c;代驾公司可以通过多种策略保持其竞争优势&#xff0c;包括利用市场潜力、创新服务模式、提高服务效率以及加强品牌建设等。以下是具体的策略&#xff1a; 利用市场潜力 汽车产业空间巨大&#xff1a;随着汽车保有量的增加&#xff0c;代驾行业…

扫地机器人:卷价格,不如卷技术

扫地机器人内卷的终点是技术和价值&#xff0c;价格只是附属品。 一路上涨的价格&#xff0c;一路下跌的销量 从价格飙升&#xff0c;到重新卷回价格&#xff0c;尴尬的背后是扫地机器人在骨感现实下的无奈抉择。 根据数据显示&#xff0c;2020中国扫地机器人线上市场零售均价…

通过可识别性和深度学习重建大脑功能网络

摘要 本研究提出了一种新的方法来重建代表大脑动力学的功能网络&#xff0c;该方法基于两个脑区在同一认知任务中的共同参与会导致其可识别性或其动力学特性降低的观点。这种可识别性是通过深度学习模型在监督分类任务中获得的分数来估计的&#xff0c;因此不需要对这种协同参…

Flink端到端的精确一次(Exactly-Once)

目录 状态一致性 端到端的状态一致性 端到端精确一次&#xff08;End-To-End Exactly-Once&#xff09; Flink内部的Exactly-Once 输入端保证 输出端保证 幂等写入 事务写入 Flink和Kafka连接时的精确一次保证 整体介绍 需要的配置 案例 状态一致性 流式计算本身就…

无线麦克风哪个牌子性价比高?一文告诉你无线领夹麦克风怎么挑选

​当我们谈论到演讲、表演或者录制视频时&#xff0c;一个高质量的无线麦克风能够使得整个体验提升至一个全新的水平。它不仅能够保证声音的清晰度和真实度&#xff0c;还能够让使用者在演讲或者表演时更加自信和舒适。基于对市场的深入研究和用户体验的考量&#xff0c;我挑选…

【Java】解决Java报错:IllegalArgumentException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 非法的参数值2.2 空值或 null 参数2.3 非法的数组索引 3. 解决方案3.1 参数验证3.2 使用自定义异常3.3 使用Java标准库中的 Objects 类 4. 预防措施4.1 编写防御性代码4.2 使用注解和检查工具4.3 单元测试 结语 引言 在Java编程…

【NPS】微软NPS配置802.1x,验证域账号,动态分配VLAN(有线网络续篇)

继上一篇文章中成功实施了有线802.1x验证域账号并动态分配VLAN的策略之后&#xff0c;我们迎来了一个新的目标&#xff1a;在用户验证失败时&#xff0c;自动分配一个Guest VLAN&#xff0c;以确保用户至少能够访问基本的网络服务。这一改进将显著提升网络的灵活性和用户的上网…

Kafka的分区副本机制

目录 生产者的分区写入策略 轮询策略 随机策略 按key分配策略 乱序分区 自定义分区策略 实现步骤&#xff1a; 消费者组Rebalance机制 Rebalance触发时机 Rebalance的不良影响 消费者分区分配策略 Range范围分配策略 RoundRobin轮询策略 Stricky粘性分配策略 生产…

计算机网络-NAT配置与ACL

目录 一、ACL 1、ACL概述 2、ACL的作用 3、ACL的分类 4、ACL的配置格式 二、NAT 1、NAT概述 2、NAT分类 2.1 、 静态NAT 2.2 、 动态NAT 3、NAT的功能 4、NAT的工作原理 三、NAT配置 1、静态NAT配置 2、动态NAT配置 四、总结 一、ACL 1、ACL概述 ACL&#xff…

让编程变得更加直观与高效 “JAVA图形化编程”官网上线!

公测预约开启 我们历经了长达三年的时光&#xff0c;执着地坚守并潜心地进行探索&#xff0c;始终怀着一颗敬畏的心&#xff0c;最终极为谨慎地推出了这款图形化编程桌面。它能够使得业务与程序清晰明了地呈现&#xff0c;而且还能与传统的低零代码平台实现紧密…

新品发布 | 飞凌嵌入式RK3576核心板,为AIoT应用赋能

为了充分满足AIoT市场对高性能、高算力和低功耗主控日益增长的需求&#xff0c;飞凌嵌入式全新推出基于Rockchip RK3576处理器开发设计的FET3576-C核心板&#xff01; 集成4个ARM Cortex-A72和4个ARM Cortex-A53高性能核&#xff0c;内置6TOPS超强算力NPU&#xff0c;为您的AI…

LeetCode 两数之和 + 三数之和

两数之和 简单题 思路&#xff1a;一个Map&#xff0c;key是数值&#xff0c;value是该数值对应的下标&#xff0c;遍历的时候判断一下当前数组下标对应的值在map里有没有可组合成target的&#xff08;具体体现为在map里找target-nums【i】)&#xff0c;如果有&#xff0c;直接…

IDEA使用阿里通义灵码插件

在这个AI火热的时代&#xff0c;纯手工写代码已经有点out了&#xff0c;使用AI插件可以帮我们快速写代码&#xff0c;起码能省去写那些简单、重复性的代码&#xff0c;大大提高编码效率&#xff0c;在这里我推荐使用阿里的通义灵码 注册安装 安装注册好后&#xff0c;打开我们…

【流媒体】音频相关概念详解

文章目录 一、前言二、概述三、音频相关概念1、采样率&#xff08;Sampling rate&#xff09;2、位深度&#xff08;Bit depth&#xff09;3、比特率&#xff08;Bit rate&#xff09;4、声道&#xff08;Audio channel&#xff09;5、音频帧6、音频编码7、音频解码 一、前言 …

搭建自己的DNS服务器

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

腺苷调节合成高密度脂蛋白用于三阴性乳腺癌的化学免疫治疗

引用信息 文 章&#xff1a;Adenosine-modulating synthetic high-density lipoprotein for chemoimmunotherapy of triple-negative breast cancer 期 刊&#xff1a;Journal of Controlled Release&#xff08;影响因子&#xff1a;10.8&#xff09; 发表时间&am…

深入探索:十种流行的深度神经网络及其运作原理

算法 深入探索&#xff1a;十种流行的深度神经网络及其运作原理一、卷积神经网络&#xff08;CNN&#xff09;基本原理工作方式 二、循环神经网络&#xff08;RNN&#xff09;基本原理工作方式 三、长短期记忆网络&#xff08;LSTM&#xff09;基本原理工作方式 四、门控循环单…