[Unnamed Pipe] Unnamed Pipe (Pipe) and Process Communication: Get Started Quickly

Table of contents

0. Pipeline Overview:

1. Pipe characteristics

2. Pipe creation: pipe function

3. Reading and writing characteristics of pipelines

4. Set the blocking characteristics of the file through the fcntl function

5. View pipe buffer command

Summarize:


0. Pipeline Overview:

        Pipes are also called nameless pipes. They are the oldest form of IPC (inter-process communication) in UNIX systems. All UNIX systems support this communication mechanism.

        Unnamed pipes are created in the kernel space. Multiple processes know the space of the same unnamed pipe and can use it to communicate. (Under a 32-bit operating system, when any process is created, the system will allocate 4G of virtual memory to it, 3G is user space, and 1G is kernel space)

        Although the unnamed pipe is created in the kernel space, it will give the current user process two file descriptors, one for reading operations and one for writing operations.

1. Pipe characteristics

1) Half-duplex, data can only flow in one direction at the same time.

2) Data can only be written from one end of the pipe and read from the other end.

3) Data written into the pipeline follows the first-in, first-out rule.

4) The data transmitted by the pipeline is unformatted, which requires the reader and writer of the pipeline to agree on the format of the data in advance, such as how many bytes count as a message, etc.

5) Pipes are not ordinary files and do not belong to a certain file system. They only exist in memory.

6) The pipe corresponds to a buffer in memory. Different systems are not necessarily the same size.

7) Reading data from the pipe is a one-time operation. Once the data is read, it is discarded from the pipe to free up space for writing more data.

8) Pipes have no names and can only be used between processes with common ancestors (parent process and child process, or two sibling processes, with affinity).

        To understand the characteristics of pipelines, we can compare them to pipes in real life. Things are plugged into one end of the pipe and things are taken out from the other end of the pipe. A pipe is a special type of file that is represented by two open file descriptors at the application layer.

2. Pipe creation: pipe function

pipe function:

#include <unistd.h>
int pipe(int pipefd[2]);
Function: Create an unnamed pipe and return two file descriptors responsible for reading and writing the pipe.
Parameters:
    pipefd: is the first address of the int type array, which is stored The file descriptors pipefd[0] and pipefd[1] of the pipe are obtained.

                 pipefd[0]: Responsible for performing read operations on the pipe.

                 pipefd[1]: Responsible for performing write operations on the pipe.
                 All general file I/O functions can be used to operate pipes (except lseek()).
Return value:
    Success: 0
    Failure: -1

 Code example:

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

int main()
{
    int fd_pipe[2];
    if (pipe(fd_pipe) == -1) {
        perror("fail to pipe");
        exit(1);
    }

    printf("fd_pipe[0] = %d\n", fd_pipe[0]);
    printf("fd_pipe[1] = %d\n", fd_pipe[1]);

    if (write(fd_pipe[1], "hello world ", 12) == -1) {
        perror("fail to write");
        exit(1);
    }
    write(fd_pipe[1], "nihao beijing", strlen("nihao biejing") + 1);
    char buf[32] = "";
    ssize_t bytes;
    if ((bytes = read(fd_pipe[0], buf, sizeof(buf))) == -1) {
        perror("fail to read");
        exit(1);
    }
    printf("buf = %s\n", buf);
    printf("bytes = %ld\n", bytes);
    return 0;
}

 The parent-child process realizes data transmission through pipes

 Sample code:

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

int main()
{
    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        perror("fail to pipe");
        exit(1);
    }
    int pipeff[2];
    if (pipe(pipeff) == -1)
    {
        perror("fail to pipe");
        exit(1);
    }

    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    {
        char buf[128] = "";
        char buu[128] = "";
        while (1)
        {
            fgets(buf, sizeof(buf), stdin);
            buf[strlen(buf) - 1] = '\0';

            if (write(pipefd[1], buf, sizeof(buf)) == -1)
            {
                perror("fail to write");
                exit(1);
            }

            if (read(pipeff[0], buu, sizeof(buu)) == -1)
            {

                perror("fail to read ");
                exit(1);
            }
            printf("buu = %s\n", buu);
        }

    }
    else
    {
        char buf[128] = "";
        char buu[128] = "";
        while (1)
        {
            if (read(pipefd[0], buf, sizeof(buf)) == -1)
            {

                perror("fail to read ");
                exit(1);
            }
            printf("buf = %s\n", buf);


            fgets(buu, sizeof(buu), stdin);
            buu[strlen(buu) - 1] = '\0';

            if (write(pipeff[1], buu, sizeof(buu)) == -1)
            {
                perror("fail to write");
                exit(1);
            }
        }

    }
    return 0;
}

3. Reading and writing characteristics of pipelines

When using pipes, you need to pay attention to the following four special situations (assuming that they are all blocking I/O operations and the O_NONBLOCK flag is not set):

1. Both reading and writing ends exist, only reading but not writing:

    //Both reading and writing ends exist, only reading and not writing
    //If there is data in the pipe, the data will be read normally
    //If there is no data in the pipe, the read operation will block and wait until there is data.

2. Both reading and writing ends exist, only writing but not reading

    //Both reading and writing ends exist, only writing but not reading
    //If the write operation is always performed, the buffer corresponding to the unnamed pipe will be filled. After it is full, the write function will also block and wait.
    //The default buffer of the unnamed pipe 64K bytes

3. Only the reading side

    //Close the file descriptor, only the read end
    //If there is data in the pipe, the read operation reads the data normally
    //If there is no data in the pipe, the read function returns 0

4. Only write paragraphs

    //Close the reading end, only the writing end
    //Close the reading end, once a write operation is performed, a SIGPIPE (pipe rupture) is immediately generated
    //The default processing method of this signal is to exit the process

