网络编程(五)IO模型

文章目录

  • 一、 阻塞IO
    • (一)阻塞IO模式
    • (二)示例
  • 二、非阻塞IO
    • (一)特点
    • (二)fcntl
    • (三)示例
  • 三、IO多路复用
    • (一)实现原理
    • (二)select函数
    • (三)使用示例
    • (四)关于select函数的理解

一、 阻塞IO

(一)阻塞IO模式

写操作阻塞:
写操作有阻塞的,当缓冲区满时,写操作就会阻塞
直到缓冲区中腾出足够的空间容纳的下本次写操作时,写操作解除阻塞。

读操作阻塞:
当程序执行到读操作时,如果缓冲区有内容,就读走继续向下执行。
如果缓冲区中没有内容,程序就会进入休眠态,直到缓冲区中有内容了,
由内核唤醒当前进程,读走内容继续向下执行。

(二)示例

以有名管道通信为例:同时开启一个读端和三个写端,三个写端分别向各自的管道文件写数据,读端使用循环分别读出管道的内容并打印

read.c

#include <my_head.h>int main(int argc, char const *argv[])
{int fd1 = 0, fd2=0, fd3=0;if(-1 == (fd1 = open("fifo1",O_RDONLY))){ERR_LOG("open error");} if(-1 == (fd2 = open("fifo2",O_RDONLY))){ERR_LOG("open error");} if(-1 == (fd3 = open("fifo3",O_RDONLY))){ERR_LOG("open error");} char buff[128];int ret=0;while(1){if(0 < (ret = read(fd1,buff,sizeof(buff)))){printf("fifo1:[%s];ret = %d\n",buff,ret);memset(buff,0,sizeof(buff));}if(0 < (ret = read(fd2,buff,sizeof(buff)))){printf("fifo2:[%s];ret = %d\n",buff,ret);memset(buff,0,sizeof(buff));} if(0 < (ret =read(fd3,buff,sizeof(buff)))){printf("fifo3:[%s];ret = %d\n",buff,ret);memset(buff,0,sizeof(buff));}}close(fd1);close(fd2);close(fd3);return 0;
}

write.c(三个写端除了打开的管道文件不同,其余相同)

#include <my_head.h>int main(int argc, char const *argv[])
{int fd = open("fifo1",O_WRONLY);char buff[128];while(1){scanf("%s",buff);if(-1 == write(fd,buff,sizeof(buff))){ERR_LOG("write error");}}close(fd);return 0;
}
  • 注:
  • 阻塞IO会相互影响:以上例说明,在写入fifo1并输出后,就会在读fifo2文件内容时阻塞等待,此时如果fifo1或者fifo3中有内容输入也不会处理。
  • 此时read进程处于休眠状态,等待用户输入内容,不会占用CPU

二、非阻塞IO

(一)特点

读操作为例:
当程序执行到读操作时,如果缓冲区有内容,就读走继续向下执行。
如果缓冲区中没有内容,程序会立即返回一个错误,而不会休眠。
这种操作一般需要一个循环来不停地测试是否有数据可读,
这种操作十分浪费CPU资源 一般不推荐使用。

有一部分函数 是自带非阻塞标志位的
如:recv和recvfrom的 MSG_DONTWAIT O_NONBLOCK 、waitpid的 W_NOHANG

(二)fcntl

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
功能:操作文件描述符
参数:fd:要操作的文件描述符cmd:操作方式F_GETFL  获取文件描述符的属性  arg被忽略F_SETFL  设置文件描述符的属性  arg是int类型其中 O_NONBLOCK 就是非阻塞的标志位...:可变参
返回值:F_GETFL 成功 返回文件状态信息  失败  -1  重置错误码

(三)示例

将文件设置为非阻塞。
read.c

