面试题答案
一键面试创建区别
- 无名管道:使用
pipe
函数创建,其函数原型为int pipe(int pipefd[2]);
,该函数在内核中创建一个管道,并返回两个文件描述符pipefd[0]
(读端)和pipefd[1]
(写端)。例如:
#include <stdio.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
// 后续可进行读写操作
close(pipefd[0]);
close(pipefd[1]);
return 0;
}
- 有名管道:使用
mkfifo
函数创建,函数原型为int mkfifo(const char *pathname, mode_t mode);
,pathname
是管道的路径名,mode
指定管道的权限。例如在命令行中可以使用mkfifo myfifo
创建一个名为myfifo
的有名管道,在程序中:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main() {
if (mkfifo("myfifo", 0666) == -1) {
perror("mkfifo");
return 1;
}
// 后续可进行读写操作
return 0;
}
使用场景区别
- 无名管道:主要用于具有亲缘关系(如父子进程)的进程间通信。例如,父进程创建一个子进程,通过无名管道父进程可以向子进程发送数据,或者子进程向父进程汇报结果。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main() {
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return 1;
} else if (pid == 0) { // 子进程
close(pipefd[1]); // 关闭写端
char buffer[1024];
ssize_t bytes_read = read(pipefd[0], buffer, sizeof(buffer));
if (bytes_read == -1) {
perror("read");
return 1;
}
buffer[bytes_read] = '\0';
printf("子进程读到: %s\n", buffer);
close(pipefd[0]);
} else { // 父进程
close(pipefd[0]); // 关闭读端
const char *msg = "Hello, child!";
ssize_t bytes_written = write(pipefd[1], msg, strlen(msg));
if (bytes_written == -1) {
perror("write");
return 1;
}
close(pipefd[1]);
}
return 0;
}
- 有名管道:不仅可以用于亲缘关系的进程间通信,还可以用于没有亲缘关系的进程间通信。比如一个客户端进程和一个服务端进程,它们可以通过有名管道进行数据交互。例如有一个写端程序:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
int fd = open("myfifo", O_WRONLY);
if (fd == -1) {
perror("open");
return 1;
}
const char *msg = "Data from writer";
ssize_t bytes_written = write(fd, msg, strlen(msg));
if (bytes_written == -1) {
perror("write");
return 1;
}
close(fd);
return 0;
}
以及一个读端程序:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("myfifo", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
char buffer[1024];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read == -1) {
perror("read");
return 1;
}
buffer[bytes_read] = '\0';
printf("读到: %s\n", buffer);
close(fd);
return 0;
}
读写特性区别
- 无名管道:
- 半双工通信,数据只能在一个方向上流动,要么读要么写。
- 如果管道写端关闭,读端读取完管道中剩余数据后,再次
read
会返回0,表示文件结束。 - 如果管道读端关闭,写端继续
write
会产生SIGPIPE
信号,默认情况下进程会终止。
- 有名管道:
- 同样是半双工通信。
- 当所有写端关闭时,读端读取完数据后,再次
read
会返回0。 - 当读端不存在时,以
O_WRONLY
方式打开有名管道,open
操作会阻塞,直到有读端打开该管道;如果以O_WRONLY | O_NONBLOCK
方式打开,open
会立即返回 -1,并设置errno
为ENXIO
。