IPC 进程间通信---半双工管道

2019-02-15  本文已影响0人  一只肥豚鼠

管道相关的关键概念

管道是Linux支持的最初Unix IPC形式之一,具有以下特点:

管道的创建

#include <unistd.h>
int pipe(int fd[2])

管道的读写规则

管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等(从本质上说,管道也是一种文件,但它又和一般的文件有所不同,可以克服使用文件进行通信的两个问题,这个文件只存在内存中)。

从管道中读取数据:

关于管道的读规则验证:

代码

/**
 *  半双工管道 
 *  管道的读写规则
 **/
#include <iostream>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <cstring>

const int PIPE_CREATE_ERROR = -1;

int main(int argc, char const *argv[])
{
    int pipe_fd[2];
    pid_t pid;
    char r_buf[100];
    char w_buf[100];
    char *p_wbuf;
    int r_num;
    int cmd;
    memset(r_buf, 0x00, sizeof(r_buf));
    memset(w_buf, 0x00, sizeof(w_buf));
    p_wbuf = w_buf;

    if(pipe(pipe_fd) < 0)
    {
        std::cerr << "pipe create error: " << strerror(errno) << std::endl;
        return PIPE_CREATE_ERROR;
    }

    if((pid=fork()) == 0)
    {
        std::cout << std::endl;
        close(pipe_fd[1]);
        sleep(3);
        r_num=read(pipe_fd[0], r_buf, 100);
        std::cout << "read num is " << r_num
                  << " the data read from the pipe is " << r_buf << std::endl;
        close(pipe_fd[0]);
        exit(0);
    }
    else if(pid > 0)
    {
        close(pipe_fd[0]);
        std::string message("Hey, my son, i am send a message to you now!");
        strcpy(w_buf, message.c_str());
        if(write(pipe_fd[1], w_buf, message.length() + 1) != -1)
        {
            std::cout << "parent write over\n" << std::endl;
        }
        close(pipe_fd[1]);
        std::cout << "parent close fd[1] over" << std::endl;
        sleep(10);
    }

    return 0;
}

结果

parent write over

parent close fd[1] over

read num is 45 the data read from the pipe is Hey, my son, i am send a message to you now!

向管道中写入数据:

对管道的写规则的验证1:写端对读端存在的依赖性

代码:

/**
 * 对管道的写规则的验证1:写端对读端存在的依赖性
 * 关闭子进程的读端和写端,关闭父进程的读端,使得父进程的写端无法写入数据
 **/

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <cstring>
#include <signal.h>


const int PIPE_CREATE_ERROR = -1;

void pipe_break_handler(int)
{
    std::cout << "Broken pipe" << std::endl;
}

int main(int argc, char const *argv[])
{
    int pipe_fd[2];
    pid_t pid;
    char r_buf[4];
    char* w_buf;
    int writenum;
    int cmd;
    signal(SIGPIPE, pipe_break_handler);
    memset(r_buf, 0x00, sizeof(r_buf));
    if(pipe(pipe_fd) < 0)
    {
        std::cerr << "pipe create error" << std::endl;
        return PIPE_CREATE_ERROR;
    }

    if((pid=fork()) == 0)
    {
        close(pipe_fd[0]);
        close(pipe_fd[1]);
        sleep(10);
        exit(0);
    }
    else if(pid > 0)
    {
        sleep(1);
        close(pipe_fd[0]);
        w_buf="hey";
        if((writenum = write(pipe_fd[1], w_buf, 4)) == -1)
        {
            std::cout << "write to  pipe error" << std::endl;
        }
        else
        {
            std::cout << "The bytes write to pipe is %d " << writenum << std::endl;
        }
        close(pipe_fd[1]);
    }
    return 0;
}

结果

Broken pipe
write to  pipe error

对管道的写规则的验证2:linux不保证写管道的原子性验证

代码

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <cerrno>
#include <cstring>

const int PIPE_CREATE_ERROR = -1;

int main(int argc, char const *argv[])
{
    int pipe_fd[2];
    pid_t pid;
    char r_buf[4096];
    char w_buf[4096*2];
    int writenum;
    int rnum;
    memset(r_buf, 0x00, sizeof(r_buf));
    if(pipe(pipe_fd) < 0)
    {
        std::cerr << "pipe create error" << std::endl;
        return PIPE_CREATE_ERROR;
    }

    if((pid=fork()) == 0)
    {
        close(pipe_fd[1]);
        while(true)
        {
            sleep(1);
            rnum = read(pipe_fd[0], r_buf, 1000);
            std::cout << "child: readnum is " << rnum << std::endl;
        }
        close(pipe_fd[0]);
        exit(0);
    }
    else if(pid > 0)
    {
        close(pipe_fd[0]);
        memset(r_buf, 0x00, sizeof(r_buf));
        if((writenum = write(pipe_fd[1], w_buf, 1024)) == -1)
        {
            std::cerr << "write to pipe error" << std::endl;
        }
        else
        {
            std::cout << "the bytes write to pipe is " << writenum << std::endl;
        }
        writenum=write(pipe_fd[1], w_buf, 4096);
        close(pipe_fd[1]);
    }
    return 0;
}

结果

the bytes write to pipe 1000
the bytes write to pipe 1000
the bytes write to pipe 1000
the bytes write to pipe 1000
the bytes write to pipe 1000
the bytes write to pipe 120
the bytes write to pipe 0
the bytes write to pipe 0
上一篇下一篇

猜你喜欢

热点阅读