Linux学习笔记9

news2025/1/16 19:03:51

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);

    // 设置消息类型为 1
    msg.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.coloradmin.cn/o/1790847.html

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

相关文章

Transformer 论文重点

摘要 提出了一个 Transformer 模型&#xff0c;针对于一个机器翻译的小任务上表现结果比当时所有模型的效果都好&#xff0c;并且架构相比其它更加简单&#xff0c;后面就火到了发现什么方向都能用的地步。 介绍 循环神经网络&#xff0c;特别是长短时记忆[ 13 ]和门控循环[…

计算机SCI期刊,中科院3区,专业性强,审稿专业

一、期刊名称 Frontiers in Neurorobotics 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机科学 影响因子&#xff1a;3.1 中科院分区&#xff1a;3区 三、期刊征稿范围 神经机器人前沿在体现自主系统的科学和技术及其应用方面发表了严格的同行评审…

解决Mac无法上网/网络异常的方法,重置网络

解放方法 1、前往文件夹&#xff1a;/Library/Preferences/SystemConfiguration 2 、在弹窗中输入上边的地址 3 、把文件夹中除了下图未选中的文件全部删掉&#xff0c;删除时需要输入密码 4 、重启mac 电脑就搞定了。

Windows 宿主机访问 VirtualBox 虚拟机中创建的 docker 容器中的 mysql8.0 的数据

一、场景需求 在开发环境中&#xff0c;一般使用 windows 系统进行开发&#xff0c;但需要在 linux 系统中创建运行 mysql8.0 的 docker 容器中进行测试&#xff08;win10特定版本或win11才能安装 docker&#xff09;&#xff0c;为了方便还需要在 windows 系统中通过 SQLyog …

操作系统笔记(1)进程相关

进程概念&#xff1a; 进程同步&#xff1a;多个相关进程在执行次序上进行协调&#xff0c;使并发执行的进程之间能按照一定的规则共享系统资源&#xff0c;并能很好的合作&#xff0c;从而使进程的执行具有可再现性。 进程之间可能存在互斥或者同步的关系。 互斥(间接相互制…

Android gradle kts 8.0以上版本配置签名和修改APK输出名字

目录 概述修改签名配置新建签名文件目录配置签名信息使用签名信息打包 修改APK名称 概述 之前写过一篇文章是通过Kotlin的Dsl结合gradle编写的插件来管理项目依赖&#xff0c;我是从一个开源项目叫DanDanPlayAndroid项目上学到的&#xff0c;那时还没有使用toml文件来管理项目…

模糊小波神经网络(MATLAB 2018)

模糊系统是一种基于知识或规则的控制系统&#xff0c;从属于智能控制&#xff0c;通过简化系统的复杂性&#xff0c;利用控制法来描述系统变量之间的关系&#xff0c;采用语言式的模糊变量来描述系统&#xff0c;不必对被控对象建立完整的数学模型。相比较传统控制策略&#xf…

【Git】分支管理 -- 详解

一、理解分支 分支就是科幻电影里面的平行宇宙&#xff0c;当你正在电脑前努力学习 C 的时候&#xff0c;另一个你正在另一个平行宇宙里努力学习 JAVA。 如果两个平行宇宙互不干扰&#xff0c;那对现在的你也没啥影响。不过&#xff0c;在某个时间点&#xff0c;两个平行宇宙…

Jenkins流水线pipeline--基于上一章的工作流程

