Pipe (anonymous, named)

Linux inter-process communication method

Insert image description here

pipeline

Pipeline features

  • The pipeline is actually a buffer maintained in the kernel memory . The storage capacity of this buffer is limited, and different operating systems may not necessarily have the same size.
  • Pipelines have the characteristics of files: read operations, write operations
    • Anonymous pipe has no file entity
    • Named pipes have file entities , but do not store data. Pipelines can be manipulated in the same way as files
  • A pipe is a stream of bytes . When using a pipe, there is no concept of messages or message boundaries. The process reading data from the pipe can read data blocks of any size, regardless of the size of the data block written by the writing process to the pipe. How many.
  • The data passed through the pipeline is sequential , and the order of the bytes read from the pipeline is exactly the same as the order in which they were written to the pipeline.
  • The transmission direction of the data in the pipeline is one-way, one end is used for writing, and the other end is used for reading, and the pipeline is half-duplex . (Half Duplex data transmission means that data can be transmitted in both directions of a signal carrier, but not at the same time.)
  • 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. You cannot use lseek() to randomly access data in the pipe.
  • Anonymous pipes can only be used between processes with a common ancestor (a parent process and a child process, or two sibling processes, which have an affinity). [ The child process shares the file descriptor with the parent process after fork (✳ understanding)]

Insert image description here

anonymous pipe

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

  • Example: Count the number of files in a directory. Command: ls | wc –l. In order to execute this command, the shell creates two processes to execute ls and wc respectively.

Insert image description here

Anonymous pipe creation

  • int pipe(int pipefd[2])

    • Function: Create an anonymous pipe for inter-process communication.
    • Parameters: int pipefd[2] This array is an outgoing parameter.
      pipefd[0] corresponds to the read end of the pipe
      pipefd[1] corresponds to the write end of the pipe
    • Return value: 0 on success, -1 on failure

Note :

  1. Pipes are blocking by default: if there is no data in the pipe, read blocks, if the pipe is full, write blocks.
  2. Anonymous pipes can only be used for communication between processes that have a relationship (parent-child process, sibling process)

program1: The child process sends data to the parent process, and the parent process reads the data output.

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
    
    
    int pipefd[2];
    int ret=pipe(pipefd);
    if(ret==-1){
    
    
        perror("pipe");
        exit(0);
    }
    pid_t pid=fork();
    //父进程
    if(pid>0){
    
    
        char buf[1024] = {
    
    0};
        int len = read(pipefd[0], buf, sizeof(buf));
        printf("parent recv : %s, pid : %d\n", buf, getpid());
    }else if(pid==0){
    
    
        char * str = "hello,i am child";
        write(pipefd[1], str, strlen(str));
    }
    return 0;
}

Output result:

(base) user@ubuntu:~/Desktop/OS/NiuKe$ gcc -o test test.c 
(base) user@ubuntu:~/Desktop/OS/NiuKe$ ./test 
parent recv : hello,i am child, pid : 3552

program2: Parent and child processes communicate with each other

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//父子进程相互通信。
int main(){
    
    
    int pipefd[2];
    int ret=pipe(pipefd);
    if(ret==-1){
    
    
        perror("pipe");
        exit(0);
    }
    pid_t pid=fork();
    //父进程
    if(pid>0){
    
    
        printf("i am parent process, pid : %d\n", getpid());
        char buf[1024] = {
    
    0};
        while(1){
    
    
            //父进程接受子进程的数据,同时又给子进程发送数据。
            //从管道的读取端读取数据
            int len = read(pipefd[0], buf, sizeof(buf));
            printf("parent recv : %s, pid : %d\n", buf, getpid());
            // 向管道中写入数据
            char * str = "hello,i am parent";
            write(pipefd[1], str, strlen(str));
            sleep(1);
        }
    }else if(pid==0){
    
    
        printf("i am child process, pid : %d\n", getpid());
        char buf[1024] = {
    
    0};
        while(1){
    
    
            // 向管道中写入数据
            char * str = "hello,i am child";
            write(pipefd[1], str, strlen(str));
            sleep(1);

            int len = read(pipefd[0], buf, sizeof(buf));
            printf("child recv : %s, pid : %d\n", buf, getpid());
        }
    }
    return 0;
}

Output results

