进程间通信——匿名管道

目录

  • 内容
    • 匿名管道的特点
    • 匿名管道的创建
    • 几个简单使用场景
  • 总结

内容

匿名管道的特点

  • 只能用于有亲缘关系的进程间的通信;
  • 内部类似一个队列结构,0 为队头,1 为队尾。

匿名管道的创建

#include
int pipe(int pipefd[2]);
description: pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication. The array pipefd
is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the read end of the pipe. pipefd[1] refers to the
write end of the pipe. Data written to the write end of the pipe is buffered by the kernel until it is read from the read end of the pipe. For
further details, see pipe(7).
return value: On success, zero is returned. On error, -1 is returned, errno is set to indicate the error, and pipefd is left unchanged.

几个简单使用场景

  1. 单进程环境
  2. 父子进程环境
  3. 父子进程 + epoll 实例
#include 
#include 
#include 

#include 

#define MSG_MAX_LEN 1024

int main(){

    int fd[2] = {0};	// 0 为读端,1 为写端
    int ret;

    ret = pipe(fd);		// 创建匿名管道
    if(ret){
        perror("pipe()");
        exit(1);
    }


#if 0
    char msg[] = "Hello";
    write(fd[1], msg, strlen(msg));		// 1 端写数据
    
    char recv_buff[MSG_MAX_LEN];
    memset(recv_buff, 0, sizeof(recv_buff));
    read(fd[0], recv_buff, MSG_MAX_LEN);	// 0 端可以读出数据

    puts(recv_buff);
#elif 0
    pid_t pid;
    
    pid = fork();	// fork 出一个子进程
    if(pid < 0){
        perror("fork()");
        exit(1);
    }else if(pid == 0){     // child
    	// 子进程往管道写数据

        char msg[] = "Hello World!\n";
        
        write(fd[1], msg, strlen(msg));

        printf("pid[%d] : send OK!\n", getpid());

    }else{      // parent
    	// 父进程可以成功读出数据

        char recv_msg[MSG_MAX_LEN];
        memset(recv_msg, 0, sizeof(recv_msg));

        read(fd[0], recv_msg, MSG_MAX_LEN);

        printf("pid[%d] : recv OK!\n", getpid());
        printf("recv_msg : %s\n", recv_msg);

    }

#else

#include

    pid_t pid;

    pid = fork();
    if(pid < 0){
        perror("fork()");
        exit(1);
    }else if(pid == 0){     // child

        int i = 0;
        for(i = 0; i < 1024; i++){
			// 子进程每秒往管道中写一条数据
            char msg[] = "Hello World!\n";

            write(fd[1], msg, strlen(msg));

            printf("pid[%d] : msg[%d] send OK!\n", getpid(), i);
            sleep(1);
        }

    }else{      // parent
		
		// 创建一个 epoll 来管理父进程读数据,即每次子进程发来的数据都会触发一次读时间
		int epfd;
        epfd = epoll_create(1);
        if (epfd < 0)
        {
            perror("epoll_create()");
            exit(1);
        }

        struct epoll_event ev;
        memset(&ev, 0, sizeof(ev));
		
		// 为 fd[0] 注册读事件,并加到 epoll 中
        ev.events = EPOLLIN | EPOLLET;	// 设置为边缘 ET 触发,因为子进程每次发来的数据量很小,且父进程读缓冲区很大。
        ev.data.fd = fd[0];
        if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd[0], &ev) < 0)
        {
            perror("epoll_ctl()");
            exit(1);
        }

        while(1){
            
            struct epoll_event events[16];

            int nready = epoll_wait(epfd, events, 16, -1);	// 等待事件的到来

            if(nready <= 0){	// epoll_wait 返回小于 0 的值,出错处理
                perror("epoll_wait()");
                exit(1);
            }
            int i = 0;
            for(i = 0; i < nready; i++){	// 逐个处理被触发的事件

                if(events[i].events & EPOLLIN){	// 处理读事件
                    
                    char recv_msg[MSG_MAX_LEN];
                    memset(recv_msg, 0, sizeof(recv_msg));

                    read(fd[0], recv_msg, MSG_MAX_LEN);

                    printf("pid[%d] : recv OK!\n", getpid());
                    printf("recv_msg : %s\n", recv_msg);

                }
                if(events[i].events & EPOLLOUT){	// 逻辑上没有写事件,不用处理

                }

            }
        }
    }

#endif

    exit(0);
}

总结

  1. 简单实现了匿名管道的几种使用方法;
  2. 尝试用 epoll 来管理管道的事件。

你可能感兴趣的:(进程间通信,c++,linux,c语言)