#include <my_head.h>int main(int argc, char const *argv[])
{int fd1 = 0, fd2=0, fd3=0;int flag=0;if(-1 == (fd1 = open("fifo1",O_RDONLY))){ERR_LOG("open error");} flag=fcntl(fd1,F_GETFL);flag |= O_NONBLOCK;if(-1 == fcntl(fd1,F_SETFL,flag)){ERR_LOG("fcntl error");}if(-1 == (fd2 = open("fifo2",O_RDONLY))){ERR_LOG("open error");} flag=fcntl(fd2,F_GETFL);flag |= O_NONBLOCK;if(-1 == fcntl(fd2,F_SETFL,flag)){ERR_LOG("fcntl error");}if(-1 == (fd3 = open("fifo3",O_RDONLY))){ERR_LOG("open error");} flag=fcntl(fd3,F_GETFL);flag |= O_NONBLOCK;if(-1 == fcntl(fd3,F_SETFL,flag)){ERR_LOG("fcntl error");}char buff[128];int ret=0;while(1){if(0 < (ret = read(fd1,buff,sizeof(buff)))){printf("fifo1:[%s];ret = %d\n",buff,ret);memset(buff,0,sizeof(buff));}if(0 < (ret = read(fd2,buff,sizeof(buff)))){printf("fifo2:[%s];ret = %d\n",buff,ret);memset(buff,0,sizeof(buff));} if(0 < (ret =read(fd3,buff,sizeof(buff)))){printf("fifo3:[%s];ret = %d\n",buff,ret);memset(buff,0,sizeof(buff));}sleep(1);}close(fd1);close(fd2);close(fd3);return 0;
}
  • 注:
  • 非阻塞IO不会相互影响:以上例说明,不会再阻塞等待用户输入,在哪个管道读到数据,就直接输出。
  • 此时read进程处于运行状态,不会阻塞等待用户输入内容,会一直占用CPU资源进行遍历

三、IO多路复用

(一)实现原理

构造一个关于文件描述符的表,将所有要监视的文件描述符都放在这个表中
将这个表交给一个函数:select / poll / epoll
这个函数默认也是阻塞的,直到监视的文件文件描述符中有一个或多个准备就绪
这个函数会返回,返回时,会告诉调用者哪些文件描述符已经就绪,
调用者对已经就绪的文件描述符操作,就不会阻塞了。

(二)select函数

#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
功能:实现多路IO复用
参数:nfds:要监视的最大文件描述符+1readfds:要监视的读文件描述符集合(监视它是否可读) 不关心可以传NULLwritefds:要监视的写文件描述符集合(监视它是否可写) 不关心可以传NULLexceptfds:要监视的异常文件描述符集合 不关心可以传NULLtimeout:超时时间 传 NULL 表示永久阻塞 直到有就绪的文件描述符为止
返回值:成功  返回就绪的文件描述符的个数void FD_CLR(int fd, fd_set *set);//将文件描述符在集合中删除
int  FD_ISSET(int fd, fd_set *set);//测试文件描述符是否还在集合中//在 返回真 不在 返回假
void FD_SET(int fd, fd_set *set);//将文件描述符添加到集合中
void FD_ZERO(fd_set *set);//清空集合
  • 注:
    1. select只能监视小于FD_SETSIZE(1024)的文件描述符
    2. 我们一般只关心读文件描述符集合 其他两个传NULL即可
    3. select每次返回时会将没有就绪的文件描述符在集合中擦除
      所以在循环中使用select时每次需要重置集合

(三)使用示例

#include <my_head.h>int main(int argc, char const *argv[])
{int fd1 = 0, fd2=0, fd3=0;if(-1 == (fd1 = open("fifo1",O_RDONLY))){ERR_LOG("open error");} if(-1 == (fd2 = open("fifo2",O_RDONLY))){ERR_LOG("open error");} if(-1 == (fd3 = open("fifo3",O_RDONLY))){ERR_LOG("open error");} //创建fd_set readfds;//用来保存需要监视的文件描述符的母本fd_set tempfds;int max_fd=0;FD_ZERO(&readfds);FD_ZERO(&tempfds);FD_SET(fd1,&readfds);max_fd = max_fd > fd1 ? max_fd : fd1;FD_SET(fd2,&readfds);max_fd = max_fd > fd2 ? max_fd : fd2;FD_SET(fd3,&readfds);max_fd = max_fd > fd3 ? max_fd : fd3;char buff[128];int num = 0;while(1){tempfds = readfds;num = select(max_fd+1,&tempfds,NULL,NULL,NULL);for(int i=0; i<max_fd+1 && num; i++){if(FD_ISSET(i,&tempfds)){memset(buff,0,sizeof(buff));if(0 < read(i,buff,sizeof(buff))){printf("fd%d:[%s]\n",i,buff);}num--;}}}close(fd1);close(fd2);close(fd3);return 0;
}

