【Linux】进程间通信——进程间通信的介绍和分类、管道、匿名管道、命名管道、匿名管道与命名管道的区别

文章目录

  • 进程间通信
    • 1.进程间通信的介绍
      • 1.1目的和发展
    • 2.进程间通信分类
    • 3.管道
      • 3.1匿名管道
        • 3.1.1匿名管道的原理(文件角度)
        • 3.1.2匿名管道的原理(内核角度)
        • 3.1.3管道读写规则
        • 3.1.4管道特点
      • 3.2命名管道
        • 3.2.1创建命名管道
        • 3.2.2命名管道的打开规则
    • 4.命名管道实现server&client通信

进程间通信

1.进程间通信的介绍

  进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的产生。进程间通信可以发生在同一台机器上的不同进程间,也可以发生在不同机器上的进程间。
  

1.1目的和发展

  目的:

  (1)数据传输:一个进程需要将它的数据发送给另一个进程。

  (2)资源共享:多个进程之间共享同样的资源。

  (3)通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

  (4)进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
  
  发展:

  管道 -> System V进程间通信 -> POSIX进程间通信。
  

2.进程间通信分类

  管道:匿名管道、命名管道

  System V IPC:System V 消息队列、System V 共享内存、System V 信号量

  POSIX IPC:消息队列、共享内存、信号量、互斥量、条件变量、读写锁
  

3.管道

  管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”。
在这里插入图片描述
  

3.1匿名管道

  匿名管道的原理:

  匿名管道的原理是使用pipe函数创建管道,并在父进程中得到两个文件描述符,一个用于从管道读数据,另一个用于向管道写数据。 子进程在创建时会自动继承这两个文件描述符,从而可以实现父子进程间的数据交换。

#include <unistd.h>

//功能:创建一无名管道

//原型
int pipe(int fd[2]);

//参数
//fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
//返回值:成功返回0,失败返回错误代码

在这里插入图片描述

//例子:从键盘读取数据,写入管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( void )
{
	int fds[2];
	char buf[100];
	int len;
	if ( pipe(fds) == -1 )
	perror("make pipe"),exit(1);
	
	// read from stdin
	while ( fgets(buf, 100, stdin) ) 
	{
		len = strlen(buf);
		// write into pipe
			if ( write(fds[1], buf, len) != len )
			{
				perror("write to pipe");
				break;
			}
		memset(buf, 0x00, sizeof(buf));
	
		// read from pipe
		if ( (len=read(fds[0], buf, 100)) == -1 ) 
		{
			perror("read from pipe");
			break;
		}
		// write to stdout
		if ( write(1, buf, len) != len ) 
		{
			perror("write to stdout");
			break;
		}
	}
}

  

3.1.1匿名管道的原理(文件角度)

  匿名管道的原理从文件角度来说,是利用内存中共享的一段缓冲区,以文件的方式对缓冲区实现。但因为该文件只存在于内存中,没有唯一命名,所以称为匿名管道。

  具体来说,父进程创建管道文件描述符,然后通过fork创建子进程。子进程继承了父进程的文件描述符,这样父子进程就可以通过这个文件描述符进行通信。 由于管道是半双工方式,数据传输的方向是单向的,所以如果需要进行双向通信,需要创建两个管道。

在这里插入图片描述

在这里插入图片描述

  

3.1.2匿名管道的原理(内核角度)

  从内核角度来说,匿名管道的原理是利用内核缓冲区作为伪文件,这个缓冲区由读端和写端两部分组成,对应两个文件描述符。数据从写端流入,从读端流出。

  匿名管道的内部实现方式是队列,而且是环形队列。这种队列的特性是先进先出,即一端入队,另一端出队,即只能从一端写入,另一端读出。缓冲区的大小默认是4k字节,但会根据实际情况做适当调整。

  由于用队列实现,数据只能读取一次,不能重复读取。另外,匿名管道是半双工方式,数据传输的方向是单向的。此外,匿名管道只适用于有血缘关系的进程,如父子进程、兄弟进程等。

在这里插入图片描述

这也符合了Linux的一切皆文件的思想

  
  父进程tast_struct中有指向file_struct的指针 *file,其中files_struct是一个struct file *fd_array[],这个array的数组中指向了各种的文件。同时创建子进程,子进程是父进程的一份拷贝,所以此时父进程指向的文件,子进程也同样会指向该文件,进程间通信的前提完成:让不同的文件看到同一份资源。

  
