五、进程间通信-无名管道

1、无名管道

  用于具有亲缘关系的进程间通信(常见的就是父子进程),数据只能单向流动。

(1)创建管道

#include<unistd.h> 
int pipe(int pipefd[2]);
参数:
  • pipefd[2]:参数为两个文件描述符,一个读文件描述符,一个写文件描述符。
返回值:
  • 成功返回0
  • 失败返回-1,且errno错误码被设置。

(2)特点:

  • 特殊文件(没有名字),无法使用open,但是可以使用close.

  • 只能通过子进程继承文件描述符的形式来使用。

  • write和read操作可能会zuse进程。

  • 所有文件描述符被关闭之后,无名管道被销毁。

(3)使用步骤

  • 父进程pipe无名管道

  • fork子进程。

  • close无用端口。

  • write/read读写端口。

  • close读写端口。

 (4)应用实例

#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define MAX_DATA_LEN 256
#define DELAY_TIME 1

/******父进程通过管道传输数据到子进程**********/
int main()
{
    pid_t pid;
    int pipe_fd[2];
    char buf[MAX_DATA_LEN];
    const char data[]  = "Pipe Test Program";
    int real_read,real_write;

    memset((void*)buf,0,sizeof(buf));

    /*创建管道*/
    if(pipe(pipe_fd) < 0)
    {
        printf("pipe create error!\n");
        exit(1);
    }

    /*创建子进程*/
    if((pid=fork()) == 0)  
    {
        /*子进程关闭写文件描述符,并通过使子进程暂停3s等待父进程已关闭相应的读描述符*/
        close(pipe_fd[1]);
        sleep(DELAY_TIME*3);

        /*子进程读取管道内容*/
        if((real_read = read(pipe_fd[0],buf,MAX_DATA_LEN)) > 0)
        {
            printf("%d bytes read from the pipe is '%s'\n",real_read,buf);
        }

        /*关闭子进程读描述符*/
        close(pipe_fd[0]);
        exit(0);
    }
    else if(pid > 0)
    {
        /*关闭父进程读描述符,并通过使父进程暂停1s等待子进程已关闭相应的写描述符*/
        close(pipe_fd[0]);
        sleep(DELAY_TIME);
        if((real_write == write(pipe_fd[1],data,strlen(data)))!= -1)
        {
            printf("Parent write %d bytes:'%s'\n",real_write,data);;
        }
        /*关闭父进程写描述符*/
        close(pipe_fd[1]);

        /*收集子进程退出信息*/
        waitpid(pid,NULL,0);

        exit(0);

    }
    return 0;
}
  • 定义一个数组pipe_fd,在创建匿名管道后通过数组返回管道的文件描述符。

  • 调用pipe()创建一个匿名管道,创建成功则得到两个文件描述符pipe_fd[0]、 pipe_fd[1],否则返回-1。

  • 调用fork()创建一个子进程,如果返回值是0则表示此时运行的是子进程,那么在子进程中调用close()函数关闭写描述符,并使子进程睡眠3s等待父进程已关闭相应的读描述符。

  • 子进程调用read()函数读取管道内容,如果管道没有数据则子进程将被阻塞,读取到数据就将数据打印出来。特别地如果调用read()函数读取一个关闭了写描述符的管道,那么read()会返回0,(本例子中父进程的写描述符没有关闭)。

  • 调用close()函数关闭子进程读描述符。

  • 如果fork()函数的返回值大于0,则表示此时运行的是父进程,那么在父进程中先调用close()关闭管道的读描述符,并且等待1s,因为此时可能子进程先于父进程运行,暂且.等待一会。

  • 父进程调用write()函数将数据写入管道。

  • 关闭父进程写描述符。

  • 调用waitpid()函数收集子进程退出信息并退出进程。

运行结果:

posted @ 2022-04-27 09:08  轻轻的吻  阅读(70)  评论(0编辑  收藏  举报