标签:style blog http io ar color os sp for
管道基本概念
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
如:ps aux | grep httpd | awk ‘{print $2}‘
管道示意图
管道的本质
固定大小的内核缓冲区
管道限制
1)管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
2)匿名管道只能用于具有共同祖先的进程(如父进程与fork出的子进程)之间进行通信;[通常,一个管道由一个进程创建,然后该进程调用fork,此后父子进程共享该管道]
匿名管道pipe
- SYNOPSIS
- #include <unistd.h>
- int pipe(int pipefd[2]);
功能
创建无名管道
参数
Pipefd:文件描述符数组,其中pipefd[0]表示读端,pipefd[1]表示写端
管道创建示意图
- void err_exit(string str);
-
- int main()
- {
- int pipefd[2];
- if (pipe(pipefd) == -1)
- err_exit("pipe error");
-
- pid_t pid;
- if ((pid = fork()) < 0)
- err_exit("fork error");
- if (pid == 0)
- {
- close(pipefd[0]);
-
- dup2(pipefd[1],STDOUT_FILENO);
-
- close(pipefd[1]);
-
- execlp("/bin/ls","/bin/ls",NULL);
-
-
- fprintf(stderr,"Child: execlp error");
- exit(0);
- }
-
-
- close(pipefd[1]);
-
- dup2(pipefd[0],STDIN_FILENO);
-
- close(pipefd[0]);
- execlp("/usr/bin/wc","/usr/bin/wc","-w",NULL);
-
-
- fprintf(stderr,"Parent: execlp error");
-
- return 0;
- }
-
- void err_exit(string str)
- {
- perror(str.c_str());
- exit(EXIT_FAILURE);
- }
示例:管道编程实践
- void err_exit(string str);
-
- int main()
- {
- int pipefd[2];
- int ret;
- if ((ret = pipe(pipefd)) != 0)
- {
- err_exit("pipe error");
- }
-
- pid_t pid = fork();
- if (pid == -1)
- {
- err_exit("fork error");
- }
-
- if (pid == 0)
- {
- close(pipefd[0]);
- string str("I Can Write Pipe from Child!");
-
- write(pipefd[1],str.c_str(),str.size());
- close(pipefd[1]);
- exit(0);
- }
-
-
- close(pipefd[1]);
- char buf[1024];
- memset(buf,0,sizeof(buf));
- read(pipefd[0],buf,sizeof(buf));
- cout << "Read from pipe: " << buf << endl;
- close(pipefd[0]);
-
- return 0;
- }
-
- void err_exit(string str)
- {
- perror(str.c_str());
- exit(EXIT_FAILURE);
- }
匿名管道读写规则
1)管道空时
O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
2)管道满时
O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
3)管道不停被写,写满
O_NONBLOCK disable: write调用阻塞(Block)
O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
- int main()
- {
- int pipefd[2];
- int ret;
- if ((ret = pipe(pipefd)) != 0)
- {
- err_exit("pipe error");
- }
-
- pid_t pid = fork();
- if (pid == -1)
- {
- err_exit("fork error");
- }
-
- if (pid == 0)
- {
- sleep(10);
- close(pipefd[0]);
- string str("I Can Write Pipe from Child!");
-
- write(pipefd[1],str.c_str(),str.size());
- close(pipefd[1]);
- exit(0);
- }
-
-
- close(pipefd[1]);
- char buf[1024];
- memset(buf,0,sizeof(buf));
-
-
- int flags = fcntl(pipefd[0],F_GETFL);
- flags |= O_NONBLOCK;
- ret = fcntl(pipefd[0],F_SETFL,flags);
- if (ret != 0)
- {
- err_exit("Set UnBlock error");
- }
-
- int readCount = read(pipefd[0],buf,sizeof(buf));
- if (readCount < 0)
- {
-
- err_exit("read error");
- }
- cout << "Read from pipe: " << buf << endl;
- close(pipefd[0]);
-
- return 0;
- }
4)如果所有管道写端对应的文件描述符被关闭,则read返回0
- int main()
- {
- int pipefd[2];
- int ret;
- if ((ret = pipe(pipefd)) != 0)
- {
- err_exit("pipe error");
- }
-
- pid_t pid = fork();
- if (pid == -1)
- {
- err_exit("fork error");
- }
-
- if (pid == 0)
- {
-
- close(pipefd[0]);
- close(pipefd[1]);
- exit(0);
- }
-
-
- sleep(1);
- close(pipefd[1]);
- char buf[1024];
- memset(buf,0,sizeof(buf));
-
- int readCount = read(pipefd[0],buf,sizeof(buf));
- if (readCount == 0)
- {
- cout << "OK, read 0 byte" << endl;
- }
- close(pipefd[0]);
-
- return 0;
- }
5)如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE
- void onSignalAction(int signalNumber)
- {
- switch(signalNumber)
- {
- case SIGPIPE:
- cout << "receive signal SIGPIPE: " << signalNumber << endl;
- break;
- default:
- cout << "other signal" << endl;
- break;
- }
- }
-
- int main()
- {
- if (signal(SIGPIPE,onSignalAction) != 0)
- {
- err_exit("signal error");
- }
-
- int pipefd[2];
- int ret;
- if ((ret = pipe(pipefd)) != 0)
- {
- err_exit("pipe error");
- }
-
- pid_t pid = fork();
- if (pid == -1)
- {
- err_exit("fork error");
- }
-
- if (pid == 0)
- {
-
- sleep(1);
- close(pipefd[0]);
- string str("I Can Write Pipe from Child!");
-
- write(pipefd[1],str.c_str(),str.size());
- close(pipefd[1]);
- exit(0);
- }
-
-
- close(pipefd[1]);
- close(pipefd[0]);
-
- wait(NULL);
- return 0;
- }
Linux PIPE特征
1)当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性。
2)当要写入的数据量大于PIPE_BUF时,Linux将不再保证写入的原子性。
- int main()
- {
- int pipefd[2];
- int ret = pipe(pipefd);
- if (ret < 0)
- {
- err_exit("pipe error");
- }
-
- int flags = fcntl(pipefd[1],F_GETFL);
- flags |= O_NONBLOCK;
- ret = fcntl(pipefd[1],F_SETFL,flags);
- if (ret < 0)
- {
- err_exit("fcntl error");
- }
-
-
- unsigned int countForTestPipe = 0;
- while (true)
- {
- ret = write(pipefd[1],"a",1);
- if (ret < 0)
- {
- break;
- }
- ++ countForTestPipe;
- }
-
- cout << "size = " << countForTestPipe << endl;
- }
-
附-管道容量查询
man 7 pipe
附-深入理解文件描述符
- int main()
- {
- close(STDIN_FILENO);
- if (open("readfile.txt",O_RDONLY) == -1)
- {
- err_exit("open read error");
- }
- close(STDOUT_FILENO);
- if (open("writefile.txt",O_WRONLY|O_TRUNC|O_CREAT,0644) == -1)
- {
- err_exit("open write error");
- }
-
- if (execlp("/bin/cat","/bin/cat",NULL) == -1)
- {
- err_exit("execlp error");
- }
-
- return 0;
- }
Linux管道(匿名PIPE)
标签:style blog http io ar color os sp for
原文地址:http://www.cnblogs.com/yuyanbian/p/4120881.html