Both reading and writing ends exist, only reading but not writing

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

int main()
{
    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        perror("fail to pipe");
        exit(1);
    }
    //读写端都存在,只读不写
    //如果管道中有数据,会正常读取数据
    //如果管道中没有数据,则读操作会阻塞等待,直到有数据为止
    write(pipefd[1], "hello world", 11);
    char buf[128] = "";
    if (read(pipefd[0], buf, sizeof(buf)) == -1)
    {
        perror("fail to read");
        exit(1);
    }
    printf("buf = %s\n", buf);

    if (read(pipefd[0], buf, sizeof(buf)) == -1)
    {
        perror("fail to read");
        exit(1);
    }
    printf("buf = %s\n", buf);
    return 0;
}
~

Both reading and writing ends exist, only writing but not reading

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

int main()
{
    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        perror("fail to pipe");
        exit(1);
    }
    //读写端都存在,只写不读
    //如果一直执行写操作,则无名管道对应的缓冲区会被写满,写满之后,write函数也会阻塞等待
    //默认无名管道的缓冲区64K字节
    int num = 0;
    while (1)
    {
        if (write(pipefd[1], "666", 1024) == -1)
        {
            perror("fail to write");
            exit(1);
        }
        num++;
        printf("num = %d\n", num);
    }
    return 0;
}

Only read side

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


int main()
{
    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        perror("fail to pipe");
        exit(1);
    }
    write(pipefd[1], "hello world", 11);
    //关闭文件描述符,只有读端
    //如果管道中有数据,则读操作正常读取数据
    //如果管道中没有数据,则read函数返回0
    close(pipefd[1]);

    char buf[128] = "";
    ssize_t bytes;
    if ((bytes = read(pipefd[0], buf, sizeof(buf))) == -1)
    {
        perror("fail to read");
        exit(1);
    }
    printf("bytes = %ld\n", bytes);
    printf("buf = %s\n", buf);

    memset(buf, 0, sizeof(buf));
    if ((bytes = read(pipefd[0], buf, sizeof(buf))) == -1)
    {
        perror("fail to read");
        exit(1);
    }
    printf("bytes = %ld\n", bytes);
    printf("buf = %s\n", buf);
    return 0;
}

only write

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

void handler(int sig) {
    printf("SIGPIPE发生了,管道破裂\n");
}
int main()
{
    signal(SIGPIPE, handler);
    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        perror("fail to pipe");
        exit(1);
    }
    //关闭读端,只有写端
    //关闭读端,一旦执行写操作,立刻产生一个SIGPIPE(管道破裂)
    //这个信号默认处理方式是退出进程
    close(pipefd[0]);

    int num = 0;
    while (1)
    {
        if (write(pipefd[1], "hello", 1024) == -1)
        {
            perror("fail to write");
            exit(1);
        }
        num++;
        printf("num = %d\n", num);
    }
    return 0;
}

4. Set the blocking characteristics of the file through the fcntl function

Set to blocking:

        fcntl(fd,F_SETFL,0);

Set to non-blocking:

        fcntl(fd,F_SETFL,O_NONBLOCK);

Non-blocking: If it is blocked and there is no data in the pipe, read will wait until there is data before continuing to run, otherwise it will wait.

Setting method:

//获取原来的flags
int flags = fcntl(fd[0], F_GETFL);
// 设置新的flags
flag |= O_NONBLOCK;
// flags = flags | O_NONBLOCK;
fcntl(fd[0], F_SETFL, flags);

Conclusion: If the writing end is not closed, the reading end is set to non-blocking. If there is no data, -1 is returned directly.

        If it is non-blocking, when the read function is running, it will first check whether there is data in the pipe. If there is data, the data will be read normally. If there is no data in the pipe, the read function will return immediately and continue to run the following code.

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

int main()
{
    int fd_pipe[2];
    char buf[] = "hello world";
    pid_t pid;

    if (pipe(fd_pipe) == -1)
    {
        perror("fail to pipe");
        exit(1);
    }

    pid = fork();
    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    {
        fcntl(fd_pipe[0], F_SETFL, O_NONBLOCK);
        while (1)
        {
            memset(buf, 0, sizeof(buf));
            read(fd_pipe[0], buf, sizeof(buf));
            printf("buf = %s\n", buf);
            sleep(1);
        }
    }
    else
    {
        while (1)
        {
            sleep(5);
            write(fd_pipe[1], buf, strlen(buf));
        }
    }
    return 0;
}

5. View pipe buffer command

You can use the ulimit -a command to view the kernel buffer size corresponding to the created pipe file in the current system.

 View pipe buffer functions

#include <unistd.h>
​
long fpathconf(int fd, int name);
功能:该函数可以通过name参数查看不同的属性值
参数:
    fd:文件描述符
    name:
        _PC_PIPE_BUF,查看管道缓冲区大小
        _PC_NAME_MAX,文件名字字节数的上限
返回值:
    成功:根据name返回的值的意义也不同。
    失败: -1

Example:

int main()
{
    int fd[2];
    int ret = pipe(fd);
    if (ret == -1)
    {
        perror("pipe error");
        exit(1);
    }
​
    long num = fpathconf(fd[0], _PC_PIPE_BUF);
    printf("num = %ld\n", num);
​
    return 0;
}

Summarize:

        Unnamed pipes are a powerful and basic inter-process communication mechanism that allow related processes to easily share data. The use of unnamed pipes is widely used, whether in simple Shell commands or in complex multi-process applications.

        Note: Unnamed pipes can only be used between processes with a common ancestor and can only achieve one-way communication.

Guess you like

Origin blog.csdn.net/crr411422/article/details/131421001