linux历程--管道通信

来源:互联网 发布:免费网络发布平台大全 编辑:程序博客网 时间:2024/05/29 08:25
1)管道概念
   管道是单向的,先进先出的(FIFO),它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道头部读出数据。

2)管道创建
   管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者可用于运行于同一系统中任意两个进程间的通信。
   无名管道由pipe()函数创建:
       int pipe(int fd[2]);
   当一个管道建立时,它会创建两个文件描述符,fd[0]用于读管道,fd[1]用于写管道,即一个管道的头部和尾部的描述符。

3)管道关闭
   关闭管道只需要将这两个文件描述符关闭即可,可以使用普通的close函数逐个关闭。

4)管道读写
   管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。管道创建于内核中,fd[1]创建于父进程中,用于向管道中写数据;fd[0]创建于子进程中,用于从管道中读数据。
   注意:必须在系统调用fork()之前调用pipe(),否则子进程将不会继承文件描述符。如果先调用fork()再调用pipe(),则会创建两个管道,即父子进程各用各的管道,达不到通信的目的。


5)例 pipe_test.c
   #include<unistd.h>
   #include<sys/types.h>
   #include<errno.h>
   #include<stdio.h>
   #include<stdlib.h>
   int main() {
       int pipe_fd[2];
       pid_t pid;
       char buf[100];
       char *p_buf;
       int r_num;

       memset(buf, 0, sizeof(buf));

       //创建管道
       if (pipe(pipe_fd) < 0) {
           printf("pipe create error\n");
           return -1;
       }

       //创建子进程
       if ((pid = fork()) == 0) {
           printf("\n");
           close(pipe_fd[1]);
           sleep(2);  //睡眠2s,等待父进程将数据写入管道
           if ((r_num = read(pipe_fd[0], buf, 100)) > 0) {
               printf("%d numbers read from the pipe is %s\n", r_num, buf);
           }
           close(pipe_fd[0]);
           exit(0);
       } else if (pid > 0) {
           close(pipe_fd[0]);
           if (write(pipe_fd[1], "Hello", 5) != -1) {
               printf("parent process write Hello!\n");
           }
           if (write(pipe_fd[1], " Pipe", 5) != -1) {
               printf("parent process write Pipe!\n");
           }
           close(pipe_fd[1]);
           sleep(3);
           waitpid(pid, NULL, 0);  //等待子进程结束
           exit(0);
       }
   }

6)命令管道(FIFO)
   命名管道和无名管道基本相同,不同点:无名管道只能用于父子进程;但通过命名管道,不相关的进程也能交换数据。

7)FIFO创建
    #include<sys/types.h>
    #include<sys/stat.h>
    int mkfifo(const char *pathname, mode_t mode)
   参数: pathname   FIFO文件名
          mode  属性(与文件操作的mode属性一样)
   一旦创建一个FIFO,就可使用一般的文件访问函数(open、close、
   read、write等)操作FIFO。命名管道实际上就是一个文件。

8)FIFO操作
   当打开FIFO是,不阻塞标志(O_NONBLOCK)将对以后的读写产生如下影响:
     1,没有使用O_NONBLOCK:访问要求无法满足时进程将阻塞。如想要读取空的FIFO就会导致进程阻塞。
     2,使用O_NONBLOCK:访问要求无法满足时不阻塞,立刻出错返回,errno是ENXIO。

9)例:fifo_rd.c和fifo_wr.c(两个进程,所以需要两个文件)
   fifo_rd.c
     #include<sys/types.h>
     #include<sys/stat.h>
     #include<errno.h>
     #include<fcntl.h>
     #include<stdio.h>
     #include<stdlib.h>
     #include<string.h>
     #define FIFO "/tmp/myfifo"
     main(int argc, char **argc) {
         char buf_r[100];
         int fd;
         int read_len;

         //创建管道
         if ((mkfifo(FIFO, O_CREAT | O_EXCL)<0) && (errno!=EEXIST)) {
             printf("can't create fifoserver\n");
         }

         memset(buf_r, 0, sizeof(buf_r));

         //打开管道
         if ((fd = open(FIFO, O_RDONLY | O_NINBLOCK, 0)) == -1) {
             perror("open");
             exit(1);
         }
         while(1) {
             memset(buf_r, 0, sizeof(buf_r));

             if ((read_len=read(fd, buf_r, 100)) == -1) {
                 if (errno == EAGAIN)
                     printf("has not data\n");
             }
             printf("read %s from FIFO\n", buf_r);
             sleep(1);
         }
         pause(); //暂停,等待信号
         unlink(FIFO);
     }   


   fifo_wr.c
     #include<sys/types.h>
     #include<sys/stat.h>
     #include<errno.h>
     #include<fcntl.h>
     #include<stdio.h>
     #include<stdlib.h>
     #include<string.h>
     #define FIFO_SERVER "/tmp/myfifo"
     main(int argc, char **argv) {
         int fd;
         char w_buf[100];
         int write_len;

         //打开管道
         fd = open(FIFO_SERVER, O_WRONLY | O_NONBLOCK, 0);

         if (argc == 1) {
             printf("Please send something\n");
             exit(-1);
         }

         strcpy(w_buf, argv[1]);

         //向管道写入数据
         if ((write_len = write(fd, w_buf, 100)) == -1) {
             if (errno == EAGAIN) {
                 printf("The FIFO has not been read\n");
             }
         } else {
             printf("write %s to the FIFO\n", w_buf);
         }
     }
注意:管道里面的数据被读过之后就会自动清除,即存入和取出。上面两个程序要先运行fifo_rd.c,因为管道在该文件中创建。
原创粉丝点击