一、无名管道
1. 什么是管道
一个管道实际上就是个只存在内存中的文件,对这个文件的操作要通过两个已经打开文件进行,它们分别代表管道的两端。管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,有其自己的数据结构,类似时空隧道的概念,建立两个进程之间的通讯桥梁,数据的读出和写入:一个进程向管道写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
2. 无名管道的特性
- 只能用于具有亲缘关系的进程之间的通信,通常一个管道由一个进程创建,然后该进程调用fork,此后父子进程之间就可以通过管道通信。
- 半双工的通信模式
int pipe(int fd[2]);
调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端,一个写端,然后通过fd参数传出给用户程序两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。所以管道在用户程序看起来就像一个打开的文件,通过read(fd[0])或者write(fd[1])向这个文件读写数据,其实是读写内核缓冲区。
注意:
是
输出结果:
1. 测试代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd[2] = {};
pipe(fd); //创建0两个管道,fd[0] 读, fd[1] 写
pid_t pid = fork();
if (pid == 0) { //子进程
close(fd[1]); //关闭写端
int i;
for (i = 0; i < 100; i++) {
int x;
read(fd[0], &x, 4);
printf("%d ", x);
fflush(0);
}
close(fd[0]);
exit(0);
}
close(fd[0]);
int i;
for(i = 100; i < 200; i++) {
write(fd[1], &i, 4);
usleep(100000); //0.1秒
}
close(fd[1]);
return 0;
}
输出结果:
2. 测试代码:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe error");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork error");
exit(-1);
}
if (pid == 0) { //写
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
close(pipefd[0]);
execlp("ls", "ls", NULL);
fprintf(stderr, "error excute ls\n");
exit(EXIT_FAILURE);
}
dup2(pipefd[0], STDIN_FILENO); //读
close(pipefd[1]);
close(pipefd[0]);
execlp("wc", "wc", "-w", NULL);
fprintf(stderr, "error excute wc\n");
exit(EXIT_FAILURE);
}
输出结果:
2. 测试代码:
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
close(0);
open("test.txt", O_RDONLY);
close(1);
open("test2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
execlp("cat", "cat", NULL);
return 0;
}
输出结果:
管道的读写规则
1. 当没有数据可读时:
- O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到位置。
- O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
2. 如果所有管道写端对应的文件描述符被关闭,则read返回0
3. 如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE。
4. 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
5. 当要写入的数据量大于PIPE_BUF时,linux将不再写入的原子性。
1. 测试代码:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe error");
exit(EXIT_FAILURE);
}
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork error");
exit(EXIT_FAILURE);
}
if (pid == 0) {
sleep(3);
close(pipefd[0]);
write(pipefd[1], "hello", 5);
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]);
char buf[10] = { 0 };
read(pipefd[0], buf, 10);
printf("buf = %s\n", buf);
return 0;
}
输出结果:
2. 测试代码:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe error");
exit(EXIT_FAILURE);
}
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork error");
exit(EXIT_FAILURE);
}
if (pid == 0) {
sleep(3);
close(pipefd[0]);
write(pipefd[1], "hello", 5);
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]);
char buf[10] = { 0 };
int flags = fcntl(pipefd[0], F_GETFL);
fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK);
int ret = read(pipefd[0], buf, 10);
if (ret == -1) {
perror("read error");
exit(EXIT_FAILURE);
}
printf("buf = %s\n", buf);
return 0;
}
输出结果:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe error");
exit(EXIT_FAILURE);
}
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork error");
exit(EXIT_FAILURE);
}
if (pid == 0) {
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]);
sleep(1);
char buf[10] = { 0 };
int ret = read(pipefd[0], buf, 10);
printf("ret = %d\n", ret);
return 0;
}
输出结果:
测试代码:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
void handler(int sig)
{
printf("recv a sig = %d\n", sig);
}
int main(int argc, char *argv[])
{
signal(SIGPIPE, handler);
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe error");
exit(EXIT_FAILURE);
}
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork error");
exit(EXIT_FAILURE);
}
if (pid == 0) {
close(pipefd[0]);
exit(EXIT_SUCCESS);
}
close(pipefd[0]);
sleep(1);
char buf[10] = { 0 };
int ret = write(pipefd[1], "hello", 5);
if (ret == -1) {
printf("write error\n");
}
return 0;
}
输出结果:
3. 测试代码:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe error");
exit(EXIT_FAILURE);
}
int ret;
int count = 0;
int flags = fcntl(pipefd[1], F_GETFL);
fcntl(pipefd[1], F_SETFL, flags | O_NONBLOCK);
while (1) {
ret = write(pipefd[1], "A", 1);
if (ret == -1) {
printf("err = %s\n", strerror(errno));
break;
}
count++;
}
printf("count = %d\n", count);
return 0;
}
输出结果: