📅  最后修改于: 2021-01-18 06:38:18             🧑  作者: Mango
管道是两个或多个相关或相互关联的过程之间的通信介质。它可以在一个进程内,也可以在子进程与父进程之间进行通信。通讯也可以是多层次的,例如父母,孩子和孙子女之间的通讯等。通讯是通过一个进程写入管道并从管道读取其他进程来实现的。要实现管道系统调用,请创建两个文件,一个文件写入文件,另一个文件读取文件。
可以实时查看管道机制,例如用管道将水填充到某个容器(例如桶)中,然后有人将其取回(例如用杯子)。填充过程只不过是写入管道,而读取过程只不过是从管道中检索。这意味着一个输出(水)被输入到另一个(桶)。
#include
int pipe(int pipedes[2]);
此系统调用将创建用于单向通信的管道,即,它创建两个描述符,第一个连接到管道以从管道读取数据,另一个连接到写入管道。
描述符pipedes [0]用于读取,pipedes [1]用于写入。可以将任何写入pipedes [1]的内容从pipedes [0]中读取。
成功时此调用将返回零,失败时将返回-1。要了解失败的原因,请使用errno变量或perror()函数。
#include
#include
#include
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
即使可以读写文件的基本操作,也必须在执行操作之前先打开文件,并在完成所需的操作后关闭文件。通常,默认情况下,通常为每个进程打开3个描述符,分别用于输入(标准输入– stdin),输出(标准输出– stdout)和错误(标准错误– stderr)文件描述符分别为0、1和2。
该系统调用将返回一个文件描述符,该文件描述符用于进一步的文件读/写/查找(lseek)操作。通常,文件描述符从3开始,并随着打开的文件数量增加一个数字。
传递给open系统调用的参数是路径名(相对路径或绝对路径),这些标志提到打开文件的目的(例如,打开要读取的O_RDONLY,要写入的O_WRONLY,要读写的O_RDWR并附加到现有文件中) O_APPEND,以创建文件(如果O_CREAT等不存在),以及为用户或所有者/组/其他人提供读/写/执行权限的必需模式。模式可以用符号提及。
读– 4,写– 2和执行– 1。
例如:八进制值(以0开头),0764表示所有者具有读取,写入和执行权限,组具有读取和写入权限,其他具有读取权限。这也可以表示为S_IRWXU |。 S_IRGRP | S_IWGRP | S_IROTH,表示或操作为0700 | 0040 | 0020 | 0004→0764。
成功时,此系统调用将在出现错误的情况下返回新的文件描述符id和-1。可以使用errno变量或perror()函数确定错误原因。
#include
int close(int fd)
上面的系统调用关闭已经打开的文件描述符。这意味着该文件不再使用,并且关联的资源可以由任何其他进程重用。该系统调用成功返回零,如果出错则返回-1。可以使用errno变量或perror()函数确定错误原因。
#include
ssize_t read(int fd, void *buf, size_t count)
上面的系统调用是从指定的文件中读取文件描述符fd的参数,具有已分配内存(静态或动态)的适当缓冲区以及缓冲区的大小。
文件描述符ID用于标识相应的文件,该文件在调用open()或pipe()系统调用之后返回。从文件读取之前,需要先打开文件。如果调用pipe()系统调用,它将自动打开。
如果成功,此调用将返回读取的字节数(如果遇到文件末尾,则返回零),如果失败,则返回-1。在没有数据可用或文件关闭的情况下,返回字节可以小于请求的字节数。如果发生故障,请设置正确的错误编号。
要了解失败的原因,请使用errno变量或perror()函数。
#include
ssize_t write(int fd, void *buf, size_t count)
上面的系统调用是使用文件描述符fd的参数,具有分配的内存(静态或动态)和缓冲区大小的适当缓冲区写入指定的文件。
文件描述符ID用于标识相应的文件,该文件在调用open()或pipe()系统调用之后返回。
写入文件之前,需要先打开文件。如果调用pipe()系统调用,它将自动打开。
如果成功,此调用将返回写入的字节数(如果未写入任何内容,则返回零),如果失败则返回-1。如果发生故障,请设置正确的错误编号。
要了解失败的原因,请使用errno变量或perror()函数。
以下是一些示例程序。
示例程序1-使用管道编写和读取两条消息的程序。
步骤1-创建管道。
步骤2-向管道发送消息。
步骤3-从管道检索消息并将其写入标准输出。
步骤4-将另一条消息发送到管道。
步骤5-从管道中检索消息并将其写入标准输出。
注意-发送所有消息后也可以检索消息。
源代码:simplepipe.c
#include
#include
int main() {
int pipefds[2];
int returnstatus;
char writemessages[2][20]={"Hi", "Hello"};
char readmessage[20];
returnstatus = pipe(pipefds);
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
printf("Writing to pipe - Message 1 is %s\n", writemessages[0]);
write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Reading from pipe – Message 1 is %s\n", readmessage);
printf("Writing to pipe - Message 2 is %s\n", writemessages[0]);
write(pipefds[1], writemessages[1], sizeof(writemessages[0]));
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Reading from pipe – Message 2 is %s\n", readmessage);
return 0;
}
注–理想情况下,每个系统调用都需要检查返回状态。为了简化过程,不对所有呼叫进行检查。
gcc -o simplepipe simplepipe.c
Writing to pipe - Message 1 is Hi
Reading from pipe – Message 1 is Hi
Writing to pipe - Message 2 is Hi
Reading from pipe – Message 2 is Hell
示例程序2-使用父进程和子进程通过管道写入和读取两条消息的程序。
步骤1-创建管道。
步骤2-创建一个子进程。
步骤3-父进程写入管道。
步骤4-子进程从管道中检索消息并将其写入标准输出。
步骤5-再次重复步骤3和步骤4。
源代码:pipewithprocesses.c
#include
#include
int main() {
int pipefds[2];
int returnstatus;
int pid;
char writemessages[2][20]={"Hi", "Hello"};
char readmessage[20];
returnstatus = pipe(pipefds);
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
pid = fork();
// Child process
if (pid == 0) {
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Child Process - Reading from pipe – Message 1 is %s\n", readmessage);
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Child Process - Reading from pipe – Message 2 is %s\n", readmessage);
} else { //Parent process
printf("Parent Process - Writing to pipe - Message 1 is %s\n", writemessages[0]);
write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
printf("Parent Process - Writing to pipe - Message 2 is %s\n", writemessages[1]);
write(pipefds[1], writemessages[1], sizeof(writemessages[1]));
}
return 0;
}
汇编
gcc pipewithprocesses.c –o pipewithprocesses
执行
Parent Process - Writing to pipe - Message 1 is Hi
Parent Process - Writing to pipe - Message 2 is Hello
Child Process - Reading from pipe – Message 1 is Hi
Child Process - Reading from pipe – Message 2 is Hello
管道通信仅被视为单向通信,即,父进程写入而子进程读取,反之亦然,而不是两者都。但是,如果父母和孩子都需要同时写入和读取管道,该解决方案是使用管道的双向通信。需要两条管道来建立双向通信。
以下是实现双向通信的步骤-
步骤1-创建两个管道。第一个是父母写,孩子读,比如pipe1。第二个是让孩子写,父母读,比如pipe2。
步骤2-创建一个子进程。
步骤3-关闭不需要的一端,因为每次通信只需要一端。
步骤4-在父进程中关闭不需要的端,读取pipe1的端并写入pipe2的端。
步骤5-在子进程中关闭不需要的端,写入pipe1的端,并读取pipe2的端。
步骤6-根据需要执行通信。
示例程序1-使用管道实现双向通讯。
步骤1-创建pipe1,以供父进程写入和子进程读取。
步骤2-创建pipe2,以供子进程写入并由父进程读取。
步骤3-从父级和子级关闭管道的多余末端。
步骤4-编写消息的父进程和阅读并显示在屏幕上的子进程。
步骤5-编写消息的子进程和读取和显示在屏幕上的父进程。
源代码:twowayspipe.c
#include
#include
int main() {
int pipefds1[2], pipefds2[2];
int returnstatus1, returnstatus2;
int pid;
char pipe1writemessage[20] = "Hi";
char pipe2writemessage[20] = "Hello";
char readmessage[20];
returnstatus1 = pipe(pipefds1);
if (returnstatus1 == -1) {
printf("Unable to create pipe 1 \n");
return 1;
}
returnstatus2 = pipe(pipefds2);
if (returnstatus2 == -1) {
printf("Unable to create pipe 2 \n");
return 1;
}
pid = fork();
if (pid != 0) // Parent process {
close(pipefds1[0]); // Close the unwanted pipe1 read side
close(pipefds2[1]); // Close the unwanted pipe2 write side
printf("In Parent: Writing to pipe 1 – Message is %s\n", pipe1writemessage);
write(pipefds1[1], pipe1writemessage, sizeof(pipe1writemessage));
read(pipefds2[0], readmessage, sizeof(readmessage));
printf("In Parent: Reading from pipe 2 – Message is %s\n", readmessage);
} else { //child process
close(pipefds1[1]); // Close the unwanted pipe1 write side
close(pipefds2[0]); // Close the unwanted pipe2 read side
read(pipefds1[0], readmessage, sizeof(readmessage));
printf("In Child: Reading from pipe 1 – Message is %s\n", readmessage);
printf("In Child: Writing to pipe 2 – Message is %s\n", pipe2writemessage);
write(pipefds2[1], pipe2writemessage, sizeof(pipe2writemessage));
}
return 0;
}
gcc twowayspipe.c –o twowayspipe
In Parent: Writing to pipe 1 – Message is Hi
In Child: Reading from pipe 1 – Message is Hi
In Child: Writing to pipe 2 – Message is Hello
In Parent: Reading from pipe 2 – Message is Hello