Process Communication - Pipeline

一、无名管道

参考:
1、
https://www.cnblogs.com/zhangxuan/p/6704915.html
2, https://www.cnblogs.com/kunhu/p/3608109.html

Basic understanding pipeline:
1, based on the pipe file descriptor , the establishment of the pipe, there are two file descriptors:
2, the pipeline mechanism is the standard input and standard output between a connecting process of the two, to provide a let kinds of communications between multiple processes method when the process creates a pipe, each will need to provide two file descriptors to operate the pipeline. One of the pipeline write operation, read operation of another pipeline. Reading and writing of the pipeline system is consistent with the general IO function, using write () function to write data, read () from the read data.
                                          
3, pipe () function

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

Return Value: success, returns 0, otherwise it returns -1. Parameter array comprising two pipe file descriptors used.
fd [0]: Read the pipe, fd [1]: write pipeline. Pipe must be called at fork () in (), otherwise the child will not inherit the file descriptors .

General Procedure:
1. pipe () to create the pipe
2. fork () to create a subprocess
3. The child process inherits the parent process pipe
4. The pipe is closed: one by closing the file descriptor, close ().
Pipeline communication between the parent and child processes: parent and child to each have their own pipeline of read-write channel, the end-independent reading or writing sections closed.
Master function pipe (), read (), write (), close ().

Examples 1.1

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>
#define MAX_LINE 80
int main()
{
    int thePipe[2], ret;
    //数组thePipe被填入两个有效的文件描述符。thePipe[0]固定于读管道,thePipe[1]固定于写管道
    char buf[MAX_LINE+1];
    const char *testbuf="a test string.";
    if ( pipe( thePipe ) == 0 )
    {
        printf("thePipe[0]=%d, thePipe[1]=%d \n", thePipe[0], thePipe[1]);
        if (fork() == 0)
        {//child 进程
            close(thePipe[1]);
            ret = read( thePipe[0], buf, MAX_LINE );
            printf("read ret=%d \n", ret);
            buf[ret] = 0;
            printf( "Child read %s\n", buf );
        }
        else
        {//parent 进程
            close(thePipe[0]);
            ret = write( thePipe[1], testbuf, strlen(testbuf) );
            printf("write ret=%d \n", ret);
            ret = wait( NULL );
            printf("wait ret=%d \n", ret);
        }
    }
    //逐个关闭文件描述符
    close(thePipe[0] );
    close(thePipe[1] );
    return 0;
}

The result:

added:

1, file identifier
thePipe, usually denoted by fd, can be understood as the address of the file , the file identifier is int, FILE * equivalent to the role, but he is an int. In essence, this very unique int, with open function, int fd which kept the address of the file you want to operate, but it is yet not int *, after the write and read function must be specified depending on the direction of the fd, you can be found write, read parameter has a place to fill in the fd, it may be required to fill in, but it is an int variable, in which there are no windows, but people do not understand the document identifier, see the write and read use may be foggy, not to mention after the close, is clearly associated with the operation of the fd file.

2, read function
header file: #include <unistd.h>
function: for reading data from the file descriptor corresponding to (or reading data from the device to open the file)
an ssize_t Read (FD int, void * buf, size_t count)
parameters: fd: is the file descriptor buf: for the read data buffer; count: the number of bytes read at a time (the number of bytes read request, the read data stored in the buffer up buf region while reading and writing the current file position set back)

. 3, function Write
function is defined: ssize_t write (int fd, const void * buf, size_t count);
function Description: write () will buf parameter referred memory write parameter count bytes to the file on referred

4, wait () function returns a child's PID.

