管道的使用

管道的使用

管道用在Linux的进程通信中,只能用在具有血缘关系的进程中。管道本质就是一段内存缓冲区,一个进程有写权限,另一个有读权限。

在c/c++中,我们可以使用pipe创建一个管道。show you the code:

int pipe (int fd[2]);

// 参数
// fd[0] : 读端
// fd[1] : 写端
#include <stdio.h>
#include <unistd.h>

int main() {

  int fd[2];
  pipe(fd);

  int pid = fork();
  if (pid == 0) {
    // 子进程
    int num;
    // 关闭管道的写端口
    close(fd[1]);
    while (read(fd[0], &num, sizeof(int)) != 0) {
      printf("num %d\n", num);
    }
    // 关闭管道的读端口
    close(fd[0]);

  } else if (pid > 0) {
    // 关闭管道的读端口
    close(fd[0]);
    for (int i = 1; i <= 10; i++) {
      write(fd[1], &i, sizeof(i));
    }
     // 关闭管道的写端口
    close(fd[1]);
  }

  return 0;
}

最后输出--1 2 .... 10。

需要创建一个数组,用pipe函数将数组变为管道。变为管道后,fd[0]是读的端口,fd[1]是写的端口。这里父进程通过管道向子进程输入数字,然后子进程打印数字。因为父进程是要写,所以写之前要关闭读的端口close fd[0],然后通过写端口将数字传入子进程,写完之后要关闭写的端口close fd[1],防止子进程读取的时候发生阻塞使子程序一直运行
 

write()read()的使用方法:

  • wirte()

第一个参数是管道的写端口(记的之前要关闭管道的读端口,读完之后关闭管道的写端口),第二个参数是需要写入的数据的地址,第三个参数是写入数据的大小。

  • read()

第一个参数是管道的读端口(记的之前要关闭管道的写端口,读完之后关闭管道的读端口),第二个参数是需要将读取的数据放在的地址,第三个参数是读取数据的大小。

注意:

  • 1、wirte()之前关闭管道的读端口,读完之后关闭管道的写端口
  • 2、read()之前要关闭管道的写端口,读完之后关闭管道的读端口

缺点:

  • 1、单工通信。只能一个进程写,一个进程读,如果要双向通信需要创建两个管道。
  • 2、只有有血缘关系的进程才可以通信。

四种特殊情况

  • 当管道的所有写端的描述符都关闭了,还要进程在读取,read()会返回一个0。
#include <stdio.h>
#include <unistd.h>
#include <wait.h>

int main() {

  int fd[2];
  pipe(fd);
  int status = -1;

  int pid = fork();
  if (pid == 0) {
    close(fd[1]);
    int i;
    while (1) {
      ssize_t ret = read(fd[0], &i, sizeof(i));
      if (ret == 0) {
        printf("pipe is empty\n");
        return 0;
      }
      printf("%d ", i);
    }
    close(fd[0]);
  } else if (pid > 0) {
    // 父进程
    close(fd[0]);
    for (int i = 1; i <= 10; i++) {
      write(fd[1], &i, sizeof(i));
    }
    close(fd[1]);
    wait(&status);
  }

  return 0;
}

最后输出1 2 3 4 5 6 7 8 9 10 pipe is empty

THE END