实现进程间通信:匿名管道和命名管道

通信:因为进程有强大独立性,当想把自己数据交给另一个进程,需要通信。

创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站制作、成都网站设计、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的金凤网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

通信本质:让不同进程看到相同资源。

实现进程间通信:匿名管道和命名管道

  1. 匿名管道:管道:通过某种机制传递资源(数据),匿名管道只适用于有血缘关系的进程,一般用于父,子进程通信。

    a.创建管道

    b.创建子进程

    c.父,子进程关闭自己不需要的文件描述符

    注意:匿名管道提供单向通信,父读子写或父写子读,若要实现双向通信,可再创建一个管道。

#include
#include
#include
#include
#include
int main()
{
    int _pipefd[2]={-1,-1};
    int ret=pipe(_pipefd);
    if(ret==-1)
    {
        perror("pipe");
        return 2;
    }
    pid_t id=fork();
    if(id<0)
    {
        perror("fork");
        return 2;
    }
    else if(id==0)
     {
        close(_pipefd[0]);
        char buf[]="hello world";
        int count=5;
        while(count--)
        {
            write(_pipefd[1],buf,strlen(buf));
            sleep(1);
        }
    }
    else
     {  
       close(_pipefd[1]);
       char buf[1024]={0};
       while(1)
        {
          memset(buf,'\0',sizeof(buf));
          ssize_t _size=read(_pipefd[0],buf,sizeof(buf)-1);
          if(_size>0)
          {
               buf[_size]='\0';
               printf("buf:%s\n",buf);
          }    
        }
    }
    return 0; 
}

运行结果:实现进程间通信:匿名管道和命名管道

使用管道需注意以下四种情况:

1.如果所有指向管道写端的文件描述符都关闭了,仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 int main()
  7 {
  8     int _pipefd[2]={-1,-1};
  9     int ret=pipe(_pipefd);
 10     if(ret==-1)
 11     {
 12         perror("pipe");
 13         return 2;
 14     }
 15
 16     pid_t id=fork();
 17     if(id<0)
 18     {
 19         perror("fork");
 20         return 2;
 21     }
 22     else if(id==0)
 23      {
 24         close(_pipefd[0]);
 25         char buf[]="hello world";
 26         int count=5;
 27         int i=0;
 28         while(count--)
 29         {
 30             if(i==3)
 31             {
 32                 printf("I want sleep\n");
 33                 break;
 34             }
 35             write(_pipefd[1],buf,strlen(buf));
 36             sleep(1);
 37             i++;
 38         }
 39         close(_pipefd[0]);
 40     }
 41     else
 42     {
 43         close(_pipefd[1]);
 44         char buf[1024]={0};
 46         while(1)
 47         {
 48             memset(buf,'\0',sizeof(buf));
 49             ssize_t _size=read(_pipefd[0],buf,sizeof(buf)-1);
 50             if(_size>0)
 51             {
 52                   buf[_size]='\0';
 53                 printf("buf:%s\n",buf);
 54             }
 55         }
 56     }
 57     return 0;
 58 }

运行结果:实现进程间通信:匿名管道和命名管道

2.如果有指向管道写端的文件描述符没关闭,持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 int main()
  8 {
  9     int _pipefd[2]={-1,-1};
 10     int ret=pipe(_pipefd);
 11     if(ret==-1)
 12     {
 13         perror("pipe");
 14         return 2;
 15     }
 16 
 17     pid_t id=fork();
 18     if(id<0)
 19     {
 20         perror("fork");
 21         return 2;
 22     }
 23     else if(id==0)
 24     {
 25         close(_pipefd[0]);
 26         char buf[]="hello world";
 27         int count=5;
 28         int i=0;
 29         while(count--)
 30         {
 31              if(i==3)
 32              {
 33                   printf("I want sleep\n");
 34                   sleep(10);
 35              }
 36              write(_pipefd[1],buf,strlen(buf));
 37              sleep(1);
 38              i++;
 39         }
 40         close(_pipefd[0]);
 41     }
 42     else
 43     {
 44         close(_pipefd[1]);
 45         char buf[1024]={0};
 46         while(1)
 47         {
 48             memset(buf,'\0',sizeof(buf));
 49             ssize_t _size=read(_pipefd[0],buf,sizeof(buf)-1);
 50             if(_size>0)
 51             {
 52                 buf[_size]='\0';
 53                 printf("buf:%s\n",buf);
 54             }
 55         }
 56     }
 57     return 0;
 58 }

运行结果:

实现进程间通信:匿名管道和命名管道

实现进程间通信:匿名管道和命名管道