Examples 1.2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_DATA_LEN 256
#define DELAY_TIME 1
int main()
{
    pid_t pid;//进程pid
    char buf[MAX_DATA_LEN];//数据缓冲区
    const char *data="Pipe Test program";
    int real_read,real_write;
    int pipe_fd[2];
    memset((void*)buf,0,sizeof(buf));//初始化
    if(pipe(pipe_fd)<0)//返回值为-1,创建管道失败
    {
        perror("Pipe create error!\n");
        exit(1);
    }
    if ((pid=fork())<0)
    {
        perror("Fork error!\n");
        exit(1);
    }
    else if (pid==0)
    {//child 进程
        //printf("hhhhh\n");
        close(pipe_fd[1]);
        sleep(DELAY_TIME*3);//延迟3秒
        if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0)
        {
            printf("Child receive %d bytes from pipe: '%s'.\n",real_read,buf);
        }
        close(pipe_fd[0]);
        exit(0);
    }
    else
    {
        close(pipe_fd[0]);//关闭读进程
        sleep(DELAY_TIME);
        if ((real_write=write(pipe_fd[1],data,strlen(data)))>0)
        {
            printf("Parent write %d bytes into pipe: '%s'.\n",real_write,data);
        }
        close(pipe_fd[1]);
        waitpid(pid,NULL,0);
        exit(0);
    }
    return 0;
}

operation result:

 Second, the named pipe FIFO

参考:
1 https://www.cnblogs.com/fangshenghui/p/4039805.html

Concept: Named Pipes also known as FIFO file, a special file.
1. Make two unrelated processes communicate with each other:
A indicated by the path name, the file system is visible.
B created a pipeline, two processes may be ordinary file operation thereof.
2. Follow the FIFO FIFO rules:
A for the return pipe read from the beginning of the data
. b put on the pipe write data to the end
. c does not support, such as lseek () and other file positioning operations
3, create a named pipe: mkfifo ()
FILNAME refers to the file name, and the mode is mode named pipe read and write permissions to the specified file, create, indicating that access. S_IFIFO | 0666 creates a named pipe and specify access privileges for 0666, namely the user creator, the creator of the same group, all other users read and write access to the named pipe.

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *filename, mode_t mode);
mkfifo("/tmp/fifo", S_IFIFO|0666)

4, unlike ordinary files are blocked problem
• blocking problem does not occur when ordinary file read and write
• read and write in the pipeline, but there may be blockage
• non-blocking flag: () function is set to O_NONBLOCK in Open
5 blocking and non-blocking open open:
for reading process
• If the pipeline is blocked open , and no current data in the FIFO, then for the reading process will block the data is written
• If the pipeline is non-blocking open , then whether or not there is data in the FIFO, reading process will be executed immediately read operation. That is, if there is no data in the FIFO, the read function returns 0 immediately
for the write process
• If the pipeline is blocked open, the write operation will block the data can be written
• non-blocking if the pipeline is open and all the data can not be written , the read operation for the partial write or call failed

Example 2

 read.c

/*fifo_read.c 读管道程序*/
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<limits.h>
#define MYFIFO "/tmp/myfifo" /*有名管道文件名*/
/*在 limits.h 中有 #define PIPE_BUF 4096 即 4 个字节大小*/
#define MAX_BUFFER_SIZE PIPE_BUF /*定义在 limits.h 中*/
int main()
{
    char buff[MAX_BUFFER_SIZE];
    int fd;
    int nread;
    /*判断有名管道是否已经存在,若尚未创建,则以相应的权限创建*/
    if(access(MYFIFO,F_OK)==-1)
    {
        if((mkfifo(MYFIFO,0666)<0)&&(errno!=EEXIST))
        {
            printf("Cannot create fifo file\n");
            exit(1);
        }
    }
    printf("hello\n");
    /*以只读阻塞方式打开有名管道*/
    fd=open(MYFIFO,O_RDONLY);
    //printf("hello\n");
    if(fd==-1)
    {
        printf("Open fifo file error\n");
        exit(1);
    }
    while(1)
    {
        memset(buff,0,sizeof(buff));
        if((nread=read(fd,buff,MAX_BUFFER_SIZE))>0)
        {
            printf("Read '%s' from FIFO\n",buff);
        }
//假设读取到 exit 的时候退出
        if(!strcmp(buff,"exit")) break;
    }
    close(fd);
    exit(0);
}/*end*/

write.c

