Linux进程间通信

您所在的位置:网站首页 修改英文文章的软件 Linux进程间通信

Linux进程间通信

#Linux进程间通信| 来源: 网络整理| 查看: 265

1. 进程间通信概述

进程间通信(Inter-Process Communication, IPC)是指在两个或者多个不同得劲进程间传递或者交换信息,通过信息的传递建立几个进程间的联系,协调一个系统中的多个进程之间的行为。 1.1 进程间通信的工作原理 进程与进程之间是相互独立的,各自运行在自己的虚拟内存中。要想在进程与进程间建立联系,需要通过内核,在内核中开辟一块缓冲区,两个进程的信息在缓冲区中进行交换或者传递。其原理如下图所示。 在这里插入图片描述 进程间通信原理是:进程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]。此时,就可以将子进程中的某个数据写入到管道,然后在父进程中,将此数据读出来。 过程如下图所示: 在这里插入图片描述 其程序代码如下:

#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()) 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; }

结果: 在这里插入图片描述 管道特点:

只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork(),此后父子进程之间就可以应用该管道。一般而言,进程退出,管道释放,所以管道的生命周期跟随进程。一般而言,内核会对管道操作进行同步与互斥管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。 在这里插入图片描述 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; }

在这里插入图片描述 通过以上代码,可以了解到使用mkfifo()函数创建命名管道并进行数据传递的过程: (1)用mkfifo()函数创建一个命名管道,命名管道文件路径为/root/process/hello (2)调用open()函数打开该命名管道文件,以读写的方式打开。 (3)调用write()函数向文件写入信息"hello world", 同时调用read()函数读取该文件,输出到终端。 (4)调用close()函数关闭打开的命名管道文件。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3