Linux学习笔记9

Linux 进程间通信

介绍一下管道,管道是一种特殊的文件,它通过文件描述符来进行访问和操作

管道的读写操作是阻塞式的,如果没有数据可读,读操作会被阻塞,直到有数据可读;如果管道已满,写操作也会被阻塞,直到有空间可写

无名管道

特点:半双工,用于有亲缘关系的两个进程之间

介绍一下pipe 函数  int pipe(int pipefd[2])
参数pipefd[0]:用于读管道。
参数pipefd[1]:用于写管道。

使用逻辑:先建立一个fd[2]数组,将fd[]传入pipe函数去创建管道,之后创建进程通过返回值判断是子进程还是父进程,如果是子进程像读取数据,则要将fd[0]给close,父进程同理

int main() {int pfd[2];char buf[30];pid_t pid;// 创建管道if (pipe(pfd) == -1) {printf("Error: Failed to create pipe.\n");return 1;}// 创建子进程pid = fork();if (pid == -1) {printf("Error: Failed to create child process.\n");return 1;}if (pid == 0) {// 子进程从管道中读取数据close(pfd[1]);read(pfd[0], buf, sizeof(buf));printf("Child: Received message: %s\n", buf);close(pfd[0]);} else {// 父进程向管道中写入数据close(pfd[0]);write(pfd[1], "Hello, world!", 14);close(pfd[1]);}return 0;
}

有名管道

刚刚说的无名管道是适用于有亲缘关系的进程之间的,但是有名管道是可以用于无关系的进程之间的

有名管道fifo 给文件系统提供一个路径,这个路径和管道关联,只要知道这个管道路径,就可以进行文件访问,fifo 是指先进先出,也就是先写入的数据,先读出来

使用mkfifo函数创建有名管道,指定一个路径名。格式如下

int mkfifo(const char *pathname, mode_t mode);
参数*pathname:路径名,管道名称。
参数mode:管道的权限。

例如,mkfifo("/path/to/fifo", 0666)将创建一个路径为/path/to/fifo的有名管道。

例程如下:

int main() {const char *fifoPath = "/path/to/fifo";int fd;mkfifo(fifoPath, 0666);// 创建有名管道// 打开管道并进行通信fd = open(fifoPath, O_WRONLY);write(fd, "Hello, world!", 14);close(fd);fd = open(fifoPath, O_RDONLY);char buf[15];read(fd, buf, sizeof(buf));printf("Received message: %s\n", buf);close(fd);// 删除有名管道unlink(fifoPath);return 0;
}

从这个例程可以看出来 :unlink等于删除有名管道,我们先去用open函数去获取 管道 读/写的句柄,之后再执行读写

有名管道的例程2 writepipe.c

