系统编程之管道篇

管道(一)

一、

q 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

q 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

q 只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道

二、匿名管道pipe  

q 包含头文件<unistd.h>

q 功能:创建一无名管道

q 原型

q intpipe(int fd[2]);

q 参数

q fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端

q 返回值:成功返回0,失败返回错误代码

//01pipe.c

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int pipefd[2];

         if (pipe(pipefd) == -1)

                   ERR_EXIT("pipeerror");

 

         pid_t pid;

         pid = fork();

         if (pid == -1)

                   ERR_EXIT("forkerror");

 

         if (pid == 0)

         {

                   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;

 

}

 

//02pipe.c

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int pipefd[2];

         if (pipe(pipefd) == -1)

                   ERR_EXIT("pipeerror");

 

         pid_t pid;

         pid = fork();

         if (pid == -1)

                   ERR_EXIT("forkerror");

 

         if (pid == 0)

         {

                   dup2(pipefd[1],STDOUT_FILENO);

                   close(pipefd[1]);

                   close(pipefd[0]);

                   execlp("ls","ls", NULL);

                   fprintf(stderr, "errorexecute ls\n");

                   exit(EXIT_FAILURE);

         }

 

         dup2(pipefd[0], STDIN_FILENO);

         close(pipefd[0]);

         close(pipefd[1]);

         execlp("wc", "wc","-w", NULL);

         fprintf(stderr, "error executewc\n");

         exit(EXIT_FAILURE);

 

}

 

//03cp.c

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int pipefd[2];

         if (pipe(pipefd) == -1)

                   ERR_EXIT("pipeerror");

 

         pid_t pid;

         pid = fork();

         if (pid == -1)

                   ERR_EXIT("forkerror");

 

         if (pid == 0)

         {

                   dup2(pipefd[1],STDOUT_FILENO);

                   close(pipefd[1]);

                   close(pipefd[0]);

                   execlp("ls","ls", NULL);

                   fprintf(stderr, "errorexecute ls\n");

                   exit(EXIT_FAILURE);

         }

 

         dup2(pipefd[0], STDIN_FILENO);

         close(pipefd[0]);

         close(pipefd[1]);

         execlp("wc", "wc","-w", NULL);

         fprintf(stderr, "error executewc\n");

         exit(EXIT_FAILURE);

 

}

 

管道(二)

一、当没有数据可读时

q O_NONBLOCKdisableread调用阻塞,即进程暂停执行,一直等到有数据来到为止。

q O_NONBLOCKenableread调用返回-1errno值为EAGAIN

 

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int pipefd[2];

         if (pipe(pipefd) == -1)

                   ERR_EXIT("pipeerror");

 

         pid_t pid;

         pid = fork();

         if (pid == -1)

                   ERR_EXIT("forkerror");

 

         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)

                   ERR_EXIT("readerror");

         printf("buf=%s\n", buf);

        

         return 0;

 

}

 

 

 

二、当管道满的时候

q O_NONBLOCKdisable write调用阻塞,直到有进程读走数据

q O_NONBLOCKenable:调用返回-1errno值为EAGAIN

三、如果所有管道写端对应的文件描述符被关闭,则read返回0

 

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int pipefd[2];

         if (pipe(pipefd) == -1)

                   ERR_EXIT("pipeerror");

 

         pid_t pid;

         pid = fork();

         if (pid == -1)

                   ERR_EXIT("forkerror");

 

         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;

 

}

 

四、如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE

 

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

voidhandler(int sig)

{

         printf("recv a sig=%d\n",sig);

}

 

intmain(int argc, char *argv[])

{

         signal(SIGPIPE, handler);

         int pipefd[2];

         if (pipe(pipefd) == -1)

                   ERR_EXIT("pipe error");

 

         pid_t pid;

         pid = fork();

         if (pid == -1)

                   ERR_EXIT("forkerror");

 

         if (pid == 0)

         {

                   close(pipefd[0]);

                   exit(EXIT_SUCCESS);

         }

 

         close(pipefd[0]);

         sleep(1);

         int ret = write(pipefd[1],"hello", 5);

         if (ret == -1)

                   printf("writeerror\n");

        

         return 0;

 

}

 

五、当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

intmain(int argc, char *argv[])

{

         int pipefd[2];

         if (pipe(pipefd) == -1)

                   ERR_EXIT("pipe error");

 

         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;

}

 

 

 

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<unistd.h>

#include<sys/types.h>

#include<errno.h>

#include<fcntl.h>

 

 

#defineERR_EXIT(m) \

        do \

        { \

                perror(m); \

                exit(EXIT_FAILURE); \

        } while(0)

 

#defineTEST_SIZE 68*1024

 

