进程间通信--IPC机制

news2024/9/28 3:25:31

                

        今天主要讲述独立的进程之间的通信,我们知道,进程是一个完整代码的执行过程,那么我们想实现在进程运行的过程之中传递信息或者是发送数据,就是通过IPC机制来完成。

        一、什么是IPC机制

        IPC:inter process communication 进程间通信机制

  1.  进程与进程间的用户空间、资源相互独立,内核空间共享。若要实现进程间通信,需要使用进程间通信机制
  2. 进程间通信需要操作共享的内核空间

        下图简略画出了两种进程通信的方式,本文主要讲解传统的通信 方式,即管道通信和信号通信

        

 

  • IPC机制:

    1、传统的进程间通信机制

            a、管道fifo

            b、信号signal

    2、system V 操作系统的IPC对象

            a、消息队列 message queue

            b、共享内存 shared memory

            c、信号灯集 semaphore

    3、用于跨主机进程间通信机制

            a、套接字 socket

 二、IPC通信方式之一 (管道通信)

 

        1、管道的基础概念

        在进程的内核空间中(3G-4G),创建一个管道(通道),要通信的进程可以往管道中添加内容,另一个进程从管道中获取。

        管道中的数据直接存储内核空间的内存中,用于通信

 

 2、管道的特点

  •  管道可以看作一个特殊的文件,一般的文件存储在磁盘上,管道文件的内容存储在内存中(用于通信)
  • 管道遵循先进先出的原则

  • 管道的数据是一次性的,对管道进行读操作,被读取的数据会从管道中删除

  • 当管道被关闭后(读和写),管道对应的内存空间中的数据就消失了

  • 管道是一种半双工的通信方式

  • 管道的大小:64KB = 64 * 1024B

  • 管道的使用,使用文件IO函数完成读和写,使用read、write,禁止使用lseek

        虽然特点很多,但是只有记住,管道其实就是一个文件,我们如何使用文件IO读取数据和写数据,那么在管道当中也是相同的操作即可 

 3、管道的分类和区别

        有名管道:

  • 定义:管道名字在文件系统中可见,管道文件在磁盘上有对应的标识(在磁盘上的文件大小为0

        无名管道:

  • 定义:由于无名管道不可见文件名,所以不能用在任意的两个进程之间的通信(两个进程不一定找到的是同一个管道文件)

        区别: 有名管道可以用于任意进程之间的数据传输,而无名管道由于不可见文件名,只能用于具有亲缘关系的进程之中,比如父进程和子进程之间传递数据

 4、管道的创建

1、有名管道的创建 

        mkfifo函数创建有名管道

函数头文件:

        #include <sys/types.h>

        #include <sys/stat.h>

函数原型:

        int mkfifo(const char *pathname, mode_t mode);

功能:创建一个有名管道文件

参数:

        参数1: const char *pathname:指定要创建的有名管道的文件路径名

        参数2: mode_t mode:创建权限, mode & ~umask

返回值:

        成功,返回 0

        失败,返回 -1,设置errno。errno == 17,代表文件已经存在,是一个合法的错误,文件存在可以继续执行

 

	//完成进程间通信
	//0、创建管道文件,如果管道文件存储,直接打开
	if( mkfifo("./fifofile",0664) < 0)
	{
		if(errno != 17)
		{
			perror("create fifo failed\n");
			return -1;
		}
		printf("fifo file is ok\n");
	}
	else
		printf("create fifo success\n");

 2、无名管道的创建

         pipe函数创建无名管道

头文件 

        #include <unistd.h>

函数原型

        int pipe(int pipefd[2]);

功能:创建一个无名管道,同时打开无名管道文件的读写端

参数: int pipefd[2]:数组,实参传递数组名,用于设置存储两个文件描述符(管道文件读打开、管道文件写打开 的文件描述符)

        pipefd[0]:读端

        pipefd[1]:写端

返回值:

        成功,返回0

        失败,返回-1,且设置errno

 

#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main()
{

	//先创建无名管道通信
	int fd[2];
	if( pipe(fd) < 0 )
	{
		perror("pipe faild:");
		return -1;
	}
	printf("pipe success\n");
	
	//创建子进程
	pid_t pid = fork();

	if(pid > 0)
	{//父进程
		close(fd[0]);
		char buf[128];
		//父进程通过管道发送到子进程
		while(1)
		{
			bzero(buf,128);
			scanf("%s",buf);
			write(fd[1],buf,strlen(buf));
			if(strcmp(buf,"quit") == 0)
				break;
		}
		close(fd[1]);
	}
	else if(pid == 0)
	{//子进程
		close(fd[1]);
		char buf[128];
		//子进程通过管道读取父进程数据
		while(1)
		{
			int ret = read(fd[0],buf,128);
			buf[ret] = '\0';
			printf("child print : %s\n",buf);
			if(strcmp(buf,"quit")==0)
				break;
		}
		close(fd[0]);
	}

	return 0;
}

         对于管道文件用得比较多的是有名文件,重点掌握

 三、IPC通信方式之一(信号通信)

 1、信号的概念

         信号就是一种通知,由一个进程发送到另一个进程的通知,通知另一个进程现在需要完成什么操作

 

 

 

进程对信号的处理方式

1、执行默认操作(缺省操作)

        定义:每一种信号都规定了默认处理操作

        当信号发送时,进程去执行默认处理

2、忽略信号

        定义:当信号发生时,对信号不做处理

        有两个信号无法忽略 9)SIGKILL 19)SIGSTOP

