使用两个有名管道实现双向通信
使用两个有名管道(FIFO)实现双向通信。父进程负责写入信息到管道,子进程负责从管道读取信息并显示到终端上。使用信号处理来确保进程在接收到 “quit” 命令时正确退出。
进程A
#include <myhead.h>
// 信号处理函数,收到信号时退出
void handle_signal(int sig) {
exit(EXIT_SUCCESS);
}
int main(int argc, const char *argv[]) {
signal(SIGTERM, handle_signal); // 注册信号处理函数
pid_t pid;
pid = fork();
if (pid > 0) { // 父进程, 发送信息
char buff[1024];
int send = open("./path1", O_WRONLY);
if (send == -1) {
perror("open send");
return -1;
}
while (1) {
memset(buff, 0, sizeof(buff));
int len = read(0, buff, sizeof(buff));
write(send, buff, len); // 写入管道
if (strcmp(buff, "quit\n") == 0) {
kill(getpid(), SIGTERM); // 通知子进程退出
break;
}
}
close(send);
exit(EXIT_SUCCESS);
} else if (pid == 0) { // 子进程,读取信息
char buff[1024];
int receive = open("./path2", O_RDONLY);
if (receive == -1) {
perror("open receive");
return -1;
}
while (1) {
memset(buff, 0, sizeof(buff));
int len = read(receive, buff, sizeof(buff)); // 读取管道数据
write(1, buff, len);
if (strcmp(buff, "quit\n") == 0) {
kill(getppid(), SIGTERM); // 通知父进程退出
break;
}
}
close(receive);
exit(EXIT_SUCCESS);
} else {
perror("fork");
return -1;
}
return 0;
}
进程B
#include <myhead.h>
// 信号处理函数,收到信号时退出
void handle_signal(int sig) {
exit(EXIT_SUCCESS);
}
int main(int argc, const char *argv[]) {
signal(SIGTERM, handle_signal); // 注册信号处理函数
pid_t pid;
pid = fork();
if (pid > 0) { // 父进程, 发送信息
char buff[1024];
int send = open("./path2", O_WRONLY);
if (send == -1) {
perror("open send");
return -1;
}
while (1) {
memset(buff, 0, sizeof(buff));
int len = read(0, buff, sizeof(buff));
write(send, buff, len); // 写入管道
if (strcmp(buff, "quit\n") == 0) {
kill(getpid(), SIGTERM); // 通知子进程退出
break;
}
}
close(send);
exit(EXIT_SUCCESS);
} else if (pid == 0) { // 子进程,读取信息
char buff[1024];
int receive = open("./path1", O_RDONLY);
if (receive == -1) {
perror("open receive");
return -1;
}
while (1) {
memset(buff, 0, sizeof(buff));
int len = read(receive, buff, sizeof(buff)); // 读取管道数据
write(1, buff, len);
if (strcmp(buff, "quit\n") == 0) {
kill(getppid(), SIGTERM); // 通知父进程退出
break;
}
}
close(receive);
exit(EXIT_SUCCESS);
} else {
perror("fork");
return -1;
}
return 0;
}
代码解释
进程A
-
信号处理函数:
void handle_signal(int sig) { exit(EXIT_SUCCESS); }
- 当接收到
SIGTERM
信号时,进程会调用handle_signal
函数并退出。
- 当接收到
-
注册信号处理函数:
signal(SIGTERM, handle_signal);
- 注册
SIGTERM
信号的处理函数。
- 注册
-
创建子进程:
pid_t pid; pid = fork();
-
父进程(发送信息):
if (pid > 0) { // 打开管道 int send = open("./path1", O_WRONLY); // 读取标准输入并写入管道 while (1) { int len = read(0, buff, sizeof(buff)); write(send, buff, len); if (strcmp(buff, "quit\n") == 0) { kill(getpid(), SIGTERM); // 通知子进程退出 break; } } close(send); exit(EXIT_SUCCESS); }
-
子进程(读取信息):
else if (pid == 0) { // 打开管道 int receive = open("./path2", O_RDONLY); // 从管道读取数据并显示到终端 while (1) { int len = read(receive, buff, sizeof(buff)); write(1, buff, len); if (strcmp(buff, "quit\n") == 0) { kill(getppid(), SIGTERM); // 通知父进程退出 break; } } close(receive); exit(EXIT_SUCCESS); }
进程B
-
信号处理函数:
void handle_signal(int sig) { exit(EXIT_SUCCESS); }
- 当接收到
SIGTERM
信号时,进程会调用handle_signal
函数并退出。
- 当接收到
-
注册信号处理函数:
signal(SIGTERM, handle_signal);
- 注册
SIGTERM
信号的处理函数。
- 注册
-
创建子进程:
pid_t pid; pid = fork();
-
父进程(发送信息):
if (pid > 0) { // 打开管道 int send = open("./path2", O_WRONLY); // 读取标准输入并写入管道 while (1) { int len = read(0, buff, sizeof(buff)); write(send, buff, len); if (strcmp(buff, "quit\n") == 0) { kill(getpid(), SIGTERM); // 通知子进程退出 break; } } close(send); exit(EXIT_SUCCESS); }
-
子进程(读取信息):
else if (pid == 0) { // 打开管道 int receive = open("./path1", O_RDONLY); // 从管道读取数据并显示到终端 while (1) { int len = read(receive, buff, sizeof(buff)); write(1, buff, len); if (strcmp(buff, "quit\n") == 0) { kill(getppid(), SIGTERM); // 通知父进程退出 break; } } close(receive); exit(EXIT_SUCCESS); }
运行步骤
-
创建命名管道:
#include<myhead.h> int main (int argc, const char *argv[]) { if(mkfifo("./path1",0644)==-1){ perror("path1"); return -1; } if(mkfifo("./path2",0644)==-1){ perror("path2"); return -1; } return 0; }
-
编译两个程序:
gcc usr2.c -o u1 gcc usr2.c -o u2
-
分别在两个终端窗口中运行两个程序:
./u1
和
./u2
总结
这篇博客展示了如何使用两个有名管道实现双向通信。父进程负责写入信息到管道,子进程负责从管道读取信息并显示到终端上。还使用了信号处理来确保进程在接收到 “quit” 命令时正确退出。