1流水线部署 1.流水线文本名Jenkinsfile,将流水线放入gitlab远程仓库代码里面 2构建参数 2pipeline脚本 Jenkinsfile文件内容 pipeline {agent anyenvironment {key"value"}stages {stage("拉取git仓库代码") {steps {deleteDir()checkout scmGit(branc…

小熊家务帮day5-day7 客户管理模块1 (小程序认证,手机验证码认证,账号密码认证,修改密码,找回密码等)

客户管理模块 1.认证模块1.1 认证方式介绍1.1.1 小程序认证1.1.2 手机验证码登录1.1.3 账号密码认证 1.2 小程序认证1.2.1 小程序申请1.2.2 创建客户后端工程jzo2o-customer1.2.3 开发部署前端1.2.4 小程序认证流程1.2.4.1 customer小程序认证接口设计Controller层Service层调用…

运营商卷大模型,云厂商霸主地位不保?

文&#xff5c;艺 思 编&#xff5c;王一粟 经过了2023年的小试牛刀&#xff0c;2024年&#xff0c;三大运营商带着大模型一路狂飙。 刚刚过去的5月&#xff0c;中国电信、中国移动、中国联通三大运营商集体完成了新一轮的大模型进化&#xff0c;特别是围绕大模型的研发与…

2023年计算机图形学课程知识总结

去年就该写的&#xff0c;但是去年这个时候太忙了。 就写来自己看看。留个记录留个念 文章目录 1. 图形&#xff0c;图像的定义2. 点阵、矢量3. 走样&#xff0c;反走样4. 字符裁剪精度&#xff08;1&#xff09; 串精度&#xff08;2&#xff09; 字符精度&#xff08;3&…

【ubuntu软件版本管理】利用update-alternatives管理ubuntu软件

​ 我们有的时候希望在安装了新软件之后保留旧版本的软件&#xff0c;比如希望保留旧版本的gcc&#xff0c;以防以前写的C编译出问题&#xff0c;这时候就需要版本管理软件update-alternatives。 ​ 在此之前我们需要先弄清楚&#xff0c;什么是ubuntu的软件&#xff1f;拿C源…

力扣 54.螺旋矩阵

题目描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入&#…

【宠粉赠书】大模型时代的网络安全:安恒“网安三剑客”实战指南

不知不觉中&#xff0c;小智的粉丝已经突破一万。为了回馈粉丝们的厚爱&#xff0c;今天小智给大家送上一套网络安全界的三宝书——安恒"网安三剑客"。下面我会详细给大家介绍这套图书&#xff0c;文末留有领取方式。 随着人工智能&#xff08;AI&#xff09;和大模型…

基于协同过滤算法的东北特产销售系统的设计

基于协同过滤算法的东北特产销售系统的设计 管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;基础数据管理&#xff0c;公告管理&#xff0c;新闻信息管理&#xff0c;商品管理 农户账户功能包括&#xff1a;系统首页&#xf…

【数据库】SQL--DQL(初阶)

文章目录 DCL1. 基本介绍2. 语法2.1 基础查询2.2 条件查询2.3 聚合函数2.4 聚合查询2.5 分组查询2.6 排序查询2.7 分页查询2.8 综合案例练习2.9 执行顺序 3. DQL总结 DCL 更多数据库MySQL系统内容就在以下专栏&#xff1a; 专栏链接&#xff1a;数据库MySQL 1. 基本介绍 DQL英…

WPF -> MVVM

1.1安装MVV MLight 打开 Visual Studio 2022。 在顶部菜单栏中选择“工具” -> “NuGet 包管理器” -> “程序包管理器控制台”。 在控制台中输入以下命令&#xff0c;并按回车键运行&#xff1a; Install-Package MvvmLightLibsStd104.等待安装完成后&#xff0c;你就…

汇编:调用Win32 API

在32位汇编程序中使用 Win32 API 是很常见的&#xff0c;特别是在开发 Windows 应用程序时调用的频率很高&#xff0c;Win32 API 提供了访问 Windows 操作系统功能的接口&#xff0c;包括窗口、消息处理、文件操作、网络通信等等。以下是使用 Win32 API 的一般步骤&#xff1a;…

Vue3项目练习详细步骤(第二部分:主页面搭建)

主页面搭建 页面主体结构 路由 子路由 主页面搭建 页面主体结构 在vuews目录下新建Layout.vue文件 主页面内容主体代码 <script setup> import {Management,Promotion,UserFilled,User,Crop,EditPen,SwitchButton,CaretBottom } from element-plus/icons-vue imp…