3、捕获信号

        定义:为特定的信号注册新的处理函数,当信号产生时,去执行自定义的处理函数

        有两个信号无法忽略 9)SIGKILL 19)SIGSTOP

 

 1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
 6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX

常见的信号如上图,共有62个信号:(1-31) (33-64)

        2) SIGINT: 退出进程 ctrl + c

        3) SIGQUIT :退出进程 ctrl + \

        20) SIGTSTP : 挂起进程 ctrl + z

        无法被捕获、忽略 的信号 9)SIGKILL 19)SIGSTOP

        11) SIGSEGV 段错误信号 退出进程

        13) SIGPIPE 管道破裂信号 退出进程

        17) SIGCHLD 子进程退出结束,子进程会发送 17 这个信号 给父进程

2、信号通信常用的函数 

 1、kill:发送信号给指定的进程

头文件:

        #include <sys/types.h>

        #include <signal.h>

函数原型:

        int kill(pid_t pid, int sig);

功能:发送信号给指定的进程

参数:

参数1: pid_t pid:

        pid > 0 :将信号发送给给指定的进程,pid值 就是 进程号

        pid == 0 :将信号发送给当前进程组的所有进程

        pid == -1:将信号发送给当前进程权限所能发送的所有进程,除了 init 1号进程

        pid < -1 :将信号发送给指定进程组夏的所有进程,进程组id == pid的绝对值

参数2:

         int sig:指定要发送的信号,写数字或者宏

返回值:

         成功,返回0

        失败,返回-1,设置errno 

 2、signal:接收指定的信号执行命令

头文件:

        #include <signal.h>

函数原型:

        typedef void (* sighandler_t)(int) ;//类型替换 sighandler_t 表示函数指针类型

        sighandler_t signal(int signum, sighandler_t handler);

功能:

        捕获信号,为 信号 注册信号的处理函数:将 signum信号 与 handler函数指针对应的函数做绑定

参数: 参数1: int signum:指定要捕获的信号

参数2:

         sighandler_t handler:函数指针,函数地址,指向返回值为 void,参数为 int 类型函数的地址

        SIG_IGN:忽略信号

        SIG_DFL:缺省操作,执行默认操作

        捕获信号:函数名,注册 是执行 自定义的函数(即参数2可以换成函数名,这个函数名名代替第一个参数执行,而第一个参数是kill传递过来的信号,signal接收以后,用这个函数代替执行这个信号)

返回值:

        成功,返回注册的处理函数的地址

        失败,返回SIG_ERR ,设置errno

        对于管道文件和信号,都是进程间传递数据的传统通信方式,信号里面的kill和signal:kill负责发送信号,signal复制接收信号,并不难理解,两个函数的联合使用就是信号传递的完整过程

四、问题小测 

        实现用管道文件和信号实现进程间的数据传输 

 进程1

 用于发送数据:

//发送信号,使用kill这个函数
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc, const char *argv[])
{
	//创建管道文件
	int num_mk=mkfifo("./fifofile",0664);
	if(num_mk<0)
	{
		if(errno==EEXIST)
		{
			printf("file is exist\n");
		}
	//	printf("mkfifo error\n");
	}
	//发送指定的信号
	int num_pid=atoi(argv[1]);
	int num_sig=kill(num_pid,10);//发送10这个信号给制定进程
	printf("%d\n",num_pid);
	if(num_sig==0)
	{
		printf("成功发送\n");
	}
	//打开管道文件,写入数据
	int fd_wr=open("./fifofile",O_WRONLY);
	if(fd_wr<0)
	{
		printf("open error\n");
		return -1;
	}
	while(1)
	{
		char buf[128];
		fgets(buf,128,stdin);
		int ret=write(fd_wr,buf,strlen(buf));
		if(ret<0)
		{
			printf("读取失败\n");
		}
		if(strcmp(buf,"quit\n")==0)
			break;
	}
	close(fd_wr);

	return 0;
}