在这里插入图片描述
  

  接着,我们可以进行不同进程间的通信了,如果我们想要先让子进程写入,父进程读取。则我们可以在父进程和子进程所指的同一个文件中,进行不同的操作:让子进程在文件缓冲区中写入数据,让父进程在同样的文件缓冲区中读取数据。即可完成通过使用管道的通信操作(所以管道也是文件)。

在这里插入图片描述
  

3.1.3管道读写规则

  (1)当没有数据可读时
  O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
  O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

  (2)当管道满的时候
  O_NONBLOCK disable: write调用阻塞,直到有进程读走数据。
  O_NONBLOCK enable:调用返回-1,errno值为EAGAIN。

  (3)如果所有管道写端对应的文件描述符被关闭, 则read返回0。

  (4)如果所有管道读端对应的文件描述符被关闭, 则write操作会产生信号SIGPIPE,进而可能导致write进程退出。

  (5)当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

  (6)当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

  

3.1.4管道特点

  (1)只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信; 通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

  (2)管道提供流式服务

  (3)一般而言,进程退出,管道释放,所以管道的生命周期随进程

  (4)一般而言,内核会对管道操作进行同步与互斥

  (5)管道是半双工的,数据只能向一个方向流动; 需要双方通信时,需要建立起两个管道。

在这里插入图片描述
  

3.2命名管道

  命名管道的介绍:

  Linux命名管道是一种特殊的文件类型,它允许不具有亲缘关系的进程之间进行通信。命名管道存在于文件系统中,但同时具有管道的优点,可以用于进程间通信。进程通过操作命名管道文件进行数据交换。

  命名管道的创建可以使用命令行工具(如mkfifo命令)或者在编程语言中的调用系统调用接口(如mkfifo函数)来创建。 创建好命名管道之后,可以使用open()和read/write()函数来读取和写入数据。

  在数据传输方面,命名管道的数据传输不会写入磁盘,而是在内存中进行传递。命名管道允许多个进程通过使用相同的管道名称进行通信,而不仅仅是两个进程之间的通信。与普通管道一样,命名管道中的数据也是临时存储在内存中的。

  

3.2.1创建命名管道

  命名管道可以从命令行上创建:

$ mkfifo filename

  
  命名管道也可以从程序里创建,相关函数有:

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

  
  创建命名管道:

int main(int argc, char *argv[])
{
	mkfifo("p2", 0644);
	return 0;
}

  
  匿名管道与命名管道的区别:

  (1)匿名管道由pipe函数创建并打开。

  (2)命名管道由mkfifo函数创建,打开用open。

  (3)FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

  

3.2.2命名管道的打开规则

  (1)如果当前打开操作是为读而打开FIFO时
  O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO。
  O_NONBLOCK enable:立刻返回成功。

  (2)如果当前打开操作是为写而打开FIFO时
  O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO。
  O_NONBLOCK enable:立刻返回失败,错误码为ENXIO。

  

4.命名管道实现server&client通信

测试实现:

在这里插入图片描述
  

comm.hpp

#pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<string>
#include <unistd.h>
#include <fcntl.h>

#define FIFO_FILE "./myfifo"
#define MODE 0664

enum{
    FIFO_CREATE_ERR=1,
    FIFO_DELETE_ERR=2,
    FIFO_OPEN_ERR=3
};

  
Makefile

.PHONY:all
all:server client
server:server.cc
	g++ -o $@ $^ -std=c++11
client:client.cc
	g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm -f client server myfifo

  
server.cc

//#include<iostream>
#include"comm.hpp"

using namespace std;

//管理管道文件
int main()
{
    //创建信道
    int n=mkfifo(FIFO_FILE,MODE);
    if(n==-1)
    {
        perror("mkfifo");
        exit(FIFO_CREATE_ERR);
    }
    //sleep(5);
    //打开信道
    int fd=open(FIFO_FILE,O_RDONLY);
    if(fd<0)
    {
        perror("open");
        exit(FIFO_OPEN_ERR);
    }
    cout<<"server open file done"<<endl;

    //开始信道
    while(true)
    {
        char buffer[1024]={0};
        int x=read(fd,buffer,sizeof(buffer));
        if(x>0)
        {
            buffer[x]=0;
            cout<<"client say#"<<buffer<<endl;
        }
        else if(x==0)
        {
            cout<<"clinet quit,me too!\n"<<endl;
            break;
        } 
        else break;
    }
    close(fd);

    int m=unlink(FIFO_FILE);
    if(m==-1)
    {
        perror("unlink");
        exit(FIFO_DELETE_ERR);
    }

    return 0;
}

  
client.cc

