当前位置: 首页 > news >正文

Linux高级编程-进程间通信(IPC)

进程之间共享数据的方式可以通过进程通信:

        1、古老的通信方式:无名管道  有名管道  信号

         2、IPC对象通信 :消息队列(用的相对少,这里不讨论)、共享内存(最高效)、 信号量集             3、socket通信:网络通信、线程信号

这里我们主要介绍下无名管道、有名管道、信号量集、socket通信在后序中会一次介绍。先说下管道相关的知识。

        管道(pipe)是进程间通信(IPC)的一种机制,允许一个进程将数据传输到另一个进程。它具有以下特性和行为:

        1. 半双工模式

        半双工:管道是半双工的,只能单向传输数据,即数据只能从一个方向流动(从写端到读端)。如果需要双向通信,需要两个管道。

        2. 特殊文件

        特殊文件:管道是特殊文件,不支持定位操作。与普通文件不同,管道不支持 lseek 和 fseek,因为它们的读取是基于流的,不像普通文件那样可以随机访问。

        3. 文件IO操作

        文件IO:对管道的读写操作使用文件IO函数,例如 open、read、write 和 close。同样,使用标准库函数如 fgets 和 fread 也可以对管道进行操作,但需要配合文件描述符和流管理。

特性和行为:

        写阻塞:如果管道的缓冲区(通常是 64KB)已满,进一步写入数据会阻塞,直到管道有足够的空间。这个行为保证了数据不会丢失。

        读阻塞:如果管道为空,读操作会阻塞,直到管道中有数据可读。若管道关闭,读操作将返回 0,表示管道已经结束。

        管道破裂:如果管道的读端被关闭,而写端仍存在,写操作会失败,通常返回 EPIPE 错误(Broken pipe)。也可以通过触发它关闭程序。

        正常结束:如果管道的写端关闭且管道中没有数据,读操作将返回 0,表示管道已经关闭,没有更多数据可读。

gdb调试中可以使用 set folloe -fork(回车)  -mode f child/parent选择进程进行调试

一、无名管道

        无名管道(anonymous pipe)是一种用于在相关进程间进行简单数据通信的机制。它通过一对文件描述符提供了一个半双工的通信通道,即一个进程可以写入数据到管道的写端,另一个进程从管道的读端读取数据。以下是关于无名管道的特性:

        亲缘关系进程:无名管道只能在具有亲缘关系的进程之间使用,通常是父子进程。创建无名管道的进程(通常是父进程)在 fork 调用之后,子进程会继承父进程的文件描述符,允许父子进程通过管道进行通信。

        固定的读写端:无名管道有两个固定的文件描述符,一个用于读取(读端),关闭写的文件描述符pipefd[1] ;另一个用于写入(写端)、关闭读的文件描述符pipefd[0] 。读端和写端在 pipe 调用时被创建,且只能通过文件描述符 pipefd[0] 和 pipefd[1] 进行操作。也可以通过fdopen()转为文件流指针进行使用。

1、创建并打开管道

int pipe(int pipefd[2]);

        功能:创建一个无名管道,并初始化管道的读端和写端。

        参数:

                pipefd[0]:指向管道的读端的文件描述符。

                pipefd[1]:指向管道的写端的文件描述符。

        返回值:成功返回 0;失败返回 -1,并设置 errno 以指示错误。

        注意事项:fork 之前创建,无名管道的创建应在 fork 调用之前进行,以便父进程和子进程共享同一管道的文件描述符。

2、读写

ssize_t read(int fd, void *buf, size_t count);

        功能:从管道的读端读取数据。

        参数:

                fd:管道的读端文件描述符(pipefd[0])。

                buf:用于存储读取数据的缓冲区。

                count:要读取的最大字节数。

        返回值:成功时返回读取的字节数,失败时返回 -1。

ssize_t write(int fd, const void *buf, size_t count);

        功能:向管道的写端写入数据。

        参数:

                fd:管道的写端文件描述符(pipefd[1])。

                buf:包含要写入数据的缓冲区。

                count:要写入的字节数。

        返回值:成功时返回写入的字节数,失败时返回 -1。

3、关闭管道

int close(int fd);

        功能:关闭管道的文件描述符。

二、有名管道

        有名管道 (FIFO - First In, First Out) 是一种特殊类型的文件,它允许进程间通信。与匿名管道不同,有名管道在文件系统中可见,并且通过文件路径进行标识。它在多个不相关进程之间传递数据非常有用,任意进程都可以使用。

        1、创建有名管道:使用 mkfifo 函数创建有名管道

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);

参数:pathname:指定有名管道的路径和名称。

          mode:指定文件权限,通常为八进制表示,如 0666(读写权限)。

          返回值:成功返回 0,失败返回 -1。

        2、打开有名管道:使用 open 函数打开有名管道,注意半双工的特性。

int fd_read = open("./fifo", O_RDONLY);  // 读端打开
int fd_write = open("./fifo", O_WRONLY); // 写端打开

        注意:有名管道尽量不使用 O_RDWR 方式打开,因为这会违背管道的半双工特性;不能使用 O_CREAT 选项创建文件,应使用 mkfifo 函数。

        3、读写管道:通过标准文件 I/O 函数进行读写操作、和文件I\O一样的操作步骤。