进程2

用于接收信号

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>

void signal_tep(int num);

void signal_tep(int num) {
    // 打开管道文件
    int fd_rd = open("./fifofile", O_RDONLY);
    if (fd_rd < 0) {
        perror("open error");
        return;
    }

    while (1) {
        char buf[128];
        ssize_t ret = read(fd_rd, buf, sizeof(buf) - 1);
        if (ret <= 0) {
            perror("read error");
            break;
        }
        buf[ret] = '\0'; // 确保字符串正确结束
        printf("%s\n", buf);
        if (strcmp(buf, "quit\n") == 0) 
		{
			exit(0);//如果接收退出字符,退出进程
        }
    }

    close(fd_rd); // 关闭文件描述符
}

int main(int argc, const char *argv[]) {
    // 获取进程号
    int ret = getpid();
    printf("pid=%d\n", ret);

    // 设置信号处理函数
    if (signal(SIGUSR1, signal_tep) == SIG_ERR) {
        perror("signal error");
        exit(EXIT_FAILURE);
    }

    while (1) {
        pause(); // 等待信号:
    }

    return 0;
}

         注意:编译文件时要转换成其他文件名,不要用./aout

如下图:

 

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

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

相关文章

文件泄密?不存在的!一文读懂文件防泄密最新五个小妙招

在当今信息化时代&#xff0c;企业数据的安全性显得尤为重要。文件泄密事件频发&#xff0c;不仅会给企业带来巨大的经济损失&#xff0c;还可能损害企业的声誉。因此&#xff0c;如何有效防止文件泄密成为了企业管理中的重中之重。本文将为大家介绍最新的五个防泄密妙招&#…

vue大数据展示之虚拟列表

面试代码学习 父组件&#xff1a; <template><div class"box"><!--items总条数、 size数据高度、 shownumber每次渲染数据--><list :items"items" :size"60" :shownumber"10"></list></div><…

要实现主动元数据,关键技术在算子级血缘解析

主动元数据管理最早被 Gartner 在 2016 年提出&#xff0c;在 2022 年 Gartner 公布的顶级战略技术趋势中&#xff0c;主动元数据被认为是实现 Data Fabric&#xff08;数据编织&#xff09;和主动数据治理的基石&#xff0c;也是实现 Data Fabric 的关键能力 。在这份技术趋势…

全面解析:动态住宅代理的关键优势

在大数据时代的背景下&#xff0c;代理IP成为了很多企业顺利开展的重要工具。代理IP地址可以分为住宅代理IP地址和数据中心代理IP地址。选择住宅代理IP的好处是可以实现真正的高匿名性&#xff0c;而使用数据中心代理IP可能会暴露自己使用代理的情况。 住宅代理IP是指互联网服务…

关于springboot的Rest请求映射处理的源码分析(二)

前面我们知道了他怎么处理表单映射&#xff0c;这里我们来研究一下&#xff0c;他是如何处理具体请求的。也就是说我有那么多/user你是怎么定位到我在哪个cotroller&#xff0c;并且你是怎么定位到我具体是哪个接口。 这里我们就来逐步定位一下这个问题。 一、组件分析 老路子…

Nacos 部分漏洞整理

免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. Naco简介 微信公众号搜索:南风漏洞复现文库 该文…

element中 el-input 不更新的问题

需要在上面输入数字,下面一列都更改成一样的数字 batchChange(list,field,value){console.log(list,field,value);list.forEach((i,index) > {i[field]value;this.$set(list,index, JSON.parse(JSON.stringify(i)));});} 用 JSON.parse(JSON.stringify(i)) 转一下后,就可以…

langchain入门系列之八 langgraph多agent示例

在之前的文章中我们介绍了langgraph&#xff0c;并且用它做了一个小小的示例&#xff0c;在本文中&#xff0c;我们将使用智普清言来构建多agent 系统。百度千帆对langgraph支持较差(尤其是强制要求奇数偶数的role设置&#xff0c;传入messages的奇数偶数要求&#xff0c;让人有…

用好外呼机器人,帮助企业提升客户管理效率