#include<iostream>
#include"comm.hpp"

using namespace std;

int main()
{
    int fd=open(FIFO_FILE,O_WRONLY);
    if(fd<0)
    {
        perror("open");
        exit(FIFO_OPEN_ERR);
    }

    string line;
    while(true)
    {
        cout<<"Please Enter@";
        //cin>>line;
        getline(cin,line);

        write(fd,line.c_str(),line.size());
    }
    close(fd);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计算机网络学习之路】TCP socket编程

文章目录 前言一. 服务器1. 初始化服务器2. 启动服务器 二. 客户端三. 多进程服务器结束语 前言 本系列文章是计算机网络学习的笔记&#xff0c;欢迎大佬们阅读&#xff0c;纠错&#xff0c;分享相关知识。希望可以与你共同进步。 本篇博客基于UDP socket基础&#xff0c;介绍…

【SpringCloud】认识微服务、服务拆分以及远程调用

SpringCloud 1.认识微服务 1.1单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署 单体架构的优缺点&#xff1a; 优点&#xff1a; 架构简单&#xff0c;部署成本低 缺点&#xff1a; 耦合度高&#xff08;维护困难&#x…

设备状态监测与故障诊断系统的作用

随着工业生产的发展和技术的进步&#xff0c;设备状态监测与故障诊断系统在工业领域中扮演着越来越重要的角色。这一系统通过实时监测设备的状态和参数&#xff0c;及时发现潜在的故障&#xff0c;并提供预警信号&#xff0c;以降低生产中断、提高安全性和维护效率。以下将详细…

Django 模型和Admin站点管理(三)

一、定义模型 &#xff08;1&#xff09; 创建模型类&#xff0c;必须要继承自 models.Model from django.db import models# Create your models here. #设计数据库 #创建模型 class UserModel(models.Model):namemodels.CharField(max_length30) #对应于SQL name varchar(30…

慕尼黑电子展Samtec Demo | 回环测试带来Samtec产品组合优异表现

【摘要/前言】 大家好&#xff01;Electronica虎家展台Demo系列回来咯。 实践出真知&#xff0c;再好的纸面数据都不如来一场实际的测试和演示。Samtec团队始终在努力为客户带来卓越的产品和优质服务。而这其中&#xff0c;Demo演示的存在至关重要。演示过程可以为大家带来了…

ubuntu编译sqlite3并使用

SQLite3是一种轻量级的关系型数据库管理系统&#xff0c;它是在C语言基础上实现的。SQLite3具有许多优点&#xff0c;例如&#xff1a; 1.灵活&#xff1a;它可以在多种操作系统上运行&#xff0c;并且可以将多个数据库文件合并成一个文件。 2.易于使用&#xff1a;SQLite3使用…

“云浮云福保”暖心回归! 保障升级价格不变,医保个账可为全家缴费!

11月22日&#xff0c;2024年“云浮云福保”项目启动会在广东省云浮市迎宾馆成功举办。记者在会上获悉&#xff0c;“云浮云福保”是在云浮市医疗保障局、云浮市金融工作局、国家金融监督管理总局云浮监管分局指导下&#xff0c;的指导下&#xff0c;由中国人民财产保险股份有限…

网络安全之渗透测试入门准备

渗透测试入门所需知识 操作系统基础&#xff1a;Windows&#xff0c;Linux 网络基础&#xff1a;基础协议与简单原理 编程语言&#xff1a;PHP&#xff0c;python web安全基础 渗透测试入门 渗透测试学习&#xff1a; 1.工具环境准备&#xff1a;①VMware安装及使用&#xff1b…

Modbus转Profinet网关连接PLC与天信流量计通讯案例

本文将为您详细介绍如何成功连接PLC与天信流量计&#xff1a;从选择合适的Modbus转Profinet网关开始&#xff0c;到设置网关以实现通讯连接&#xff0c;还会涵盖部署和故障排除过程中可能遇到的一些问题。 首先&#xff0c;选择合适的Modbus转Profinet网关至关重要。我们选用基…

竞赛python区块链实现 - proof of work工作量证明共识算法

文章目录 0 前言1 区块链基础1.1 比特币内部结构1.2 实现的区块链数据结构1.3 注意点1.4 区块链的核心-工作量证明算法1.4.1 拜占庭将军问题1.4.2 解决办法1.4.3 代码实现 2 快速实现一个区块链2.1 什么是区块链2.2 一个完整的快包含什么2.3 什么是挖矿2.4 工作量证明算法&…

微信小游戏上线流程

微信小游戏上线是一个需要经过一系列步骤的过程。以下是一个一般性的微信小游戏上线流程&#xff0c;请注意&#xff0c;上述步骤可能会有微信平台的政策和规定的变化&#xff0c;因此建议在开发过程中及时查阅微信小游戏的官方文档和最新政策。北京木奇移动技术有限公司&#…

前后端分离SpringBoot+vue的买菜农副产品多功能商城

1&#xff0c;项目介绍 本系统主要针对买菜而设计&#xff0c;其功能有菜品基本信息管理、商品类别管理、系统订单管理、评论管理、系统用户管理等功能模块。并且本系统采用了现在流行的SpringBootVue进行的设计与实现&#xff0c;其中Tomcat为服务器&#xff0c;MySQL为数据库…

SpringBoot定时任务(一看就会)

一、引入依赖 定时任务是spring boot框架提供的基础能力之一&#xff0c;所以其依赖是在spring-boot-starter里面&#xff0c;但是一般开发的时候我们直接引入web依赖即可&#xff0c;web依赖中包含了spring-boot-starter。要注意的是Spring Boot 从版本1.3.0开始提供对定时任务…

写单元测试,没你想得那么简单!

前言 单元测试是什么我们就简单介绍一下&#xff1a; 单元测试是针对程序模块&#xff08;软件设计的最小单位&#xff09;来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。 接下来是本人对单元测试的理解和实践。里面没有废话&#xff0c;希望每句话能说到你心…

LangChain: 类似 Flask/FastAPI 之于 Django,LangServe 就是「LangChain 自己的 FastAPI」

原文&#xff1a;LangChain: 类似 Flask/FastAPI 之于 Django&#xff0c;LangServe 就是「LangChain 自己的 FastAPI」 - 知乎 说明&#xff1a;LangServe代替 langchainserver 成为新的langchain 部署工具 官网资料&#xff1a;&#x1f99c;️&#x1f3d3; LangServe | &…

批量插入SQL 错误 [933] [42000]: ORA-00933: SQL 命令未正确结束

使用DBeaver向【oracle数据库】插入大量数据 INSERT INTO Student(name,sex,age,address,birthday) VALUES(Nike,男,18,北京,2000-01-01) ,(Nike,男,18,北京,2000-01-01) ,(Nike,女,18,北京,2000-01-01) ,(Nike,女,18,北京,2000-01-01) ,(Nike,男,18,北京,2000-01-01) ,(Nike…

【JDK源码阅读】什么是 avoid getfield opcode ?

说明&#xff1a;JDK源码版本为 Oracle JDK 8 1. 背景 阅读 java.lang.String 的源码&#xff0c;会发现有些地方注释为/* avoid getfield opcode */&#xff0c;此处的代码是将当前类定义的成员变量引用为本地变量&#xff0c;从字面意思理解&#xff0c;是为了避免使用 get…

计算机基础知识——字,字节,进制,short,byte等

目录 进制位&#xff0c;字节&#xff0c;字Byte&#xff0c;ShortByteBuf有符号数和无符号数 进制 HEX&#xff0c;Hexadecimal &#xff0c;十六进制。 DEC&#xff0c;Decimal &#xff0c;十进制。 OCT&#xff0c;Octal &#xff0c;八进制。 BIN&#xff0c;Binary &a…

基于java和uniapp的即时聊天源码

聊天IM&#xff0c;支持单聊、群聊、朋友圈、摇一摇、附近的人、收藏、扫码、机器人、文字、图片、名片、实时音视频通话等功能。用uniapp开发&#xff0c;支持打包成多终端&#xff01; 推送&#xff1a;uniPush websocket资源&#xff1a;阿里OSS&#xff08;图片、声音、视…

JMeter —— 接口自动化测试(数据驱动)

前言 之前我们的用例数据都是配置在HTTP请求中&#xff0c;每次需要增加&#xff0c;修改用例都需要打开JMeter重新编辑&#xff0c;当用例越来越多的时候&#xff0c;用例维护起来就越来越麻烦&#xff0c;有没有好的方法来解决这种情况呢&#xff1f;我们可以将用例的数据存…