(base) user@ubuntu:~/Desktop/OS/NiuKe$ gcc -o test test.c 
(base) user@ubuntu:~/Desktop/OS/NiuKe$ ./test 
i am parent process, pid : 3630
i am child process, pid : 3631
parent recv : hello,i am child, pid : 3630
child recv : hello,i am parent, pid : 3631
parent recv : hello,i am child, pid : 3630
child recv : hello,i am parent, pid : 3631
parent recv : hello,i am child, pid : 3630

[Supplement]: Since the above program2code adds sleep, it can run normally. If this statement is removed, it will cause the process to write to the pipe and read from the pipe at the same time. Therefore, the solution to this problem is to close unnecessary ports (read or write) in advance.

Summarize

  • read pipe
    • There is data in the pipe, and read returns the number of bytes actually read.
    • No data in pipeline
      • The write end is all closed, and read returns 0 (equivalent to reading to the end of the file)
      • The write end is not completely closed, and read is blocked and waiting.
  • write pipe
    • All pipe readers are closed and the process terminates abnormally (the process receives the SIGPIPE signal)
    • The pipe readers are not all closed:
      • Pipe is full, write blocks
      • The pipe is not full, write writes the data and returns the actual number of bytes written

famous channel

  • Anonymous pipes, since they have no names, can only be used for inter-process communication of related relationships. In order to overcome this shortcoming, named pipes ( ), also called named pipes and files, were proposed .FIFOFIFO

  • 有名管道(FIFO)What is different from anonymous pipes is that it provides a path name associated with it, FIFOexists in the file system in the form of a file, and its opening method is the same as opening an ordinary file , so that even if FIFOthere is no affinity with the creation process Processes can FIFOcommunicate with each other as long as they have access to the path. Therefore, FIFOdata can also be exchanged through unrelated processes.

  • Once opened FIFO, the same I/O system calls (such as read(), write(), and close()) that are used to operate anonymous pipes and other files can be used on it. Like a pipe, FIFOthere is a writing end and a reading end, and the order in which data is read from the pipe is the same as the order in which it is written. FIFOThis is where the name comes from: first in, first out

  • 有名管道(FIFO)Some 匿名管道(pipe)features are the same as those of

    • FIFOIt exists as a special file in the file system, but FIFOits contents are stored in memory .
    • When the using FIFOprocess exits, FIFOthe file will continue to be saved in the file system for later use.
    • FIFOWith a name, unrelated processes can communicate by opening named pipes .

Creation of famous pipes

  1. mkfifo file name (created by shell command)
  2. int mkfifo(const char *pathname, mode_t mode);
    • pathname: path to the pipe name
    • mode: file permissions

program: Two processes communicate through named pipes (single send)

Writing side:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

// 向管道中写数据
int main() 
{
    
    
    // 1.判断文件是否存在
    int ret = access("test", F_OK);
    if(ret == -1) {
    
    
        printf("管道不存在,创建管道\n");
        
        // 2.创建管道文件
        ret = mkfifo("test", 0664);

        if(ret == -1) {
    
    
            perror("mkfifo");
            exit(0);
        }       

    }

    // 3.以只写的方式打开管道
    int fd = open("test", O_WRONLY);
    if(fd == -1) {
    
    
        perror("open");
        exit(0);
    }

    // 写数据
    for(int i = 0; i < 100; i++) {
    
    
        char buf[1024];
        sprintf(buf, "hello, %d\n", i);
        printf("write data : %s\n", buf);
        write(fd, buf, strlen(buf));
        sleep(1);
    }

    close(fd);

    return 0;
}

Read side

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

// 从管道中读取数据
int main() 
{
    
    
    // 1.打开管道文件
    int fd = open("test", O_RDONLY);
    if(fd == -1) {
    
    
        perror("open");
        exit(0);
    }

    // 读数据
    while(1) {
    
    
        char buf[1024] = {
    
    0};
        // 这里不能写strlen(buf) 因为这里的含义是每次按固定长度读取,最开始strlen(buf)=0
        int len = read(fd, buf, sizeof(buf));
        if(len == 0) {
    
    
            printf("写端断开连接了...\n");
            break;
        }
        printf("recv buf : %s\n", buf);
    }

    close(fd);

    return 0;
}

run

(No matter which end is executed first)

Insert image description here

Guess you like

Origin blog.csdn.net/weixin_42888638/article/details/128713365