外呼机器人&#xff0c;作为现代科技与企业管理的结合体&#xff0c;正在企业客户管理领域掀起革命性的变化。随着人工智能技术的不断进步&#xff0c;外呼机器人不仅实现了自动化呼叫&#xff0c;还能根据客户的语音情感进行相应的反馈和操作&#xff0c;极大地提高了客户满意…

AI大模型编写多线程并发框架(六十三):监听器优化·上

系列文章目录 文章目录 系列文章目录前言一、项目背景二、第七轮对话-补充异步执行代码三、第八轮对话-增加累计完成等字眼四、第九轮对话-线程安全优化五、第十轮对话-增加运行时数据七、参考文章 前言 在这个充满技术创新的时代&#xff0c;AI大模型正成为开发者们的新宠。它…

SpringBoot+Vue的图书管理系统【包含运行步骤】

SpringBootVue图书管理系统 一、项目介绍1. 图书信息管理2. 图书类型管理3. 图书借阅管理4. 用户管理 二、技术选型后端技术选型前端技术选型 三、运行步骤后端启动前端启动 四、项目演示源码获取方式 五、总结与展望 大家好&#xff0c;这里是程序猿代码之路&#xff01;随着信…

Linux基础1-基本指令7(其他常用指令,shell简介)

目录 1.uname 2.常用小指令 3.查看系统信息的其他指令 4.shell命令及其原理 4.1这里我们简单了解一下shell 4.2 shell存在的意义&#xff1f; 1.uname 如何查看计算机体系架构&#xff1f; uname -a,查看详细信息 uname -r 查看简要信息 2.常用小指令 TAB&#x…

Socket编程---UDP篇

目录 一. UDP协议 二. Socket编程 2.1 sockaddr家族 2.2 接口介绍 三. 服务端实现 四. 服务端调用实现 五. 客户端实现 六. 效果展示 一. UDP协议 何为UDP协议的含义&#xff0c;上篇粗略提及了一下TCP与UDP的区别&#xff1a; TCP&#xff1a; •…

将军百战死,程序十年成

将军百战死&#xff0c;程序十年成 十年前的 2014.8.3 我释出了动词算子式通用代码生成器的第一个完整版本 InfinityGPGenerator 0.6.5&#xff0c;即无垠式通用代码生成器 0.6.5。这是一个重大的里程碑。十年后&#xff0c;通用代码生成器已经是一个大家族。昨天&#xff0c;…

插入排序的动画展示与实现

排序学习思路&#xff1a;先实现单趟逻辑&#xff0c;在实现整体逻辑&#xff1b;先解决普遍情况&#xff0c;再解决特殊情况。 什么是插入排序 回忆下自己玩扑克牌的时候是怎么把手上的牌理顺的吧&#xff01;其实那就是插入排序&#xff0c;从左边往右边&#xff0c;把一张张…

强烈推荐!大模型辅助软件开发

图书推荐 作者介绍 很喜欢作者在书上的这句话了&#xff1a;是人类工程师的能力&#xff0c;而不是大模型的能力&#xff0c;决定了大模型协作式开发的上限。 本书内容 软件开发正在经历一场前所未有的范式变革。人工智能的飞速发展&#xff0c;特别是大型语言模型所取得的成…

【Python篇】Python 类和对象:详细讲解(上篇)

文章目录 Python 类和对象&#xff1a;详细讲解1. 什么是类&#xff08;Class&#xff09;类的定义 2. 什么是对象&#xff08;Object&#xff09;创建对象 3. 属性和方法属性&#xff08;Attributes&#xff09;方法&#xff08;Methods&#xff09;在类中定义属性和方法使用对…

使用facebook开源prophet模型预测上证指数etf股价

可以图个乐&#xff0c;没有那么准确&#xff0c;可能还需要更深入的研究分析 蓝线是预测的2024年的走势&#xff0c;绿线是实际走势&#xff0c;红线是历史和未来的分界线。结果上有蛮多差异的。 # 测试预测2024年 coded by luke 伊玛目的门徒 import akshare as ak impor…

基于Java的心灵治愈交流平台

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java语言&#xff1b;Spring Boot框架 工具&#xff1a;IDEA/Eclipse、Navicat 系统展示 首页 心…

美畅物联丨实时通信新篇章:Spring Boot与WebSocket的深度融合实践

在当今 Web 应用开发领域&#xff0c;实时通信功能已跃升为不可或缺的基石&#xff0c;特别是在即时消息传递、沉浸式在线游戏体验以及精准实时数据监控等关键领域。WebSocket协议&#xff0c;凭借其独特的全双工通讯机制&#xff0c;在单个持久连接上实现了服务器与客户端之间…