写点什么

Linux 系统编程 - 进程间通信 (管道)

作者:DS小龙哥
  • 2022 年 2 月 17 日
  • 本文字数:2354 字

    阅读完需:约 8 分钟

1. 进程间通信方式介绍

这篇文章介绍 Linux 下进程的间的通信方式,常用的方式如下:


1. socket—网络通信2. 管道---无名管道—命名管道---文件--FIFO3. 消息队列4. 共享内存5. 信号量集6. 信号—signal捕获信号---kill命令发送信号 int kill(pid_t pid, int sig);
复制代码

2. 标准流管道

标准流管道像文件操作有标准 io 流一样,管道也支持文件流模式。用来创建连接到另一进程的管道 popen 和 pclose。函数原型:


#include <stdio.h>FILE* popen(const char* command, const char* open_mode);int pclose(FILE* fp);
复制代码


popen 用于启动进程,用法含义与 fopen 类似,第二个参数填权限,支持填"r"和"w"。


pclose 用于关闭进程,释放资源。


popen 启动进程之后可以直接与启动的进程间通信,比较方便。


**示例代码: **从标准管道流中读取 打印/etc/profile 的内容:


#include <stdio.h>#include <stdlib.h>int main(){  FILE *file=NULL;  size_t len=0;  char buff[1024+1];    file=popen("cat /etc/profile","r"); //执行cat /etc/profile命令,读方式。    if(file!=NULL)  {       len=fread(buff,1,1024,file); //读数据         buff[len]='\0';       printf("len=%d\n %s\n",len,buff);  }   pclose(file); //等待线程结束。  return 0;}
复制代码

3. 无名管道

无名管道用于有亲戚关系的进程间通信。 比如: 兄弟进程、父子进程等。


#include <unistd.h> int pipe(int fds[2]);
复制代码


pipe 函数用于创建一个无名管道,如果成功,fds[0]就存放可读的文件描述符,fds[1]就存放可写文件描述符。


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


无名管道的特点:


  1. 只能在亲缘关系进程间通信(父子或兄弟)

  2. 半双工(固定的读端和固定的写端)

  3. 虚拟管道文件是一个存在内存的特殊文件,可以用 read、write 函数进行操作。


这里说的管道,就像一条水管,有两个端口,一端进水,另一端出水。管道也有两个端口,分别是读端和写端,进水可看成数据从写端被写入,出水可看数据从读端被读出。在程序里分别就对应了 read 和 write 函数。


示例代码:


#include <stdio.h>#include <unistd.h>#include <string.h>
int main(int argc,char **argv){ int fds[2]; /*1. 创建无名管道:得到管道读写文件描述符 fds[0]和读端相对应, fds[1]和写端相对应*/ pipe(fds); /*2. 创建子进程*/ pid_t pid; pid=fork(); if(pid==0) //子进程 { char buff[100+1]; int cnt; //从管道的读端读取数据 cnt=read(fds[0],buff,100); //带阻塞功能 buff[cnt]='\0'; printf("子进程收到的数据:%d,%s\n",cnt,buff); } else //父进程 { char buff[]="1234567890"; //向管道的写端写数据 write(fds[1],buff,strlen(buff)); //等待子进程结束 wait(NULL); printf("父进程正常结束.\n"); } return 0;}
复制代码

4. 命名管道

无名管道只能在亲缘关系的进程间通信大大限制了管道的使用,有名管道突破了这个限制,通过指定路径名的形式实现不相关进程间的通信,因为命名管道通信使用的管道是一个实体文件,在磁盘上的存在的,而无名管道是存在内存中的虚拟文件,其他进程无法访问,导致没有关联的进程无法进行通信。

4.1 在命令行如何创建管道文件?

[wbyq@wbyq test]$ mkfifo test.fifo[wbyq@wbyq test]$ lstest.fifo[wbyq@wbyq test]$ ls -l总用量 0prw-rw-r--. 1 wbyq wbyq 0 10月 15 15:29 test.fifo
复制代码

4.2 在命令行演示两个相关的进程通过进行管道文件进行通信

4.3 创建 fifo 文件的函数

1. 创建FIFO文件#include <sys/types.h>#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);参数:pathname:创建的FIFO文件的全路径名;mode:文件访问权限,比如0666。返回值:如果创建成功,则返回0,否则-1。
2. 删除FIFO文件#include <unistd.h>int unlink(const char *pathname);
3. 用命令创建和删除FIFO文件用命令mkfifo创建。用命令unlink删除。
复制代码

4.4 创建写端: FIFO

#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>
int main(int argc,char **argv){ if(argc!=2) { printf("./a.out <fifo文件--写>\n"); return 0; } int fd=open(argv[1],O_WRONLY); if(fd<0) { printf("%s 文件打开失败.\n",argv[1]); return 0; } char buff[]="1234567890"; write(fd,buff,strlen(buff)); close(fd); return 0;}示例代码: 进程B负责读数据#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>
int main(int argc,char **argv){ if(argc!=2) { printf("./a.out <fifo文件--读>\n"); return 0; } int fd=open(argv[1],O_RDONLY); if(fd<0) { printf("%s 文件打开失败.\n",argv[1]); return 0; } char buff[100+1]; int cnt; cnt=read(fd,buff,100); buff[cnt]='\0'; printf("buff=%s\n",buff); close(fd); return 0;}
复制代码

4.5 创建读端: FIFO

在命令行演示两个相关的进程通过进行管道文件进行通信.



代码创建读端,读取数据:


#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>
int main(void){ int fd=0; int len=0; char buff[100]; fd=open("myfifo",O_RDONLY); len=read(fd,buff,100); buff[len]='\0'; printf("read: %s\n",buff); return 0;}
复制代码


发布于: 6 小时前阅读数: 6
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
Linux系统编程-进程间通信(管道)