intmain(void)

{

         char a[TEST_SIZE];

         char b[TEST_SIZE];

 

         memset(a, 'A', sizeof(a));

         memset(b, 'B', sizeof(b));

 

         int pipefd[2];

 

         int ret = pipe(pipefd);

         if (ret == -1)

                   ERR_EXIT("pipeerror");

 

         pid_t pid;

         pid = fork();

         if (pid == 0)

         {

                   close(pipefd[0]);

                   ret = write(pipefd[1], a,sizeof(a));

                   printf("apid=%d write %dbytes to pipe\n", getpid(), ret);

                   exit(0);

         }

 

         pid = fork();

 

        

         if (pid == 0)

         {

                   close(pipefd[0]);

                   ret = write(pipefd[1], b,sizeof(b));

                   printf("bpid=%d write %dbytes to pipe\n", getpid(), ret);

                   exit(0);

         }

 

 

         close(pipefd[1]);

        

         sleep(1);

         int fd = open("test.txt",O_WRONLY | O_CREAT | O_TRUNC, 0644);

         char buf[1024*4] = {0};

         int n = 1;

         while (1)

         {

                   ret = read(pipefd[0], buf,sizeof(buf));

                   if (ret == 0)

                            break;

                   printf("n=%02d pid=%dread %d bytes from pipe buf[4095]=%c\n", n++, getpid(), ret, buf[4095]);

                   write(fd, buf, ret);

 

         }

         return 0; 

}

 

管道(三)

 

一、命名管道

q 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。

q 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。

q 命名管道是一种特殊类型的文件

二、创建一个命名管道

q 命名管道可以从命令行上创建,命令行方法是使用下面这个命令:

                            $ mkfifo filename

q 命名管道也可以从程序里创建,相关函数有:

         int mkfifo(const char *filename,mode_tmode);

一、匿名管道与命名管道

q 命名管道可以从命令行上创建,命令行方法是使用下面这个命令:

                            $ mkfifo filename

q 命名管道也可以从程序里创建,相关函数有:

         int mkfifo(const char *filename,mode_tmode);

二、命名管道的打开规则

q 如果当前打开操作是为读而打开FIFO

q O_NONBLOCKdisable:阻塞直到有相应进程为写而打开该FIFO

q O_NONBLOCKenable:立刻返回成功

q 如果当前打开操作是为写而打开FIFO

q O_NONBLOCKdisable:阻塞直到有相应进程为读而打开该FIFO

q O_NONBLOCKenable:立刻返回失败,错误码为ENXIO

//02fifor.c

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int fd;

/*     fd = open("p1", O_RDONLY);*/

         fd = open("p1", O_RDONLY |O_NONBLOCK);

        

         if (fd == -1)

                   ERR_EXIT("openerror");

 

         printf("open succ\n");

         return 0;

}

 

//03fifow.c

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include <string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int fd;

         /*fd = open("p1",O_WRONLY);*/

         fd = open("p1", O_WRONLY |O_NONBLOCK);

         if (fd == -1)

                   ERR_EXIT("openerror");

 

         printf("open succ\n");

         return 0;

}

 

三、命名管道示例程序

 

//04fifor.c

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         mkfifo("tp", 0644);

         int infd;

         infd = open("Makefile",O_RDONLY);

         if (infd == -1)

                   ERR_EXIT("open");

        

         int outfd;

         outfd = open("tp", O_WRONLY);

         if (outfd == -1)

                   ERR_EXIT("open");

 

         char buf[1024];

         int n;

         while ((n=read(infd, buf, 1024))>0)

         {

                   write(outfd, buf, n);

         }

         close(infd);

         close(outfd);

         return 0;

}

 

//05fifow.c

#include<unistd.h>

#include<sys/stat.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<fcntl.h>

 

#include<stdlib.h>

#include<stdio.h>

#include<errno.h>

#include<string.h>

#include<signal.h>

#include<sys/time.h>

 

 

#defineERR_EXIT(m) \

         do \

         { \

                   perror(m); \

                   exit(EXIT_FAILURE); \

         } while(0)

 

 

intmain(int argc, char *argv[])

{

         int outfd;

         outfd = open("Makefile2",O_WRONLY | O_CREAT | O_TRUNC, 0644);

         if (outfd == -1)

                   ERR_EXIT("open");

        

         int infd;

         infd = open("tp", O_RDONLY);

         if (outfd == -1)

                   ERR_EXIT("open");

 

         char buf[1024];

         int n;

         while ((n=read(infd, buf, 1024))>0)

         {

                   write(outfd, buf, n);

         }

         close(infd);

         close(outfd);

         unlink("tp");

         return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值