进程间并发通信-IO多路复用

2024-06-03 17:52

本文主要是介绍进程间并发通信-IO多路复用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 select

1.1 源码示例

/*************************************************************************> File Name: write.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年06月02日 星期日 14时50分23秒************************************************************************/#include<stdio.h>#include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h>#include <unistd.h>#include <string.h>int main(void)
{int fd=0;char tmpbuff[4096]={0};/* 1 创建有名管道 */mkfifo("/tmp/myfifo",0664);/* 2 打开有名管道 */fd=open("/tmp/myfifo",O_WRONLY);if(-1==fd){perror("fail to open");return -1;}/* 3 接收终端输入并写入管道文件描述符-向管道写数据 */while(1){fgets(tmpbuff,sizeof(tmpbuff),stdin);write(fd,tmpbuff,strlen(tmpbuff));}/* 4 关闭管道 */close(fd);return 0;
}
/*************************************************************************> File Name: read.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年06月02日 星期日 14时34分49秒************************************************************************/#include<stdio.h>#include <signal.h>#include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h>#include <unistd.h>#include <string.h>/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>int main(void)
{int fd=0;fd_set rdfds;fd_set tmpfds;int ret=0;char tmpbuff[4096]={0};/* 1 创建有名管道 */mkfifo("/tmp/myfifo",0664);/* 2 打开有名管道 */fd=open("/tmp/myfifo",O_RDONLY);if(-1==fd){perror("fail to open");return -1;}/* 3 文件描述符集的操作 - 4个宏 - FD_ZERO(initialize)-FD_SET(create)-FD_CLR(delete)-FD_ISSET(retrieve) *//* 3.1 初始化文件描述符集合 */FD_ZERO(&rdfds);//清除文件描述符集合 - 初始化文件描述符集合/* 3.2 增加文件描述符至文件描述符集合 */FD_SET(fd,&rdfds);//添加文件描述符至文件描述符集FD_SET(0,&rdfds);/* 4 管道读(写) - 终端和管道-谁来数据就读谁 */while(1){/* 4.1 初始化监听文件描述符集合 */tmpfds=rdfds;/* 4.2 监听文件描述符集合 -> 监听多个文件描述符,直到有一个或者多个文件描述符准备进行某类IO操作 *//*注意: 一旦监听到某个文件描述符准备进行IO操作,那么这个文件描述符监听前后状态就发生了变化 ( 非ready状态->ready状态 ),* 所以要想一直对某个文件描述符进行监听,每次调用select之前都要重置该文件描述符状态为监听之前的状态(即非ready状态)*/ret=select(fd+1,&tmpfds,NULL,NULL,NULL);if(-1==ret){perror("fail to select");return -1;}/* 4.3 查询文件描述符集合中某个文件描述符状态是否发生改变 */if(FD_ISSET(fd,&tmpfds)){memset(tmpbuff,0,sizeof(tmpbuff));read(fd,tmpbuff,sizeof(tmpbuff));printf("fifo: %s\n",tmpbuff);}if(FD_ISSET(0,&tmpfds)){memset(tmpbuff,0,sizeof(tmpbuff));fgets(tmpbuff,sizeof(tmpbuff),stdin);printf("stdin: %s\n",tmpbuff);}}/* 5 关闭文件描述符 */close(fd);return 0;
}

1.2 运行结果

1.3 分析总结

2 poll

1.1 源码示例

/*************************************************************************> File Name: write.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年06月02日 星期日 16时30分10秒************************************************************************/#include<stdio.h>#include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h>#include <unistd.h>#include <string.h>int main(void)
{int fd=0;char tmpbuff[4096]={0};/* 1 创建有名管道 */mkfifo("/tmp/myfifo",0664);/* 2 打开有名管道 */fd=open("/tmp/myfifo",O_WRONLY);if(-1==fd){perror("fail to open");return -1;}/* 3 接收终端输入并写入管道文件描述符-向管道写数据 */while(1){fgets(tmpbuff,sizeof(tmpbuff),stdin);write(fd,tmpbuff,strlen(tmpbuff));}/* 4 关闭管道 */close(fd);return 0;
}
/*************************************************************************> File Name: read.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年06月02日 星期日 16时30分10秒************************************************************************/#include<stdio.h>#include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h>#include <unistd.h>#include <string.h>#include <poll.h>int main(void)
{int fd=0;struct pollfd fds[2];int fready=0;char tmpbuff[4096]={0};/* 1 创建有名管道 */mkfifo("/tmp/myfifo",0664);/* 2 打开有名管道 */fd=open("/tmp/myfifo",O_RDONLY);if(-1==fd){perror("fail to open");return -1;}/* 3 初始化文件描述符状态结构体数组*/fds[0].fd=fd;//添加文件描述符至数组fds[0].events=POLLIN;//修改文件描述符状态为 准备读fds[1].fd=0;fds[1].events=POLLIN;/* 4 管道读(写) - 终端和管道-谁来数据就读谁 */while(1){/* 4.1 监听文件描述符状态结构体数组 */fready=poll(fds,2,-1);//文件描述符数组(数组)-文件描述符个数(数组长度)-超时时间(-1 一直等)if(-1==fready){perror("fail to poll");return -1;}/* 4.2 查询文件描述符状态 - 通过位掩码方式查询 - 置位 */if(fds[0].revents&POLLIN){memset(tmpbuff,0,sizeof(tmpbuff));read(fd,tmpbuff,sizeof(tmpbuff));printf("fifo: %s\n",tmpbuff);}if(fds[1].revents&POLLIN){memset(tmpbuff,0,sizeof(tmpbuff));fgets(tmpbuff,sizeof(tmpbuff),stdin);printf("stdin: %s\n",tmpbuff);}}/* 5 关闭管道 */close(fd);
}