(四)关于select函数的理解

  1. fd_set 实际是一个长度为1024的bit数组,
typedef struct{long ss[16]; //8*8*16=1024
}fd_set;

但是C语言最小单位是字节,因此才用这种方式表示;

  1. select的集合是基于数组实现的,最多监视1024个文件
  2. 本质是一个数组,包一个结构体是为了复制方便
  3. 四个宏定义的本质就是封装好的方便用户操作集合的位运算

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

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

相关文章

基于System-Verilog的流水灯设计与仿真

文章目录 一、system Verilog1.语言基本介绍2.过程赋值和连续赋值 二、编写testbench仿真1.流水灯testbench2.2位全加器3.实验结果 一、system Verilog 1.语言基本介绍 像 Verilog 和 VHDL 之类的硬件描述语言 (HDL) 主要用于描述硬件行为&#xff0c;以便将其转换为由组合门…

【实用技巧】Unity中的3D物理系统:刚体——使用技巧

在使用Unity的3D物理系统中的刚体&#xff08;Rigidbody&#xff09;时&#xff0c;有一些技巧可以帮助你更有效地实现物理效果和优化性能。以下是一些使用刚体的技巧&#xff1a; 合理使用Is Kinematic属性&#xff1a; 对于那些不需要物理计算的对象&#xff0c;比如玩家控制…

海底管缆先敷后埋与边敷边埋有什么区别?

海缆铺设有两种方式&#xff1a;“边敷边埋”和“先敷后埋”。 “边敷边埋”冲埋式埋设犁施工法———通过埋设犁(水力开沟机)泵送高压水&#xff0c;在海底冲出一条沟槽的同时&#xff0c;将海缆平铺下去,然后利用在潮汐作用下海床面自行回填(必要时采取压盖保护施工)。主要施…

[linux]如何跟踪linux 内核运行的流程呢

前面已经可以把内核编译出来&#xff0c;但是作为技术狗想看到内核是怎么运行的怎么办&#xff1f; 内核很多代码都是C语言写的&#xff0c;那简单&#xff0c;添加2行代码&#xff1a; include/linux/printk.h 529和530原来的&#xff1a; #define pr_info(fmt, ...) \ …

python查看包的版本