3.如果所有指向管道读端的文件描述符都关闭了,这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 int main()
  8 {
  9     int _pipefd[2]={-1,-1};
 10     int ret=pipe(_pipefd);
 11     if(ret==-1)
 12     {
 13         perror("pipe");
 14         return 2;
 15     }
 16 
 17     pid_t id=fork();
 18     if(id<0)
 19     {
 20         perror("fork");
 21         return 2;
 22     }
 23     else if(id==0)
 24     {
 25         close(_pipefd[0]);
 26         char buf[]="hello world";
 27         int count=5;
 28         while(count--)
 29         {
 30              write(_pipefd[1],buf,strlen(buf));
 31              sleep(1);
 32         }
 33         close(_pipefd[0]);
 34     }
 35     else
 36     {
 37         close(_pipefd[1]);
 38         char buf[1024]={0};
 39         int i=5;
 40         while(i--)
 41         {
 42             if(i==3)
 43             {
 44                 close(_pipefd[0]);
 45             }
 46             memset(buf,'\0',sizeof(buf));
 47             ssize_t _size=read(_pipefd[0],buf,sizeof(buf)-1);
 48             if(_size>0)
 49             {
 50                 buf[_size]='\0';
 51                 printf("buf:%s\n",buf);
 52             }
 53         }
 54         int status=0;
 55         pid_t _pid=waitpid(id,&status,0);
 56         printf("waitpid: %d,return status:%d\n",id,status&0xff);
 57     }
 58     //printf("%d ,%d \n",_pipefd[0],_pipefd[1]);
 59     return 0;
 60 }

运行结果:

实现进程间通信:匿名管道和命名管道

实现进程间通信:匿名管道和命名管道

4.如果有指向管道读端的文件描述符没关闭,持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。 

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 int main()
  8 {
  9     int _pipefd[2]={-1,-1};
 10     int ret=pipe(_pipefd);
 11     if(ret==-1)
 12     {
 13         perror("pipe");
 14         return 2;
 15     }
 16 
 17     pid_t id=fork();
 18     if(id<0)
 19     {
 20         perror("fork");
 21         return 2;
 22     }
 23     else if(id==0)
 24     {
 25         close(_pipefd[0]);
 26         char buf[]="hello world";
 27         int count=5;
 28         while(count--)
 29         {
 30              write(_pipefd[1],buf,strlen(buf));
 31              sleep(1);
 32         }
 33         close(_pipefd[0]);
 34     }
 35     else
 36     {
 37         close(_pipefd[1]);
 38         int status=0;
 39         pid_t wait=waitpid(id,&status,0);
 40         if(wait==id)
 41            printf("wait:%d,status:%d\n",wait,status);
 42     }
 43     return 0;
 44 }

总结匿名管道特点:

  1. 单向通信,适用于有血缘关系的进程通信。

  2. 管道提供流式服务(数据按序,不规定一次读多少)

  3. 管道内部有保证数据读完(完整性)。

  4. 进程间同步

通过路径看到共同资源

  1. 在shell下交互的建立

  2. 调用函数

//client:
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 int main()
  9 {
 10     umask(0);
 11     int fd=mkfifo("./.tmp",S_IFIFO|0666);
 12     if(fd<0)
 13     {
 14         perror("mkfifo");
 15         exit(1);
 16     }
 17     int _fd=open("./.tmp",O_WRONLY);
 18     if(_fd<0)
 19     {
 20         perror("mkfifo");
 21         exit(1);
 22     }
 23     while(1)
 24     {
 25     char buf[1024];
 26     fflush(stdout);
 27     memset(buf,'\0',sizeof(buf));
 28     printf("client:");
 29     size_t size=read(0,buf,sizeof(buf)-1);
 30     buf[size]='\0';
 31     write(_fd,buf,strlen(buf));
 32     }
 33     return 0;
 34 }
//server:
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 int main()
  9 {
 10     int _fd=open("./.tmp",O_RDONLY);
 11     if(_fd<0)
 12     {
 13         perror("open");
 14         exit(1);
 15     }
 16     char buf[1024];
 17     while(1)
 18     {
 19         memset(buf,'\0',sizeof(buf));
 20         ssize_t _size=read(_fd,buf,sizeof(buf)-1);
 21         if(_size>0)
 22         {
 23             buf[_size]='\0';
 24             printf("server:%s",buf);
 25         }
 26         else
 27         {
 28             printf("read error\n");
 29             break;
 30         }
 31     }
 32     close(_fd);
 33     return 0;
 34 }
//Makefile编写:
 .PHONY:all
  2 all:client server
  3
  4 client:client.c
  5     gcc -o $@ $^
  6 server:server.c
  7     gcc -o $@ $^
  8 .PHONY:clean
  9 clean:
 10     rm -f client server .tmp

结果验证:打开两个终端,不同进程可以通信。

实现进程间通信:匿名管道和命名管道


文章名称:实现进程间通信:匿名管道和命名管道
文章来源:http://ybzwz.com/article/gghseh.html