#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<limits.h>
#define MYFIFO "/tmp/myfifo" /*有名管道文件名*/
/*在 limits.h 中有 #define PIPE_BUF 4096 即 4 个字节大小*/
#define MAX_BUFFER_SIZE PIPE_BUF /*定义在 limits.h 中*/
int main(int argc,char *argv[]) /*参数为即将写入的字符串*/
{
    int fd;
    char buff[MAX_BUFFER_SIZE];
    int nwrite;
    if(argc<=1)
    {
        printf("Usage: ./fifo_write string\n");
        exit(1);
    }
    /*sscanf()表示从字符串中格式化输出,与 scanf 类似,都是用于输入的,只是
    scanf()以键盘为输入源,sscanf()是以固定字符串为输入源*/
    sscanf(argv[1],"%s",buff);/*将 argv[1]的内容以字符串(%s)的形式存入 buf 中*/
    /*以读写阻塞方式打开 FIFO 管道*/
    fd=open(MYFIFO,O_RDWR);
    if(fd==-1)
    {
        printf("Open fifo file error\n");
        exit(1);
    }
    /*向管道中写入字符串*/
    if((nwrite=write(fd,buff,MAX_BUFFER_SIZE))>0)
    {
        printf("Write '%s' to FIFO\n",buff);
    }
    close(fd);
    exit(0);
} /*end*/

Run steps:
1, run read.c, so that the reading process waits for
2, run write.c, then you can find the reading process can already read
3, the process of writing input exit, exit.
Recommended to use CTRL + SHIFT + T to use multiple windows running.
                                            

1, open () function

int open(const char*pathname,int flags);
参数说明:
1.pathname 要打开或创建的目标文件
2.flags 打开文件时,可以传入多个参数选项,用下面的 一个或者多个常量进行“或”运算,构成falgs
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR: 读,写打开
这三个常量,必须制定一个且只能指定一个
返回值
成功:新打开的文件描述符
失败:-1
open返回的文件描述符一定是最小的而且没有被使用的

 

Third, the design description to learn to use named pipes to establish communications between multiple processes

#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<limits.h>
#define MYFIFO "/tmp/myfifo" /*有名管道文件名*/
/*在 limits.h 中有 #define PIPE_BUF 4096 即 4 个字节大小*/
#define MAX_BUFFER_SIZE PIPE_BUF /*定义在 limits.h 中*/
int main(int argc,char *argv[]) /*参数为即将写入的字符串*/
{
    char buff[MAX_BUFFER_SIZE];
    int fd,p;
    int nread,nwrite;
    /*判断有名管道是否已经存在,若尚未创建,则以相应的权限创建*/
    if(access(MYFIFO,F_OK)==-1)
    {
        if((mkfifo(MYFIFO,0666)<0)&&(errno!=EEXIST))
        {
            printf("Cannot create fifo file\n");
            exit(1);
        }
    }
    p=fork();
    if(p==0)
    {
        //child 进程
        //以写方式打开命名管道
        sleep(5);//保证先执行读进程,让读进程进入阻塞队列
        printf("子进程 write 数据\n");
        if(argc<=1)
        {
            printf("Usage: ./fifo_write string\n");
            exit(1);
        }
        /*sscanf()表示从字符串中格式化输出,与 scanf 类似,都是用于输入的,只是
        scanf()以键盘为输入源,sscanf()是以固定字符串为输入源*/
        sscanf(argv[1],"%s",buff);/*将 argv[1]的内容以字符串(%s)的形式存入 buf 中*/
        /*以读写阻塞方式打开 FIFO 管道*/
        fd=open(MYFIFO,O_RDWR);
        if(fd==-1)
        {
            printf("Open fifo file error\n");
            exit(1);
        }
        /*向管道中写入字符串*/
        if((nwrite=write(fd,buff,MAX_BUFFER_SIZE))>0)
        {
            printf("Write '%s' to FIFO\n",buff);
        }
        printf("成功写入数据.\n");
        close(fd);
    }
    else
    {
        //parent 进程
        printf("父进程read 数据\n");
        fd=open(MYFIFO,O_RDONLY);
        //printf("hello\n");
        if(fd==-1)
        {
            printf("Open fifo file error\n");
            exit(1);
        }
        memset(buff,0,sizeof(buff));
        if((nread=read(fd,buff,MAX_BUFFER_SIZE))>0)
        {
            printf("Read '%s' from FIFO\n",buff);
        }
        close(fd);
    }

} /*end*/

Published 43 original articles · won praise 23 · views 5317

Guess you like

Origin blog.csdn.net/weixin_43442778/article/details/95195629