linux parent child pipe 进程 ,数据,Linux进程间通信——管道通信

1. 进程间通信概述

进程间通信(Inter-Process Communication, IPC)是指在两个或者多个不同得劲进程间传递或者交换信息,通过信息的传递建立几个进程间的联系,协调一个系统中的多个进程之间的行为。

1.1 进程间通信的工作原理

进程与进程之间是相互独立的,各自运行在自己的虚拟内存中。要想在进程与进程间建立联系,需要通过内核,在内核中开辟一块缓冲区,两个进程的信息在缓冲区中进行交换或者传递。其原理如下图所示。

a6f707dccc0c3593c19be36fae9c67af.png

进程间通信原理是:进程A中的数据写入到内核中,进程B中的数据也写入到内核中,两者在内核中进行交换。交换后,进程A读取内核中的数据,进程B也读取内核中的数据,这样两个进程间交换数据的通信就完成了。两个进程通过内核建立了联系,那么交换数据、传递数据、发送事件等行为就都可以实现了。

1.2 进程间通信的主要分类

在Linux系统中,常见的进程间通信主要包括管道通信、共享内存通信、信号量通信、消息队列通信、套接口(SOCKET)通信和全双工通信。

Linux系统除了支持信号和管道外,还支持SYSV(System V)子系统中的进程间通信机制。在SYSV的IPC机制中,包括共享内存、信号量、消息队列通信。

2. 管道

管道与命名管道是最基本的IPC机制之一。管道主要用于父子或者兄弟进程间的数据读写,命名管道则可以在无关联的进程间进行沟通传递数据。

2.1 管道的基本定义

所谓管道,就像生活中的煤气管道、下水管道等传输气体和液体的工具,而在进程通信意义上的管道就是传输信息或数据的工具。以下水管道为例,当从管道一端输送水流到另一端时,只有一个传输方向,不可能同时出现两个传输方向。在Linux系统中的进程通信中,管道这个概念也是如此,某一时刻只能单一方向传递数据,不能双向传递数据,这种工作模式就叫做半双工模式。半双工工作模式的管道通信是只能从一端写数据,从另一端读数据。

2.2 管道创建和管道关闭

管道由Linux系统提供的pipe()函数创建,该函数原型为:

#include

int pipe(int filedes[2]);

pipe()函数用于在内核中创建一个管道,该管道一端用于读取管道中的数据,另一端用于将数据写入管道。在创建一个管道后,会获得一对文件描述符,用于读取和写入,然后将参数数组filedes中的两个值传递给获取到的两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向写端。

pipe()函数调用成功,返回值为0;否则返回-1,并且设置了适当的错误返回信息。此函数只是创建了管道,要想从管道中读取数据或者向管道中写入数据,需要使用read()和write()函数来完成。当管道通信结束后,需要使用close()函数关闭管道的读写端。

2.3 pipe()函数实现管道通信

(1)在父进程中调用pipe()函数创建一个管道,产生一个文件描述符filedes[0]指向管道的读端和另一个文件描述符filedes[1]指向管道的写端。

(2)在父进程中调用fork()函数创建一个一模一样的新进程,也就是所谓的子进程。父进程的文件描述符一个指向读端,一个指向写端。子进程同理。

(3)在父进程关闭指向管道写端的文件描述符filedes[1],在子进程中,关闭指向管道读端的文件描述符filedes[0]。此时,就可以将子进程中的某个数据写入到管道,然后在父进程中,将此数据读出来。

过程如下图所示:

f8e07dd417a382adbb093cf423cc48a2.png

其程序代码如下:

#include

#include

#include

#define MAXSIZE 100

int main()

{

int fd[2], pid, line;

char message[MAXSIZE];

/*创建管道*/

if(pipe(fd) == -1)

{

perror("create pipe failed!");

return 1;

}

/*创建新进程*/

else if((pid = vfork()) < 0)

{

perror("not create a new process!");

return 1;

}

/*子进程*/

else if(pid == 0)

{

close(fd[0]);

printf("child process SEND message!\n");

write(fd[1], "Hello Linux!",12); /*向文件中写入数据*/

}

else

{

close(fd[1]);

printf("parent process RECEIVE message is:\n");

line = read(fd[0], message, MAXSIZE); /*读取消息,返回消息长度*/

write(STDOUT_FILENO,message,line); /*将消息写入终端*/

printf("\n");

wait(NULL);

_exit(0);

}

return 0;

}

结果:

ea09da8ee2bd217f0a7f1b1e34584e24.png

管道特点:

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

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

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

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

15258cb5d9dd5e8cec18a42721d307c0.png

3. 命名管道

以上介绍的管道通信的方法有很多限制。受限制之一就是两个进程必须是相关联的进程。若是没有关系的进程间通信就要用命名管道。命名管道通常被称为FIFO。它作为特殊的设备文件存在于文件系统中。因此,在进程中可以使用open()和close()函数打开和关闭命名管道。

3.1 创建一个命名管道

· 命名管道可以从命令行上创建,命令行方法是使用下面这个命令:

$ mkfifo filename

· 也可以从程序里创建,相关函数:

#include

#include

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

该函数的参数pathname是一个文件的路径名,是创建的一个命名管道的文件名;参数mode是指文件的权限,文件权限取决于(mode&~umask)的值。

使用mkfifo()函数创建的命名管道文件与前面介绍的管道通信相似,只是它们创建方式不同。访问命名管道文件与访问文件系统中的其他文件一样,都是需要首先打开文件,然后对文件进行读写数据。如果在命名管道文件中读取数据时,并没有其他进程向命名管道文件中写入数据,则会出现进程阻塞状态;如果在写入数据的同时,没有进程从命名管道中读取数据,也会出现进程阻塞状态。

程序如下:

#include

#include

#include

#include

#include

#define FIFO "/root/process/hello"

int main()

{

int fd;

int pid;

char r_msg[BUFSIZ];

if((pid = mkfifo(FIFO,0777))==-1) /*创建命名管道*/

{

perror("create fifo channel failed!");

return 1;

}

else

printf("create success!\n");

fd = open(FIFO, O_RDWR); /*打开命名管道*/

if(fd == -1)

{

perror("cannot open the FIFO");

return 1;

}

if(write(fd,"hello world", 12) == -1) /*写入消息*/

{

perror("write data error!");

return 1;

}

else

printf("write data success!\n");

if(read(fd, r_msg, BUFSIZ) == -1) /*读取消息*/

{

perror("read error!");

return 1;

}

else

printf("the receive data is: %s\n",r_msg);

close(fd); /*关闭文件*/

return 0;

}

4ba65e8a53ad0a8853940410e67263d0.png

通过以上代码,可以了解到使用mkfifo()函数创建命名管道并进行数据传递的过程:

(1)用mkfifo()函数创建一个命名管道,命名管道文件路径为/root/process/hello

(2)调用open()函数打开该命名管道文件,以读写的方式打开。

(3)调用write()函数向文件写入信息"hello world", 同时调用read()函数读取该文件,输出到终端。

(4)调用close()函数关闭打开的命名管道文件。

标签:文件,函数,间通信,命名,管道,fd,Linux,进程

来源: https://blog.csdn.net/studyhardi/article/details/89852839

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值