管道随进程
匿名管道是存在于内存中的特殊文件
特点:
          1.单向
          2.有血缘关系的进程间通信
          3.实现进程间同步
          4.提供“流式服务”



匿名管道的实现:
test.c
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
int main()
{
  int _pipe[2];
  int ret=pipe(_pipe);
  if(ret==-1)
  {
    printf("create pipe error!error code is:%d\n",errno);
    return 1;
  }
  pid_t id=fork();
  if(id<0)   //create fail
  {
    printf("fork error!\n");
    return 2;
  }
  else if(id==0)  //child
  {
    close(_pipe[0]);
    int i=0;
    char* _mesg_c=NULL;
    while(i<100)
    {
      _mesg_c="i am a child!";
      write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);
      sleep(1);
      i++;
    }
  }
  else  //father
  {
    close(_pipe[1]);
    char _mesg[100];
    int j=0;
    while(j<100)
    {
      memset(_mesg,'\0',sizeof(_mesg));
      read(_pipe[0],_mesg,sizeof(_mesg));
      printf("%s\n",_mesg);
      j++;
    }
  }
  return 0;
}

使用管道要注意以下四种情况(假设都是阻塞 I/O操作,没有设置O_NONBLOCK标志)


1、所有指向写端的文件描述符都关闭了,而仍有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样
test1.c
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
  int _pipe[2];
  int ret=pipe(_pipe);
  if(ret==-1)
  {
    printf("create pipe error!error code is:%d\n",errno);
    return 1;
  }
  pid_t id=fork();
  if(id<0)   //create fail
  {
    printf("fork error!\n");
    return 2;
  }
  else if(id==0)  //child
  {
    close(_pipe[0]);
    int i=0;
    char* _mesg_c=NULL;
    while(i<10)
    {
      _mesg_c="i am a child!";
      write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);
      sleep(1);
      i++;
    }
    close(_pipe[1]);
  }
  else  //father
  {
    close(_pipe[1]);
    char _mesg[100];
    int j=0;
    while(j<100)
    {
      memset(_mesg,'\0',sizeof(_mesg));
      int ret=read(_pipe[0],_mesg,sizeof(_mesg));
      printf("%s:code is:%d\n",_mesg,ret);
      j++;
    }
    if(waitpid(id,NULL,0)<0)
    {
      return 3;
    }
  }
  return 0;
}
结果:
     i am a child!:code is:14  (10行)
     :code is:0  (90行)
     
     Program exited normally.

2、如果有指向管道写端的文件描述符没关闭,而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
test2.c:
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
  int _pipe[2];
  int ret=pipe(_pipe);
  if(ret==-1)
  {
    printf("create pipe error!error code is:%d\n",errno);
    return 1;
  }
  pid_t id=fork();
  if(id<0)   //create fail
  {
    printf("fork error!\n");
    return 2;
  }
  else if(id==0)  //child
  {
    close(_pipe[0]);
    int i=0;
    char* _mesg_c=NULL;
    while(i<20)
    {
       if(i<10)
      {
        _mesg_c="i am a child!";
        write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);
      }
        sleep(1);
        i++;
    }
  }
  else  //father
  {
    close(_pipe[1]);
    char _mesg[100];
    int j=0;
    while(j<20)
    {
      memset(_mesg,'\0',sizeof(_mesg));
      int ret=read(_pipe[0],_mesg,sizeof(_mesg));
      printf("%s:code is:%d\n",_mesg,ret);
      j++;
    }
    if(waitpid(id,NULL,0)<0)
    {
      return 3;
    }
  }
  return 0;
}
结果:
     i am a child!:code is:14  (10行)
     :code is:0  (10行)
     
     Program exited normally.
    
3、如果所有指向管道读端的文件描述符都关闭了,这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
test3.c:
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
  int _pipe[2];
  int ret=pipe(_pipe);
  if(ret==-1)
  {
    printf("create pipe error!error code is:%d\n",errno);
    return 1;
  }
  pid_t id=fork();
  if(id<0)   //create fail
  {
    printf("fork error!\n");
    return 2;
  }
  else if(id==0)  //child
  {
    close(_pipe[0]);
    int i=0;
    char* _mesg_c=NULL;
    while(i<20)
    {
      if(i<10)
      {
        _mesg_c="i am a child!";
        write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);
      }
      sleep(1);
      i++;
    }
  }
  else  //father
  {
    close(_pipe[1]);
    char _mesg[100];
    int j=0;
    while(j<3)
    {
      memset(_mesg,'\0',sizeof(_mesg));
      int ret=read(_pipe[0],_mesg,sizeof(_mesg));
      printf("%s:code is:%d\n",_mesg,ret);
      j++;
    }
    close(_pipe[0]);
    sleep(10);
    if(waitpid(id,NULL,0)<0)
    {
      return 3;
    }
  }
  return 0;
}
结果:
     i am a child!:code is:14
     i am a child!:code is:14
     i am a child!:code is:14
     
     Program exited normally.
     
4、如果有指向管道读端的文件描述符没关闭,而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么管道被写满时,再次write会阻塞,直到管道中有空位置了才写入数据并返回。
test4.c
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
  int _pipe[2];
  int ret=pipe(_pipe);
  if(ret==-1)
  {
    printf("create pipe error!error code is:%d\n",errno);
    return 1;
  }
  pid_t id=fork();
  if(id<0)   //create fail
  {
    printf("fork error!\n");
    return 2;
  }
  else if(id==0)  //child
  {
    close(_pipe[0]);
    int i=0;
    char* _mesg_c=NULL;
    while(i<20)
    {
        _mesg_c="i am a child!";
        write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);
        sleep(1);
        i++;
    }
  }
  else  //father
  {
    close(_pipe[1]);
    char _mesg[100];
    int j=0;
    while(j<20)
   {
      if(j<3)
      {
        memset(_mesg,'\0',sizeof(_mesg));
        int ret=read(_pipe[0],_mesg,sizeof(_mesg));
        printf("%s:code is:%d\n",_mesg,ret);
      }
      sleep(1);
      j++;
   }
    if(waitpid(id,NULL,0)<0)
    {
      return 3;
    }
  }
  return 0;
}
结果:
     i am a child!:code is:14
     i am a child!:code is:14
     i am a child!:code is:14
     
     Program exited normally.