zoukankan      html  css  js  c++  java
  • 管道通信(上)

    管道通信(上)

    (一)概述

      Linux Shell 都允许重定向,而重定向使用的就是管道。例如,ps | grep vsftpd 。管道是单向的、先进先出的、无结构的、固定大小的字节流。管道是Linux由Unix那里继承过来的进程间的通信机制,它是Unix早期的一个重要通信机制。其思想是,在内存中创建一个共享文件,从而使通信双方利用这个共享文件来传递信息。由于这种方式具有单向传递数据的特点,所以这个作为传递消息的共享文件就叫做“管道”。它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进程在管道的读端读出数据。数据读出之后将从管道中移走,其他读进程都不能再读到这些数据。管道提供了简单的流控制机制。进程试图读空管道时,在有数据写入管道之前,进程将一直阻塞。同样,管道已经满时,进程在试图写管道,在其他进程从管道中移走数据之前,写进程将一直阻塞。

    (二)匿名管道

      匿名管道是具有共同祖先的进程之间的一种通信方式,因此通常用于父子进程或者兄弟进程之间的通信,在由父进程创建的子进程将会赋值父进程包括文件在内的一些资源。如果父进程创建子进程之前创建了一个文件,那么这个文件的描述符就会被父进程在随后所创建的子进程所共享。也就是说,父、子进程可以通过这个文件进行通信。

     

     参数:长度为2的整型数组

    返回值:成功返回0,失败返回-1,errno会被设置,可以通过perror打印错误信息。

    函数使用示例:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<unistd.h>
     5 int main(int argc, char const *argv[])
     6 {
     7     int fd_pipe[2];
     8     if(pipe(fd_pipe) == -1)
     9     {
    10         perror("pipe");
    11         exit(1);
    12     }
    13     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    14     {
    15         perror("write");
    16         exit(1);
    17     }
    18     char buf[128] = "";
    19     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
    20     {
    21         perror("read");
    22         exit(1);
    23     }
    24     printf("%s
    ",buf);
    25     close(fd_pipe[1]);
    26     close(fd_pipe[0]);
    27     return 0;
    28 }

    运行结果:

     父子进程之间通信示例:父进程从终端读取内容,并将内容发送给子进程。

     1 #include<unistd.h>
     2 #include<stdio.h>
     3 #include<string.h>
     4 #include<stdlib.h>
     5 int main(int argc, char const *argv[])
     6 {
     7     int fd_pipe[2];
     8     pid_t pid;
     9     if(pipe(fd_pipe) == -1)
    10     {
    11         perror("fail to pipe");
    12         exit(1);
    13     }
    14     if((pid = fork()) == -1)
    15     {
    16         perror("Fail to fork");
    17         exit(1);
    18     }
    19     else if (pid > 0)
    20     {
    21         char buf[20] = "";
    22         while (1)
    23         {
    24             if(read(STDIN_FILENO,buf,sizeof(buf)) == -1)
    25             {
    26                 perror("Fail to read from std");
    27                 exit(1);
    28             }
    29             buf[strlen(buf) - 1] = '';
    30             if(write(fd_pipe[1],buf,sizeof(buf)) == -1)
    31             {
    32                 perror("Fail to write to pipe:");
    33                 exit(1);
    34             }
    35             memset(buf,0,sizeof(buf));   
    36         }
    37     }
    38     else if (pid == 0)
    39     {
    40         char buf[128] = "";
    41         while (1)
    42         {
    43             if(read(fd_pipe[0],buf,1024) == -1)
    44             {
    45                 perror("Fail to read:");
    46                 exit(1);
    47             }
    48             printf("read from parent by pipe message is %s
    ",buf);
    49             memset(buf,0,sizeof(buf));
    50         }
    51            
    52     }
    53     return 0;
    54 }

    运行结果:

     (三)匿名管道读写规律

    (1)只读不写——当管道有内容时,读取内容,无内容时会进入阻塞态,当我面修改属性为非阻塞时,程序会直接结束。

    代码:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<string.h>
     5 #include<fcntl.h>
     6 int main(int argc, char const *argv[])
     7 {
     8     int fd_pipe[2];
     9     if(pipe(fd_pipe) == -1)
    10     {
    11         perror("fail to pipe");
    12         exit(1);
    13     }
    14     char buf[128] = "";
    15     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    16     {
    17         perror("write");
    18         exit(1);
    19     }
    20     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
    21     {
    22         perror("fail to read");
    23         exit(1);
    24     }
    25     printf("%s
    ",buf);
    26     memset(buf,0,sizeof(buf));
    27     printf("Read again
    ");
    28     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
    29     {
    30         perror("fail to read");
    31         exit(1);
    32     }
    33     printf("%s
    ",buf);
    34     return 0;
    35 }

    运行结果:

     我们首先在管道内写点数据,进程可以正常的从管道中读取数据,读完之后,管道内没有数据了,此时当我们再读的时候,就会进入阻塞态,我们再试一下,用fcntl使管道为非阻塞,看看会有怎样的效果。

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<string.h>
     5 #include<fcntl.h>
     6 int main(int argc, char const *argv[])
     7 {
     8     int fd_pipe[2];
     9     if(pipe(fd_pipe) == -1)
    10     {
    11         perror("fail to pipe");
    12         exit(1);
    13     }
    14     char buf[128] = "";
    15     fcntl(fd_pipe[0],F_SETFL,O_NONBLOCK);
    16     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    17     {
    18         perror("write");
    19         exit(1);
    20     }
    21     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
    22     {
    23         perror("fail to read");
    24         exit(1);
    25     }
    26     printf("%s
    ",buf);
    27     memset(buf,0,sizeof(buf));
    28     printf("Read again
    ");
    29     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
    30     {
    31         perror("fail to read");
    32         exit(1);
    33     }
    34     printf("%s
    ",buf);
    35     return 0;
    36 }

    (2)只写不读——管道写满之后就会进入阻塞态

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<string.h>
     5 #include<fcntl.h>
     6 int main(int argc, char const *argv[])
     7 {
     8     int fd_pipe[2];
     9     if(pipe(fd_pipe) == -1)
    10     {
    11         perror("fail to pipe");
    12         exit(1);
    13     }
    14     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    15     {
    16         perror("write");
    17         exit(1);
    18     }
    19     printf("write successful
    ");
    20     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    21     {
    22         perror("write");
    23         exit(1);
    24     }
    25     printf("write successful
    ");
    26     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    27     {
    28         perror("write");
    29         exit(1);
    30     }
    31     printf("write successful
    ");
    32     close(fd_pipe[0]);
    33     close(fd_pipe[1]);
    34     return 0;
    35 }

    我们看到,三次都写成功了,但可以一直写吗?而且管道是有大小的,我们可以写多少呢?

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<string.h>
     5 #include<fcntl.h>
     6 int main(int argc, char const *argv[])
     7 {
     8     int fd_pipe[2];
     9     if(pipe(fd_pipe) == -1)
    10     {
    11         perror("fail to pipe");
    12         exit(1);
    13     }
    14     int count = 0;
    15     while (1)
    16     {
    17         char buf[1024] = "";
    18         if(write(fd_pipe[1],buf,sizeof(buf)) == -1)
    19         {
    20             perror("write");
    21             exit(1);
    22         }
    23         count++;
    24         printf("count = %d
    ",count);
    25         sleep(1);
    26     }
    27     
    28     close(fd_pipe[0]);
    29     close(fd_pipe[1]);
    30     return 0;
    31 }

     从程序中不难看出,管道是有大小的,当我们写满之后,就会进入阻塞态。

    (3)只有读端——程序会直接结束

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<string.h>
     5 #include<fcntl.h>
     6 int main(int argc, char const *argv[])
     7 {
     8     int fd_pipe[2];
     9     if(pipe(fd_pipe) == -1)
    10     {
    11         perror("fail to pipe");
    12         exit(1);
    13     }
    14     close(fd_pipe[1]);
    15     char buf[128] = "";
    16     if(read(fd_pipe[0],buf,sizeof(buf)) == -1)
    17     {
    18         perror("read");
    19         exit(1);
    20     }
    21     printf("%s
    ",buf);
    22     close(fd_pipe[0]);
    23     return 0;
    24 }

     按道理来讲,此时读管道应该进入阻塞态的,但由于我们关闭了写端,所以程序就直接结束了。

    (4)只有写端——管道会破裂

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<string.h>
     5 #include<fcntl.h>
     6 int main(int argc, char const *argv[])
     7 {
     8     int fd_pipe[2];
     9     if(pipe(fd_pipe) == -1)
    10     {
    11         perror("fail to pipe");
    12         exit(1);
    13     }
    14     close(fd_pipe[0]);
    15     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    16     {
    17         perror("write");
    18         exit(1);
    19     }
    20     printf("write successful
    ");
    21     close(fd_pipe[1]);
    22     return 0;
    23 }

     我们运行发现程序直接结束了,其实这里大家要知道一点,就是只有写端的时候,我们写内容时是有一个SIGPIPE信号产生的,表明管道破裂了,我们可以通过一个函数——signal()来看。

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<string.h>
     5 #include<fcntl.h>
     6 #include<signal.h>
     7 void hander(int sig)
     8 {
     9     printf("SIGPIPE occurrenced
    ");
    10     exit(1);
    11 }
    12 int main(int argc, char const *argv[])
    13 {
    14     signal(SIGPIPE,hander);
    15     int fd_pipe[2];
    16     if(pipe(fd_pipe) == -1)
    17     {
    18         perror("fail to pipe");
    19         exit(1);
    20     }
    21     close(fd_pipe[0]);
    22     if(write(fd_pipe[1],"hello pipe",strlen("hello pipe")) == -1)
    23     {
    24         perror("write");
    25         exit(1);
    26     }
    27     printf("write successful
    ");
    28     close(fd_pipe[1]);
    29     return 0;
    30 }

  • 相关阅读:
    【转】 UI自动化测试的关注点
    使用MapReduce将HDFS数据导入到HBase(一)
    Hadoop2.4.1 MapReduce通过Map端shuffle(Combiner)完成数据去重
    Hadoop2.4.1 使用MapReduce简单的数据清洗
    Hadoop2.4.1 64-Bit QJM HA and YARN HA + Zookeeper-3.4.6 + Hbase-0.98.8-hadoop2-bin HA Install
    hadoop2.2.0 MapReduce求和并排序
    hadoop2.2.0 MapReduce分区
    hadoop2.2.0伪分布模式64位安装
    hadoop2.2.0 MapReduce的序列化
    MyEclipse8.6下的svn插件安装
  • 原文地址:https://www.cnblogs.com/953-zjf/p/14604198.html
Copyright © 2011-2022 走看看