int main()
{
const char *fifo_name="my_fifo";
char *file1="data.txt";
int pipe_fd=-1;
int data_fd=-1;
int res=0;
const int open_mode=O_WRONLY;
int bytes_sent=0;
char buffer[PIPE_BUF+1];
if(access(fifo_name,F_OK)==-1)
{
res=mkfifo(fifo_name,0777);
if(res !=0)
{
fprintf(stderr,"Could not create fifo %s\n",fifo_name);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO O_WRONLY\n",getpid());
pipe_fd=open(fifo_name,open_mode);
data_fd=open(fifo1,O_RDONLY);
printf("Process %d RESULT %d\n",getpid(),pipe_fd);if(pipe_fd != -1){
int bytes_read=0;
bytes_read=read(data_fd,buffer,PIPE_BUF);
buffer[bytes_read]="\0";
while(bytes_read>0)
{res = write(pipe_fd,buffer, bytes_read);
if(res == -1)
{fprintf(stderr,"Write error on pipe\n");exit(EXIT_FAILURE);}
//累加写的字节数,并继续读取数据
bytes_sent += res;
bytes_read =read(data_fd,buffer,PIPE_BUF);
buffer[bytes_read]='\0';
}
close(pipe_fd);
close(data_fd);
}
else
exit(EXIT_FAILURE);
printf("finish");
exit(EXIT_SUCCESS);}

代码思路:这段程序的作用是将一个数据文件(data.txt)的内容写入到一个FIFO文件(my_fifo)中

首先if语句里是常用的检查函数access,用于检查当前进程对文件的访问权限,其声明一般是      int access(const char *path, int mode);               我们代码里的mode是“F_OK”表示文件是否存在,如果管道文件不存在,则新建管道文件

之后分别用open函数去返回pipe和data的句柄,方便后续读写使用

如果管道句柄存在,利用read函数将会把data文件里的内容以PIPE_BUF形式读到缓冲区,因为read返回的是读取数据的数量,所以我们可以在读到buffer里的最后一位处赋值“\0”表示结束

后面的同理,注意PIPE_BUF 是一个宏,表示系统中管道(或命名管道)的缓冲区大小的上限

之后编译运行测试。

一个小tips:在Shell命令中,& 符号表示将一个进程放入后台运行。具体来说,当你在终端中执行一个命令时,如果你在命令的末尾加上 & 符号,这个命令所启动的进程就会在后台运行,而不会阻塞当前的终端会话

可以用Linux命令“job”去查看运行的任务,使用linux 命令“jobs;sleep 5;jobs”可以看着5 秒延时看看这个任务是不是执行完了

由上面的例程可以看得出来,管道实际上是通过内核中的缓冲区进行数据传输的。当你创建一个管道时,实际上是创建了一个用于数据传输的缓冲区,而这个缓冲区是由操作系统内核来管理的,而不是由用户进程来直接管理。

消息队列msg

消息队列是一种进程间通信的机制,用于在不同的进程之间传递数据。消息队列允许一个进程向另一个进程发送数据,而无需直接共享内存或使用文件等外部数据存储方式。

在消息队列中,数据被组织成消息,每个消息都有一个标识符和一个内容。进程可以通过指定标识符来发送和接收特定类型的消息。通常,消息队列是先进先出(FIFO)的,即最先发送的消息会最先被接收。

这些消息可以被异步地发送和接收,即发送进程可以继续执行而不必等待接收进程处理消息

消息队列主要有两个函数msgrcv 和msgsnd,一个接收一个发送。

函数int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数msqid:消息队列的标识码。
参数*msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用
户可定义的通用结构。
参数msgsz:消息的长短。
参数msgflg:标志位。

函数ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数msqid:消息队列的标识码。
参数*msgp:指向消息缓冲区的指针。
参数msgsz:消息的长短

我们还需要了解一下下面这些知识:

1.key 参数是一个键值,用于唯一地标识一个消息队列,这个键可以是一个由程序员指定的常量值,也可以是通过调用 ftok 函数生成的 IPC 键值。

2.在使用System V IPC机制(如消息队列、信号量和共享内存)时,有一个重要的概念就是 IPC 键(IPC Key)。IPC键(Inter-Process Communication Key)是通过ftok函数生成的唯一标识符,用于在进程间通信中标识特定的资源,比如消息队列

IPC键是用于标识和访问IPC资源的一种机制,它使得不同的进程可以通过共享的IPC键来访问同一个IPC资源,从而实现进程间的通信和共享数据。

3.ftok 函数是用于生成一个唯一的 IPC 键值的函数

定义:  key_t ftok(const char *pathname, int proj_id);

ftok 函数接受两个参数:

①pathname:一个指向路径名的指针,它是用于生成 IPC 键值的文件的路径。

②proj_id:一个整数,用作项目标识符。

例如:key = ftok(".", 'a');————这里的 pathname 参数是 “.”,表示当前目录;参数是 'a',是一个用户定义的项目标识符

【注释:这个“proj_id”参数有一些注意事项,ftok函数会根据根据我们输入的项目标识符去生成IPC值,所以我们要注意尽量用不同的proj_id参数去标识】

例程msgsend

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>#define MSGSZ 128// 定义消息结构体
typedef struct msgbuf {long mtype;char mtext[MSGSZ];
} message;int main() {int msqid;key_t key;message msg;// 生成唯一的 IPC 键值key = ftok(".", 'a');if (key == -1) {perror("ftok");exit(1);}// 创建或获取消息队列msqid = msgget(key, IPC_CREAT | 0666);if (msqid == -1) {perror("msgget");exit(1);}printf("Enter message to send: ");fgets(msg.mtext, MSGSZ, stdin);// 设置消息类型为 1msg.mtype = 1;// 发送消息到消息队列if (msgsnd(msqid, &msg, sizeof(message) - sizeof(long), 0) == -1) {perror("msgsnd");exit(1);}printf("Message sent successfully.\n");return 0;
}

代码分析:

  • 逻辑:首先生成IPC键值,然后利用这个键值去创建消息队列,之后利用msgsnd函数去发消息。
  • msgget 函数用于创建或获取一个消息队列,并返回消息队列的标识符。它会根据给定的键值创建或获取一个消息队列,并可以指定一些标志位和权限参数来控制消息队列的行为和属性。
  • sizeof(message) - sizeof(long):在消息队列中,通常第一个字段是消息的类型标识符,它通常是一个 long 类型的整数。这个标识符用于区分不同类型的消息。因此,sizeof(message) - sizeof(long) 计算了除去类型标识符所占用的空间之外,消息体的实际长度

未完待续——————————————

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

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

相关文章

CodeArts 6月体验官活动重磅来袭,限量领取华为GT系列手表!

千呼万唤始出来&#xff0c;CodeArts 6月体验官活动来啦&#xff01; 为了让开发者更好地体验CodeArts&#xff0c;小编特意给大家准备了重磅好礼。 不仅有华为GT系列手表&#xff0c;还有开发者定制礼盒&#xff0c;更有多重定制好礼~ 快叫上小伙伴一起来体验CodeArts&…

2024年湖北职称评审面试答辩技巧有哪些?看完你就懂了

2024年度湖北省部分工程专业水平能力测试面试答辩开始了&#xff0c;答辩时间是&#xff1a;2024年6月15、16日。 测试地点&#xff1a;武汉市武昌区洪山侧路63号茶港军转小区1号楼(武汉大学西门旁) 水平能力测试注意事项&#xff1a; &#xff08;一&#xff09;报名参加202…

数据结构之归并排序算法【图文详解】

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;LiUEEEEE                        …

Kolmogorov–Arnold Networks (KAN) 即将改变 AI 世界

目录 一、说明 二、KAN介绍 2.1 什么是 Kolmogorov-Arnold Networks &#xff08;KAN&#xff09;&#xff1a; 2.2 KAN 的秘诀&#xff0c;Splines&#xff01; 2.3 了解KAN工作的最简单方法 三、KAN的主要优点 四、KAN 的 Python 实现 &#xff08;PyKAN&#xff09; 4.1 …

可燃气体报警器效检:预防事故,守护家园

在现代化工业生产、居民生活中&#xff0c;可燃气体报警器作为安全预防的重要工具&#xff0c;其准确性和可靠性直接关系到人们的生命财产安全。 因此&#xff0c;对可燃气体报警器进行定期效检&#xff0c;确保其处于最佳工作状态&#xff0c;是保障安全生产的必要措施。 接…

Java集合之List(超详细)

List是Java集合框架中一个非常重要的接口&#xff0c;它代表了一个有序的集合&#xff0c;允许元素重复&#xff0c;并且可以按照插入的顺序进行访问。 我们先来看看List在集合中的位置&#xff1a; List是单列集合接口Collection下的一个分支&#xff0c;另两个分支是Set和Qu…

【Redis数据库百万字详解】数据类型

文章目录 一、字符串类型概述1.1、数据类型1.2、字符串简介1.3、字符串应用场景 二、字符串命令三、哈希类型概述3.1、哈希介绍3.2、哈希类型应用场景3.3、哈希命令 四、列表类型概述4.1、列表简介4.2、使用场景4.3、列表命令 五、集合概述5.1、集合简介5.2、使用场景5.3、集合…

网络工程从头做-1

网络工程从头做-1 自下而上&#xff0c;从接入交换机开始网络的配置和规划 实验拓扑&#xff1a; 实验步骤&#xff1a; 1.完成基本配置 1.1 PC端IP地址信息配置略 1.2 接入层交换机S1配置 [Huawei]sys S1 [S1]undo in [S1]vlan b 10 20 [S1]int e0/0/1 [S1-Ethernet0/0/1]p l…

k8s怎么监听自定义资源的变更?(2)

接上一篇当生成下面代码之后怎么去使用呢&#xff1f; 1.生成crd文件 这里我们通过kubebuilder的一个子项目 controller-gen 来生成crd文件 https://github.com/kubernetes-sigs/controller-tools curl -L -o https://github.com/kubernetes-sigs/controller-tools; go ins…

D-Day 上海站回顾丨以科技赋能量化机构业务

5月31日下午&#xff0c;DolphinDB 携手光大证券&#xff0c;在上海成功举办 D-Day 行业交流会。三十余位来自私募机构的核心策略研发、量化交易员、数据分析专家们齐聚现场&#xff0c;深入交流量化投研交易过程中的经验、挑战及解决方案。 DolphinDB 赋能机构业务平台 来自光…

1877java项目建设平台管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 项目建设平台管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开 发。开发环境为TOMCAT7.0,Myeclipse8.…

java表实体 蛇形转驼峰 正则匹配替换

java表实体 蛇形转驼峰 正则匹配替换 1.匹配寻找正则&#xff1a;([a-z])_([a-z])2.替换结果正则&#xff1a;$1\U$2\E效果如下图所示&#xff1a;

Python第二语言(三、Python函数def)

目录 1. Python函数&#xff08;def 函数名():&#xff09; 1.1 sorted对容器进行排序&#xff1a;无法指定排序规则 1.2 sort对容器自定义排序&#xff1a;可以指定排序规则 1.3 获取变量长度函数&#xff08;len&#xff09; 1.4 函数的定义 1.5 函数-传参定义 1.6 函…

OpenCV如何判断一张图片是否有过高的明暗变化

操作系统&#xff1a;ubuntu22.04OpenCV版本&#xff1a;OpenCV4.9IDE:Visual Studio Code编程语言&#xff1a;C11 前言 判断一张图片是否有过高的明暗变化&#xff0c;可以通过分析图像的亮度分布一致性来实现。一种常见的做法是计算图像的亮度标准差&#xff08;Standard …

免费,C++蓝桥杯等级考试真题--第7级(含答案解析和代码)

C蓝桥杯等级考试真题--第7级 答案&#xff1a;D 解析&#xff1a;步骤如下&#xff1a; 首先&#xff0c;--a 操作会使 a 的值减1&#xff0c;因此 a 变为 3。判断 a > b 即 3 > 3&#xff0c;此时表达式为假&#xff0c;因为 --a 后 a 并不大于 b。因此&#xff0c;程…

ElementUI的Table组件在无数据情况下让“暂无数据”文本居中显示

::v-deep .el-table__empty-block {width: 100%;min-width: 100%;max-width: 100%; }

如何在npm上发布自己的包

如何在npm上发布自己的包 npm创建自己的包 一、一个简单的创建 1、创建npm账号 官网&#xff1a;https://www.npmjs.com/创建账号入口&#xff1a;https://www.npmjs.com/signup 注意&#xff1a;需要进入邮箱验证 2、创建目录及初始化 $ mkdir ufrontend-test $ cd ufron…

今日科普:了解、预防、控制高血压

高血压&#xff0c;常被称为“隐形的健康威胁”&#xff0c;许多患者可能在毫无预警的情况下发病&#xff0c;且患病率逐年攀升&#xff0c;同时患者群体逐渐年轻化&#xff0c;高血压虽然难以根治&#xff0c;但并不可怕&#xff0c;真正可怕的是血压长期居高不下&#xff0c;…

STM32(七):ADC电位检测 (标准库函数)

前言 上一篇文章已经介绍了如何用STM32单片机中的定时器的PWM波来实现LED的“呼吸”。这篇文章我们来介绍一下如何用STM32单片机中ADC进行电位检测&#xff0c;并发送到XCOM串口中显示。 一、实验原理 1.ADC模数转换的介绍 首先&#xff0c;我们先介绍一下AD模数模块&#…

arcpy批量导出图且图名为shp属性值

1.打开arcmap加载需要导出的图。需求是逐村显示“村界内图斑”并导出为图&#xff0c;在导出每个村时不显示周围的村和“村界内图斑” 2.arcmap上方空白处右键打开“数据驱动页面” 3.在“数据驱动页面”工具条点击第一个图标&#xff0c;打开“设置数据驱动页面” 4.在“设置…