read(fd_read, buffer, sizeof(buffer));
write(fd_write, buffer, sizeof(buffer));

        4、删除有名管道:使用 unlink 函数删除有名管道文件。

int unlink(const char *pathname);
pathname:要删除的有名管道路径。
返回值:成功返回 0,失败返回 -1。

有名管道的关键点:

        同步问题、当读端关闭时,写操作会返回错误,通常是 SIGPIPE 信号;当写端关闭时,读操作返回 0。读写端必须同时存在,否则 open 函数会阻塞,直到另一端打开。亲缘关系进程中的使用、有名管道可以在 fork 之后的亲缘关系进程中使用。

三、信号通信

信号的响应方式分为以下几种:

        Term (终止):默认操作是终止进程。

        Ign (忽略):默认操作是忽略信号。

       Core (生成核心转储文件):默认操作是终止进程并生成一个核心转储文件,用于调试。

 例如:gdb a.out -c core 用于分析核心转储文件。

        Stop (停止):默认操作是停止进程。

        Cont (继续):默认操作是继续执行已停止的进程。        

        1、信号发送:通过 kill 命令或系统调用 kill() 函数可以向指定进程发送信号。

kill -9 1000  # 向进程 ID 为 1000 的进程发送 SIGKILL (9) 信号

        2. 使用 kill() 函数发送信号

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

 参数:

        pid:目标进程的进程 ID。

        sig:要发送的信号编号(可以通过 kill -l 查看所有信号的编号和名称)。

        返回值:成功返回 0,失败返回 -1。

        3、自发信号:raise() 函数

int raise(int sig);

        4、定时信号:alarm() 函数

unsigned int alarm(unsigned int seconds);

        作用:在指定的时间之后,系统会自动向进程发送 SIGALRM 信号。常用于实现定时功能。        

        5、暂停进程:pause() 函数

int pause(void);

        作用:使进程暂停执行,直到收到信号;信号的接收和处理。

每个进程对信号有三种默认响应方式:

        默认处理:系统默认的处理方式,如终止进程。

        忽略处理:忽略某些信号,如 SIGKILL (9) 和 SIGSTOP (19) 不可忽略。

        自定义处理:通过信号捕获机制,自定义信号的处理逻辑。

        6、信号处理函数 signal()

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

  参数:signum:信号编号。

  handler:信号处理函数,可以是以下三种宏之一:

        SIG_DFL:默认处理。

        SIG_IGN:忽略处理。

        自定义处理函数:定义特定的处理逻辑。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
void handle(int num)
{pid_t pid = wait(NULL);printf("wait pid :%d\n",pid);
}
int main(int argc, char *argv[])
{signal(SIGCHLD,handle);pid_t pid = fork();if(pid>0){while(1){printf("father processing...\n");sleep(1);}}else if(0 == pid) {printf("child pid %d\n",getpid());sleep(rand()%3);printf("child will done %d\n",getpid());exit(0);}else {perror("fork");return 1;}return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 构建大师:深入理解Linux下的Make和Makefile
  • UE5学习笔记20-给游戏添加声音
  • 安装VC++Redist报错0x80070003的解决办法
  • 大连网站建设手机网页页面设计
  • STM32入门教程:SPI通信
  • RabbitMQ 集群与高可用性
  • 每日算法!!
  • 利用Spring Boot实现微服务的API版本管理
  • C语言 面向对象编程
  • Java项目中的分库分表实践指南
  • QNN:基于QNN+example重构之后的yolov8det部署
  • DRF序列化_data传参
  • 一个比 Nginx 还简单的 Web 服务器
  • SoM的理解
  • 头脑风暴中的颜色
  • 【Leetcode】101. 对称二叉树
  • 2017 前端面试准备 - 收藏集 - 掘金
  • Apache Spark Streaming 使用实例
  • Intervention/image 图片处理扩展包的安装和使用
  • JS变量作用域
  • js操作时间(持续更新)
  • Less 日常用法
  • Node + FFmpeg 实现Canvas动画导出视频
  • 二维平面内的碰撞检测【一】
  • 技术发展面试
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 前端面试之闭包
  • 前嗅ForeSpider采集配置界面介绍
  • 思维导图—你不知道的JavaScript中卷
  • 线性表及其算法(java实现)
  • 优化 Vue 项目编译文件大小
  • 交换综合实验一
  • # 利刃出鞘_Tomcat 核心原理解析(八)-- Tomcat 集群
  • # 数论-逆元
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (全注解开发)学习Spring-MVC的第三天
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (万字长文)Spring的核心知识尽揽其中
  • (转)Unity3DUnity3D在android下调试
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET Micro Framework初体验
  • .net(C#)中String.Format如何使用
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .net反编译工具
  • .net项目IIS、VS 附加进程调试
  • /var/lib/dpkg/lock 锁定问题
  • [ vulhub漏洞复现篇 ] ECShop 2.x / 3.x SQL注入/远程执行代码漏洞 xianzhi-2017-02-82239600
  • [BT]小迪安全2023学习笔记(第29天:Web攻防-SQL注入)
  • [BZOJ 3282] Tree 【LCT】