linux进程间通信之管道

下面几节,将分别温习下linux进程进通信的几种机制

1:管道

管道是比较古老的进程间的通信方式。主要有有名管道和无名管道两种。

2:无名管道

它的特点就是:
1:只能使用在具有亲缘关系的进程之间的通信(父子进程或者兄弟进程之间)。因为只有具有亲缘关系的进程才能继承其创建的文件描述符。
2:是一个半双工的通信模式,具有固定的读端和写段。
3:可以将管道看着特殊的文件,也可以调用read()和write()操作。

管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1],其中fd[0]是固定用于读管道, 而fd[1]是固定用于写管道,构成一个半双工通道。
这里写图片描述
当一个管道共享多对文件描述符时,若将其中的一对读写文件描述符都删除,则该管道将失效。

这里写图片描述

上面插图来自《linux应用程序开发标准教程》中,从图中可以看到当fork()后 , 子进程会继承父进程创建的管道,这样父子进程都拥有了自己的读写通道, 从而实现了父子之间的读写,只需要把无关的读端或写段的文件描述符关闭即可。

 例如上图中,父进程负责读段,则把它的写段fd[1]关闭, 子进程负责写,则把它的读段fd[0]关掉。这样就建立起来一条“子进程写父进程读”的通道。

  下面来看一下无名管道的实例,直接上代码:
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>


#define MAX_DATA_LEN 128
#define DELAY_TIME 1

int main()
{

    pid_t pid;
    int pipe_fd[2];
    char buf[MAX_DATA_LEN] = {0};
    const char data[] ="Pipe Test Program";
    int real_read, real_write;

    if( pipe(pipe_fd) < 0)
    {
        printf("Pipe create error\n");
        exit(1);
    }

    if((pid = fork()) == 0)
    {
        /* clode write fd */
        close(pipe_fd[1]);
        sleep(DELAY_TIME *3);

        if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0)
        {
            printf("Read data from pipe is %s\n", buf);
        }

        close(pipe_fd[0]);
        exit(0);
     } else if (pid > 0)
     {
         /*close read fd*/
         close(pipe_fd[0]);
         sleep(DELAY_TIME);

         if ((real_write = write(pipe_fd[1], data,  strlen(data))) != -1)
         {
             printf("Write to pipe is: %s\n", data);
         }
          {
        /* clode write fd */
        close(pipe_fd[1]);
        sleep(DELAY_TIME *3);

        if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0)
        {
            printf("Read data from pipe is %s\n", buf);
        }

        close(pipe_fd[0]);
        exit(0);
     } else if (pid > 0)
     {
         /*close read fd*/
         close(pipe_fd[0]);
         sleep(DELAY_TIME);

         if ((real_write = write(pipe_fd[1], data,  strlen(data))) != -1)
         {
             printf("Write to pipe is: %s\n", data);
         }
         close(pipe_fd[1]);
         waitpid(pid, NULL, 0); 
         exit(0);
      }   

      return 0;
}

  运行结果:
  Write to pipe is: Pipe Test Program
  Read data from pipe is Pipe Test Program

3:有名管道

有名管道突破了无名管道的限制,可以使两个不相关的进程实现彼此之间的通信。相当于创建一个文件,建立管道之后,两个进程可以把它当做普通文件一样进行读写操作。严格遵循先进先出规则,对管道及FIFO的读写总是从开始出返回数据,对它们的写则把数据添加到末尾,需要指出的是不支持lseek()等文件定位操作。
可以采用mkdfifo()函数来创建一个命名管道,创建成功后就可以使用open, read, write函数进行操作。

mkfifo函数原型:
int mkfifo(const char *filename, mode_t mode)
传参:
     filename为要创建的管道,包括路径名
     mode只创建的管道权限,一般有O_RDONLY(读管道), O_WRONLY(写管道),O_RDWR(读写管道),O_NONBLOCK:非堵塞管道。 O_CREAT(如果文件不存在,则新建文件),O_EXCL:可以测试文件是否存在。

下面来看一个有名管道的例子,为了方便看代码,直接将命名管道应用在父子进程间通信:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#define MYFIFO "myfifo"


#define MAX_DATA_LEN 128
#define DELAY_TIME 1

int main()
{

    pid_t pid;
    int pipe_fd[2];
    char buf[MAX_DATA_LEN] = {0};
    const char data[] ="Pipe Test Program";
    int real_read, real_write;
    int fd = 0;

   // memset((void *)buf, 0, sizeof(buf));
    if(access(MYFIFO, F_OK) == -1) 
    {   
        if ((mkfifo(MYFIFO, 0666) < 0) )
                  printf("Can not create fifo file\n");
            exit(1);
        }
    }

    if((pid = fork()) == 0)
    {
        /* open write fifo */
        fd= open(MYFIFO,O_WRONLY);
        if ( fd == -1)
        {
            printf("Open write file error\n");
            exit(1);
        }

        if(write(fd, data, strlen(data)) > 0)
        {
            printf("Write %s to FIFO\n", data);
        }

        close(fd);

        exit(0);
     } else if (pid > 0)
     {
         /*open write fifo */
         fd = open(MYFIFO, O_RDONLY);
         if (fd == -1)
         {
             printf("Open fifo error\n");
             exit(1);
         }

         if(read(fd, buf, MAX_DATA_LEN) > 0)
         {
             printf("Read %s from FIFO\n", buf);
         }

         close(fd);

         exit(0);
      }

      return 0;
}

运行结果:
Write Pipe Test Program to FIFO
Read Pipe Test Program from FIFO

下一节将温习信号的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值