在Python中,有多种方法可以查看已安装包的版本。以下是几种常用的方法: 使用pip命令: 在命令行或终端中,你可以使用pip命令来查看已安装包的版本。例如,要查看numpy的版本,可以运行: pip show numpy这将显示numpy包的详细信息,包括版本号。 如果你使用的是pip3(对应于…

vue input 限制输入,小数点后保留两位 以及 图片垂直居中显示 和 分享 git 小技巧

&#xff08;1&#xff09;input 限制输入&#xff0c;小数点后保留两位 <template><div><el-input v-model"number" input"checkNumber" blur"completeNumber" placeholder"请输入"></el-input></div>…

解析如何在vue3中使用Element-UI组件以及main.js文件

关于vue的环境配置在前文《Vue3项目——配置vue环境和构建一个vue项目》有讲。 配置Vue项目 今天我们配置vue项目时&#xff0c;直接勾选Default即可。 安装Element-UI组件库 首先是对Element-UI组件的安装&#xff0c;正常安装的命令为 npm install element-ui --save但是…

文章解读与仿真程序复现思路——电工技术学报EI\CSCD\北大核心《计及台风时空特性和灵活性资源协同优化的配电网弹性提升策略》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

78、区间选点

区间选点 题目描述 给定N个闭区间[ai,bi]&#xff0c;请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数N&#xff0c;表示区间数。 接下来N行&#xf…

鸿蒙轻内核M核源码分析系列二一 03 文件系统LittleFS

2.2 文件信息数组操作 函数LfsAllocFd()设置文件信息数组元素信息。参数fileName为文件路径信息&#xff0c;传出参数fd为文件描述符即数组索引。遍历文件信息数组&#xff0c;遍历到第一个未使用的元素标记其为已使用状态&#xff0c;设置文件路径信息&#xff0c;把数组索引…

【LeetCode最详尽解答】167-两数之和 II-输入有序数组 Two-Sum-II-Input-Array-Is-Sorted

欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家&#xff01; 链接&#xff1a; 167-两数之和 II-输入有序数组 直觉 这是一个典型的双指针问题。 输入&#xff1a…

gbase8s数据库阻塞检查点和非阻塞检查点的执行机制

1. 检查点的描述 为了便于数据库系统的复原和逻辑恢复&#xff0c;数据库服务器生成的一致性标志点&#xff0c;称为检查点&#xff0c;其是建立在数据库系统的已知和一致状态时日志中的某个时间点检查点的目的在于定期将逻辑日志中的重新启动点向前移动 如果存在检查点&#…

HTML DOM 对象

HTML DOM 对象 1. 概述 HTML DOM(文档对象模型)是一个跨平台和语言独立的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。在HTML DOM中,文档被表示为节点树,其中每个节点代表文档中的一个部分,例如元素、文本或属性。HTML DOM对象是构成这个节点树的基…

Windows 服务器Nginx 下载、部署、配置流程(图文教程)

不定期更新 目录 一、下载Nginx安装包 二、上传安装包 三、启动Nginx 四、Nginx常用命令 五、Nginx&#xff08;最小&#xff09;配置详解 六、Nginx&#xff08;基础&#xff09;配置详解 七、反向代理 八、负载均衡 九、动静分离 十、报错 一、下载Nginx安装包 四…

【源码】综合股票币币合约交易所源码/etf交易所源码/美股港股台股交易所源码

支持多国语言 全开源可二开的一个版本&#xff01;支持虚拟货币 ETF 外汇 美股 A股 港股 台股。 前端是VUE开发&#xff08;带vue工程源码&#xff09;后端JAVA开发&#xff01;搭建也相对简单。 总的来说功能非常强大&#xff0c;适合线上运营的一个版本&#xff0c;有兴趣的可…

(53)MOS管专题--->(08)MOS管N沟道MOS管

(08)MOS管N沟道MOS管 1 目录 (a)IC简介 (b)数字IC设计流程 (c)Verilog简介 (d)MOS管N沟道MOS管 (e)结束 1 IC简介 (a)在IC设计中,设计师使用电路设计工具(如EDA软件)来设计和模拟各种电路,例如逻辑电路、模拟电路、数字信号处理电路等。然后,根据设…

【因果推断python】38_预测模型1

目录 工业界中的机器学习 之前的部分涵盖了因果推理的核心。那里的技术是众所周知和成熟的。他们经受住了时间的考验。第一部分建立了我们可以依赖的坚实基础。用更专业的术语来说&#xff0c;第一部分侧重于定义什么是因果推理&#xff0c;哪些偏差会阻止相关性成为因果关系&…

支付数据安全

支付数据安全是确保支付系统和用户信息安全的关键环节&#xff0c;以下是一些可以采取的措施来增强支付数据的安全性&#xff1a; 数据加密&#xff1a;使用强加密算法来保护存储和传输中的支付数据&#xff0c;确保即使数据被截获也无法被未授权者读取[26]。 使用安全的通信协…

自定义防抖注解

问题场景 在开发中由于可能存在的网络波动问题导致用户重复提交&#xff0c;所以自定义一个防抖注解。设计思路&#xff1a;自定义注解加在接口的方法上&#xff0c;注解中设置了SPEL表达式&#xff0c;可以通过SPEL表达式从接口参数中提取Redis的Key&#xff0c;以这个Key作为…

空气的物性解释

什么是空气&#xff1f;什么是常态空气&#xff1f;空气就是我们生活在其中的大气。常态空气是一个规定的值&#xff08;不同国家有所不同&#xff09;&#xff1a;压力0.1MPa&#xff08;或者说是1个标准大气压&#xff09;、温度20℃、相对湿度为36%状态下称之为常态空气。常…