0

0

进程通信(一)无名管道和有名管道

絕刀狂花

絕刀狂花

发布时间:2025-07-15 08:20:13

|

840人浏览过

|

来源于php中文网

原创

进程通信是指不同进程之间进行信息交换的过程。

《王道考研复习指导》提到,管道通信是一种特殊的消息传递方式。所谓的“管道”,是指用于连接一个读进程和一个写进程以实现它们之间通信的共享文件,也称为pipe文件。发送进程(即写进程)通过字符流形式将大量数据写入管道(共享文件),而接收进程(即读进程)则从管道中读取数据。为了确保通信的顺畅,管道机制需要提供三种协调能力:互斥、同步和确认对方存在。接下来以Linux中的管道为例进行说明。在Linux系统中,管道是一种常用的通信机制。尽管管道本质上也是一种文件,但它与普通文件不同,管道能够克服使用文件通信的两个问题,具体表现为:1)管道大小受限。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区大小为4KB,这使得它不会像文件那样无限制增长。使用单一固定缓冲区可能会导致问题,如在写入管道时可能会填满缓冲区,发生这种情况时,write()调用将默认阻塞,等待某些数据被读取以释放空间。2)读进程可能比写进程运行得快。当所有当前数据已被读取时,管道变为空。在这种情况下,read()调用将默认设置为阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。注意:从管道读取数据是一次性操作,数据一旦被读取就会被丢弃,释放空间以便写入更多数据。管道只能进行半双工通信,即在某一时刻只能单向传输。若要实现父子进程之间的双向互动,需要使用两个管道。

在Linux操作系统下,可以使用ulimit -p命令查看默认管道的大小。

1.无名管道(匿名管道)

函数原型:int pipe(int pipefd[2])

参数:文件描述符数组,其中fd[0]表示读端,fd[1]表示写端。即管道的两端,注意fd是传出参数。当程序调用pipe函数时,操作系统会创建内核缓冲区,fd作为传出参数以便操作内核缓冲区。

返回值:如果匿名缓冲区创建成功,返回值为0;否则,返回-1,并设置errno全局变量为相应的错误。

适用范围:有血缘关系的进程间通信,如父子进程、兄弟进程。

下面举例说明如何使用无名管道在父子进程间进行通信:

进程通信(一)无名管道和有名管道前文已提到,由于管道是半双工通信,即在某一时刻只能单向传输。

代码语言:C

#include
#include
#include
#include
#include

int main(){ int fd[2]; //创建文件描述符数组,fd[0]对应管道读端,fd[1]对应管道写端 int res = pipe(fd); //fd作为传出参数,以便对内核缓冲区进行操作 assert(-1 != res);

pid_t pid = fork(); //创建子进程
if(-1 == pid){
    perror("fork()");
    exit(0);
}

//子进程
if(pid == 0){
    close(fd[0]); //关闭读端
    write(fd[1],"hello",5); //向内核缓冲区写入字符串hello
}else{
    close(fd[1]); //关闭写端
    char buf[128] = {0};
    read(fd[0],buf,sizeof(buf)); //将内核缓冲区的内容写入buf中
    printf("%s \n",buf); //将写入buf中的内容输出到屏幕上
}

}

代码语言:C

gcc pipe.c -o pipe
./pipe
hello

进程通信(一)无名管道和有名管道可以看出,使用匿名管道完成了父子进程的通信,子进程作为写进程输入信息hello,父进程作为读进程读取信息并输出到屏幕上。

BJXSHOP网上购物系统 - 书店版
BJXSHOP网上购物系统 - 书店版

BJXSHOP购物管理系统是一个功能完善、展示信息丰富的电子商店销售平台;针对企业与个人的网上销售系统;开放式远程商店管理;完善的订单管理、销售统计、结算系统;强力搜索引擎支持;提供网上多种在线支付方式解决方案;强大的技术应用能力和网络安全系统 BJXSHOP网上购物系统 - 书店版,它具备其他通用购物系统不同的功能,有针对图书销售而进行开发的一个电子商店销售平台,如图书ISBN,图书目录

下载

2.有名管道

由于无名管道的限制,仅限于有血缘关系的进程间通信,因此当需要在无血缘关系的进程之间通信时,pipe就不能使用了。这时需要使用有名管道(fifo)。其特点包括:(1)在磁盘上存在一个文件,使用ls -l命令可以查看管道文件的类型为p。(2)这是一个伪文件,其大小永远为0。(3)在内核中有一个对应的缓冲区。(4)半双工的通信方式。

进程通信(一)无名管道和有名管道使用场景:(1)无血缘关系的进程间通信。

创建方式:(1)使用命令mkfifo 管道名

进程通信(一)无名管道和有名管道(2)调用函数mkfifo,函数原型为:int mkfifo(const char *pathname, mode_t mode);参数:路径和权限。

下面举例说明如何使用mkfifo实现两个无血缘关系进程之间的通信。简单描述:在A进程中向内核缓冲区输入字符串,输入end表示结束进程。在B进程中将内核缓冲区的内容保存到命令行参数argv[1]指定的文件中。A进程:fifoa.c

代码语言:C

#include

include

include

include

include

include

int main(){ int fd = open("FIFO",O_WRONLY); //默认是阻塞的 if(fd == -1){ int n = mkfifo("FIFO",0664); //创建管道文件FIFO if(-1 == n){ perror("mkfifo"); exit(0); } fd = open("FIFO",O_WRONLY); } assert(-1 != fd); printf("open success!\n"); while(1){ printf("please input:"); char buf[128] = {0}; fgets(buf,128,stdin); if(strncmp(buf,"end",3) == 0) //输入end用以结束进程 { break; } write(fd,buf,strlen(buf) - 1); //strlen(buf)-1减去回车符占用的一个字节长度,否则输出到屏幕上的值为乱码 } close(fd); }

B进程:fifob.c

代码语言:C

#include

include

include

include

include

include

int main(int argc,char *argv[]){ int fd = open("FIFO",O_RDONLY); //默认是阻塞的 if(fd == -1){ perror("open"); exit(0); } assert(-1 != fd); int file_fd = open(argv[1],O_WRONLY|O_CREAT,0664); if(file_fd == -1){ perror("open"); exit(0); } char buf[128] = {0}; while(read(fd,buf,128) > 0){ write(file_fd,buf,strlen(buf)); memset(buf,0,128); } close(fd); close(file_fd); }

代码语言:C

gcc fifoa.c -o fifoa
gcc fifob.c -o fifob
./fifoa
./fifob a.txt

A、B进程必须同时执行,否则被执行的进程会出现阻塞。这体现了管道机制中的一条要求,必须确认对方的存在,否则就会阻塞,等待对方的到来。

进程通信(一)无名管道和有名管道进程通信(一)无名管道和有名管道 在A进程中输入字符串:

进程通信(一)无名管道和有名管道 查看由B进程保存的a.txt文件:

进程通信(一)无名管道和有名管道 正是我们在A进程中输入的字符串。

相关专题

更多
c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

519

2023.09.20

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

73

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

248

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

205

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1435

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

609

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

547

2024.03.22

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

3

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.3万人学习

Git 教程
Git 教程

共21课时 | 2.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号