1.2 运行结果

1.3 分析总结

3 epoll

1.1 源码示例

/*************************************************************************> File Name: write.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年06月02日 星期日 17时22分26秒************************************************************************/#include<stdio.h>#include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h>#include <unistd.h>#include <string.h>int main(void)
{int fd=0;char tmpbuff[4096]={0};/* 1 创建有名管道 */mkfifo("/tmp/myfifo",0664);/* 2 打开有名管道 */fd=open("/tmp/myfifo",O_WRONLY);if(-1==fd){perror("fail to open");return -1;}/* 3 接收终端输入并写入管道文件描述符-向管道写数据 */while(1){fgets(tmpbuff,sizeof(tmpbuff),stdin);write(fd,tmpbuff,strlen(tmpbuff));}/* 4 关闭管道 */close(fd);return 0;
}
/*************************************************************************> File Name: read.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年06月02日 星期日 17时22分26秒************************************************************************/#include<stdio.h>#include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h>#include <unistd.h>#include <string.h>#include <sys/epoll.h>int main(void)
{int fd=0;int epfd=0;struct epoll_event env;int fready=0;int i=0;struct epoll_event retenv[2];char tmpbuff[4096]={0};/* 1 创建有名管道 */mkfifo("/tmp/myfifo",0664);/* 2 打开有名管道 */fd=open("/tmp/myfifo",O_RDONLY);if(-1==fd){perror("fail to open");return -1;}/* 3 创建内核事件表 - 并返回表头 */epfd=epoll_create(2);//预期添加到事件表的文件描述符数量if(-1==epfd){perror("fail to epoll_create");return -1;}/* 4 初始化内核epoll事件结构体 - 数据类型 -初始化事件结构体 */env.events=EPOLLIN;//修改文件描述符状态为 准备读 - 事件状态 - 非ready态env.data.fd=fd;//文件描述符 - 这里指有名管道/* 5 操作内核epoll事件表 - EPOLL_CTL_ADD(增-fd)-EPOLL_CTL_DEL(删-fd)-EPOLL_CTL_MOD(改-fd事件) */epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&env);//建立文件描述符fd及其对应的事件env,并将文件描述符fd添加到epoll事件表epfd中env.events=EPOLLIN;env.data.fd=0;epoll_ctl(epfd,EPOLL_CTL_ADD,0,&env);//终端也将发生同样的事件(EPOLLIN),所以将终端(此指stdin)也加入至该内核事件表/* 6 管道读(写) - 终端和管道-谁来数据就读谁 */while(1){/* 6.1 监听内核epoll事件表,并返回ready态的文件描述符数量 */fready=epoll_wait(epfd,retenv,2,-1);//这里通过结构体数组retenv作为出参,将ready态的文件描述符带出-ready态if(-1==fready){perror("fail to epoll_wait");return -1;}/* 6.2 遍历所有ready态的文件描述符 */for(i=0;i<fready;i++){/* 通过ready态文件描述符进一步确认是哪个文件描述符状态被置位 -* 检测(类似于IO输入检测-key检测的思想-位掩码)-查询*/if(retenv[i].data.fd==0){memset(tmpbuff,0,sizeof(tmpbuff));fgets(tmpbuff,sizeof(tmpbuff),stdin);printf("stdin: %s\n",tmpbuff);}else if(retenv[i].data.fd==fd){memset(tmpbuff,0,sizeof(tmpbuff));read(fd,tmpbuff,sizeof(tmpbuff));printf("fifo: %s\n",tmpbuff);}}}/* 6 关闭管道*/close(fd);
}

1.2 运行结果

1.3 分析总结

这篇关于进程间并发通信-IO多路复用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1027694

相关文章

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

高并发环境中保持幂等性

在高并发环境中保持幂等性是一项重要的挑战。幂等性指的是无论操作执行多少次,其效果都是相同的。确保操作的幂等性可以避免重复执行带来的副作用。以下是一些保持幂等性的常用方法: 唯一标识符: 请求唯一标识:在每次请求中引入唯一标识符(如 UUID 或者生成的唯一 ID),在处理请求时,系统可以检查这个标识符是否已经处理过,如果是,则忽略重复请求。幂等键(Idempotency Key):客户端在每次

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,

Java并发编程之——BlockingQueue(队列)

一、什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作2. 当队列空了的时候进行出队列操作123 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空

Java IO 操作——个人理解

之前一直Java的IO操作一知半解。今天看到一个便文章觉得很有道理( 原文章),记录一下。 首先,理解Java的IO操作到底操作的什么内容,过程又是怎么样子。          数据来源的操作: 来源有文件,网络数据。使用File类和Sockets等。这里操作的是数据本身,1,0结构。    File file = new File("path");   字

java 进程 返回值

实现 Callable 接口 与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。 public class MyCallable implements Callable<Integer> {public Integer call() {return 123;}} public static void main(String[] args

springboot体会BIO(阻塞式IO)

使用springboot体会阻塞式IO 大致的思路为: 创建一个socket服务端,监听socket通道,并打印出socket通道中的内容。 创建两个socket客户端,向socket服务端写入消息。 1.创建服务端 public class RedisServer {public static void main(String[] args) throws IOException {

C#关闭指定时间段的Excel进程的方法

private DateTime beforeTime;            //Excel启动之前时间          private DateTime afterTime;               //Excel启动之后时间          //举例          beforeTime = DateTime.Now;          Excel.Applicat