进程间通信方式介绍-管道

来源:互联网 发布:mac伴奏降调 编辑:程序博客网 时间:2024/04/30 10:02

1.进程间通信的方式:

(1)管道:一种两个进程间进行单向通信的机制,半双工的通信方式。数据只能单方向流动,而且只能在具有亲缘关系(父子进程、兄弟进程)的进程间使用。

   从通信的双方信息交互的方式分三种基本模式:

   单工通信(单向通信) 只有一个方向的通信而没有反方向的交互(信息流是单方向的),发送端和接收端的身份是固定的;

   半双工通信(双向交替通信)双方均可以发送、接收信息,但是同一时刻里,信息只能有一个传输方向;

   全双工通信(双向同时通信) 双方可以同时发送和接收信息。

(2)有名管道:(FIFO)半双工的通信方式,克服了只能有亲缘关系的进程通信的限制。

(3)信号量;4)消息队列;(5)信号(chapter 9);(6)共享内存;7)套接字。

2.管道的概念

管道:两个进程间进行单向通信的机制(半双工管道)

     局限性:由于管道传递数据的单向性,决定其使用的局限性:数据的单向流动;有亲缘关系的进程间的通信;没有名字;缓冲区大小受限制(传送的是无格式的字节流)

     管道就是一个存在于内存的特殊文件,进程就是通过读写该文件进行通信的(内存中的某个页面作为数据缓冲区)

 如果要建立两个进程的数据通路,首先父进程应调用pipe创建管道,接着调用fork,由于子进程自动继承父进程的数据段,便可实现父子进程同时拥有管道的操作权,如下图(a),但为了维护管道,比如想要一个父进程到子进程的数据通道时,在父进程中关闭读出端,子进程中关闭管道的写入端,图(b)。

进程间通信--管道通信                       进程间通信--管道通信

       (a)                                                                       (b)

通过管道进行的父/子进程通信(半双工通信)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>

//读管道
void read_from_pipe(int fd)
{
    charmessage[100];

   read(fd,message,100);       
    printf("readfrom pipe:%s",message);
}

//写管道
void write_to_pipe(int fd)
{
    char*message = "hello,pipe!\n";

   write(fd,message,strlen(message)+1);
}

int main(void)
{
    intfd[2];
    pid_tpid;
    intstat_val;

   //先创建管道,再创建子进程
   if(pipe(fd))
    {
      printf("create pipe failed!\n");
      exit(1);
    }

    pid =fork();

   switch(pid)
    {
       case -1:
          printf("forkerror!\n");
         exit(1);
      case  0 :
         //子进程关闭写端
         close(fd[1]);
         read_from_pipe(fd[0]);
         exit(0);
      default:
         //关闭父进程的读端
         close(fd[0]);
         write_to_pipe(fd[1]);
         wait(&stat_val);     //??
         exit(0);                 
    }

    return0;
}

//建立两个管道来实现全双工通信
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>

void child_rw_pipe(int rfd,int wfd)
{
    char*message1 = "This pipe two,I am child process and I can write butcannot read!!\n";
    charmessage2[100];

   write(wfd,message1,strlen(message1)+1);

   read(rfd,message2,100);
   printf("child process read from pipe one:%s:",message2);
}

void parent_rw_pipe(int rfd,int wfd)
{
    char*message1 = "This pipe one,I am parent process and I can write butcannot read!!\n";
    charmessage2[100];

   write(wfd,message1,strlen(message1)+1);

   read(rfd,message2,100);
   printf("parent process read from pipe two:%s",message2);
}

int main(void)
{
    intfd1[2],fd2[2];
    pid_tpid;
    intstat_val;

   printf("There are two pipes\n");

   //管道1实现父进程写,子进程读
   if(pipe(fd1))
    {
      printf("create pipe1 failed\n");
      exit(1);
    }

   //管道2实现子进程写,父进程读
   if(pipe(fd2))
    {
      printf("create pipe2 failed\n");
      exit(1);
    }

    pid =fork();
   switch(pid)
    {
       case-1:
         printf("create process failed!!\n");
         exit(1);
       case0:
          //子进程
         close(fd1[1]);   //关闭管道1的写端
         close(fd2[0]);   //关闭管道2的读端
         child_rw_pipe(fd1[0],fd2[1]);
         exit(0);
      default:
          //父进程
         close(fd1[0]);   //关闭管道1的读端
         close(fd2[1]);   //关闭管道2的写端
         parent_rw_pipe(fd2[0],fd1[1]);
         wait(&stat_val);
         exit(0);
    }
}

 

通过管道模拟shell命令:

cat file|sort

通过一个管道,将”cat file”的结果通过管道送给命令”sort”。需要用dup()或者dup2()系统调用将标准输入和标准输出联系起来,这里的”catfile”和”sort”命令不是自己来完成,而是通过调用exec函数族来实现的。

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>

int main(void)
{
 

   intfd[2];
    pid_tpid;
    intstat_val;

   if(pipe(fd))
    {
      perror("create pipe failed!\n");
      exit(0);
    }

    pid =fork();
   switch(pid)
    {
       case-1:
         perror("create process failed!\n");
         exit(1);
       case0:
         dup2(0,fd[0]);           //关闭标准输入,从管道读取内容
         close(fd[1]);            //子进程关闭管道的写端
          printf("I amchild program!\n");
          if(execlp("sort","sort",NULL))
            perror("execlp error!\n");
         exit(0);
      default:
         dup2(1,fd[1]);         //关闭标准输出,将要写到标准输出的内容写入管道
         close(fd[0]);          //父进程关闭管道的读端
          printf("Thisis  parent process!\n");
         if(execlp("cat","cat","a.txt",NULL))
            perror("execlp error!\n");
         wait(&stat_val);