The first 11 chapters interprocess communication (1) _ Pipeline

1. The  inter-process communication Overview

(1 Overview

  ① Data transfer: a process needs to transmit its data to another process, an amount of data transmitted in bytes to several megabytes.

  ② share data: operating multiple processes want to share data, a process to modify the shared data, other process should be seen immediately.

  ③ notification events: a process needs to send a message to another (group) process, notifying them of the occurrence of a certain event (to be notified when the parent process as the process is terminated).

  ④ resource sharing: sharing the same resources among multiple processes. To do this, we need to provide the kernel lock and synchronization mechanisms.

  ⑤ Process Control: Some want to completely control the process of execution of another process (such as Degub process), and the control will process all want to be able to intercept and exceptions into another process, and be able to timely know its status changed.

(2) the process of modern means of communication

  ① conduit (pipe) and naming management (FIFO) ② signal (signal) ③ ④ message queue shared memory semaphore ⑤ ⑥ socket (Socket)

2.  The pipe communication

2.1  Overview

(1) is a conduit for the local computer communication method for communication between two processes designed, created a pipeline, is actually obtained , both file descriptors : one for reading and one for writing .

(2) The most common IPC mechanism, by calling pipe system

(3) pipes are simplex , data can only flow in one direction , two-way communication when required, need to establish two pipes.

Reading and writing (4) data: a process to write the contents of the pipeline process is read out of the other end of the pipe. Written content every time the buffer added to the end of the pipe , and each time from the head of the read data buffer (i.e., should be consistent with a sequential write of sequentially read !)

2.2  pipes classification and write

Category (1) pipeline

  ① anonymous pipes:

    A. In relation process process (between parent and child, brother process)

    B. a call pipe systems , pipelines built by the parent process

    C. pipes in the kernel space, in fact, a cache

  ② named pipe (FIFO):

    A. two without any relationship between the processes of the communication for data transfer via a named pipe, the kernel is essentially a cache, the other in the file system is present in a particular design file (pipe file) .

    B. By calling mkfifo system created.

(2) pipeline to create: 

head File

#include <unistd.h>

function

int pipe(int fd[2]);

Features

Waiting for one or more designated signal generating

return value

Successful return 0, otherwise -1

Remark

①fd [0]: is the read end of the pipe, the pipe for reading.

②fd [1]: a write pipe end, the pipe for writing.

Write (2) of the pipe

  ① pipeline is mainly used for communication between different processes. In fact, usually the first to create a pipeline, and then creates another child process by fork function .

  ② Note simplex pipe, so to turn off some of the parent and child fd therein (shown above). If you need two-way communication, you need to create two pipes.

[Programming] experiment written parent, the child process reads

//cal_pipe.c

 View Code

[Programming] simulation experiment Pipe command

  ① a child process execution command, the command execution result into the pipeline

  ② another sub-process reads the results of command execution from the pipe, and then filtered (grep) keyword

  ③ analysis command: cat / etc / passwd | grep root. When this command is executed, in fact, there are three processes: the child process parent shell, cat child process and execution of grep! This simulation scenario in this case is the same, the execution result into the pipeline by the child's cat, grep child process reads out from the pipe!

 //cmd_pipe.c

Copy the code

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

char* cmd1[3] = {"/bin/cat", "/etc/passwd", NULL};
char* cmd2[3] = {"/bin/grep", "root", NULL};
// char * cmd2 [3] = { "wc", "-l", NULL}; // count the number of users
int main(void)
{
    you fd [2]

    if(pipe(fd) < 0){
        perror("pipe error");
        exit(1);
    }

    int i = 0;
    pid_t pid;
    // create a process fan: a parent process and sub-process 2
    for(; i<2; i++){
        pid = fork();
        if(pid < 0){
            perror("fork error");
            exit(1);
        }else if(pid == 0){ //child process
            if (i == 0) {// first sub-process responsible for writing data to the pipeline
                close (fd [0]); // Close the read end   
                
                // Note that the default output is a standard cat command output (screen), and therefore need to redirect output to the write end of the pipe
                // The standard output is redirected to the write end of the pipe, cat execution results are written to the pipeline
                if (dup2 (fd [1], STDOUT_FILENO)! = STDOUT_FILENO) {// the fd [1] as a weight to the standard output
                    perror("dup2 error");
                }
                
                close (fd [1]); // hexyl standard output is redirected to a write pipe end, fd [1] may be closed

                // call the exec function executes the cat command
                if (execvp (cmd1 [0], cmd1) <0) {// v array, p absolute or relative path
                    perror("execvp error");
                    exit(1);
                }
            }

            if (i == 1) {// the second sub-process is responsible for reading data from the pipeline
                close (fd [1]); // Close the write end
                // redirects standard input to the read end of the pipe, so that grep read from the conduit rather than from the standard input
                if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO){
                    perror("dup2 error");
                }

                close (fd [0]); // standard input hexyl redirected to the read end of the pipe, fd [0] can be closed

                // call the exec function to execute grep command
                if(execvp(cmd2[0], cmd2) < 0){
                    perror("execvp error");
                    exit(1);
                }
            }

            break;
        }else{ //parent process
            if (i == 1) {// Create a sub-process to be completed, step 2
                // parent process to wait until the child process is completed before going to create all recovery
                close(fd[0]);
                close(fd[1]);
                wait (0); // recovered two sub-processes
                wait(0);
            }
        }
    }
    if(pid = fork() < 0){
    
    }

    return 0;
}
/ * Output:
 root:x:0:0:root:/root:/bin/bash
 operator:x:11:0:operator:/root:/sbin/nologin
*/

Copy the code

[Experimental] collaborative programming process (two two-way communication process through two pipes)

  ① parent x and y to write the first one pipeline.

  ② sub-process reads x and y from a pipeline. And calls add is added.

  ③ The child process writes the result to the second conduit.

  ④ parent process reads the calculation result from the second conduit, and outputs.

//add.c ==> to be compiled into a single executable file add.o

Copy the code

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

int main(int argc, char* argv[])
{
    int x = 0, y = 0;
    if(read(STDIN_FILENO, &x, sizeof(int)) < 0){
        perror("read error");
    }
    if(read(STDIN_FILENO, &y, sizeof(int)) < 0){
        perror("read error");
    }

    int result = x + y;

    if(write(STDOUT_FILENO, &result, sizeof(int)) != sizeof(int)){
        perror("write error");
    }

    return 0;
}

Copy the code

//co_process.c ==> compiled into an executable file

Copy the code

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

int main(void)
{
    int fda[2], fdb[2];

    // Create two pipes in order to achieve duplex operation
    if( (pipe(fda) < 0) || (pipe(fdb) <0) ){
        perror("pipe error");
        exit(1);
    }

    pid_t pid;
    pid = fork();
    if(pid < 0){
    }else if(pid == 0){//child process
        /*
         * (1) the parent child process is responsible for reading the writing from a pipe parameters x and y
         * (2) to call bin / add are accumulated by the program exec function
         * (3) The accumulated results are written to the pipe b.
         */
        close (fda [1]); // can only be read from a pipe
        close (fdb [0]); // b can be written to the pipe

        // redirected to the standard input of the read end of a pipe, then
        // (add a program read from the pipe end of the accumulated read parameters x and y)
        if(dup2(fda[0], STDIN_FILENO) != STDIN_FILENO){
            perror("dup2 error");
        }
        // write the standard output to the end of the pipe b, the
        // (accumulated result of the program is written to add in the duct b)
        if(dup2(fdb[1], STDOUT_FILENO) != STDOUT_FILENO){
            perror("dup2 error");
        }

        close (fda [0]); // redirection is complete, it can be closed
        close(fdb[1]);

        if(execlp("bin/add", "bin/add", NULL) < 0){
            perror("execlp error");
            exit(1);
        }
    }else{ //parent process
        /*
         * (1) x and y parameters read from stdin
         * (2) x and y write a conduit
         * (3) is read from the pipe b, and outputs the accumulated result
         */
        close(fda[0]);
        close(fdb[1]);

        int x, y;
        // (1) read the parameters x and y accumulated
        printf("please input x and y: ");
        scanf("%d %d", &x, &y);
        @ (2) the x and y write a conduit
        if(write(fda[1], &x, sizeof(int)) != sizeof(int)){
            perror("write error");
        }
        if(write(fda[1], &y, sizeof(int)) != sizeof(int)){
            perror("write error");
        }

        @ (3) from the pipe b, the reading result (note that block the pipeline when no data!)
        int result;
        if(read(fdb[0], &result, sizeof(int)) < 0){
            perror("read error");
        }else{
            printf("add result is %d\n", result);
        }

        close(fda[1]);
        close(fdb[0]);
        wait(0);
    }
    return 0;
}

Copy the code

2.3  Characteristics of the pipe

(1) to create a two-way pipe by opening the two pipes

(2) pipes are obstructive when the process data is read from the pipe, the process will be blocked if there is no data.

(3) When a process constantly write data to the pipeline, but there is no process to read data, when this time as long as the pipe is not full of it, but if the pipeline will be filled with data error.

(4) incomplete pipeline

  ① When reading a write terminal already closed when the pipe after all of the data is read, read return 0 to indicate the end of the file reaches.

  ② If writing a terminal has been read off of the pipe, the generation SIGPIPE signal , if the signal is ignored or capture the signal and returns to the processing program , the write returns -1 , errno is set while EPIPE.

[Experiment] read a write programming has closed end conduit

//broken_pipe_r.c

Copy the code

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

/*
 * Incomplete pipe: reading a write pipe end has closed
 */
int main ()
{
    you fd [2]
    if(pipe(fd) < 0){
        perror("pipe error");
        exit(1);
    }

    pid_t pid;
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if (pid > 0){ //parent process
        Never complete pipeline // parent process read data
        
        close(fd[1]);
 
        sleep (5); // wait for the child to write end of the pipe is closed
        
        while(1){
            char c;
            if(read(fd[0], &c, 1) == 0){
                printf("\nwrite-end of pipe closed.\n");
                break;
            }else{
                printf("%c", c);
            }
        }

        close(fd[0]);
        wait(0);
    }else{ //child process
        // child process negative writes the data pipeline
        close(fd[0]);
        char* s = "12345";
        write(fd[1], s, strlen(s)*sizeof(char));

        // shut down the pipeline after writing data write end -> becomes incomplete
        // pipeline, but be sure to read the pipe before the pipe in the parent write end is closed!
        close(fd[1]);
    }
    return 0;
}
/ * Output
 12345
 write-end of pipe closed.
 */

Copy the code

[Experiment] Programming a read-write terminal already closed conduit

//broken_pipe_w.c

Copy the code

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

/*
 * Incomplete pipeline: the end of the pipeline had been shut down to write a read
 */

// signal handler
void sig_handler (int signo)
{
    if(signo == SIGPIPE){
        printf("SIGPIEP occured\n");
    }
}

int main(void)
{
    // Register signal processing function
    if (signal (SIGPIPE, sig_handler) == SIG_ERR) {
        perror("signal sigpipe error");
        exit(1);
    }
    you fd [2]
    if(pipe(fd) < 0){
        perror("pipe error");
        exit(1);
    }

    pid_t pid;
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid > 0){ //parent process       
        // parent process registration signal processing function
        if (signal (SIGPIPE, sig_handler) == SIG_ERR) {
            perror("signal sigpipe error");
            exit(1);
        }

        // The parent process is responsible for writing data to the incomplete pipeline (read end closed) in
        sleep (5); // let the child process to run, in order to ensure that the read end closed

        close(fd[0]);

        char* s = "12345";
        int len = strlen(s) * sizeof(char);
        if(write(fd[1], s, len ) != len){
            fprintf(stderr, "%s, %s\n", strerror(errno),
                   (errno == EPIPE) ? "EPIPE": ", unknow");
        }

        close(fd[1]);
        wait(0);

    }else{ //child process
        close(fd[0]);
        close(fd[1]);
    }
    return 0;
}
/ * Output:
 SIGPIEP occured
 Broken pipe, EPIPE
 */

Copy the code

2.4  Pipelining standard library

head File

#include <stdio.h>

function

FILE* popen(const char* cmdstring, const char* type);

parameter

cmdstring : command-line parameters to be executed.

type:r或w。

  ① If type is r, is represented by the child exec (cmdstring), the result is written duct (sub-process will be internal standard output to the write end of the pipe), the parent process execution result read command from the pipe.

  ② If the type is w, it means that the parent process to write data to the pipe, the child process to read data from the pipe as the input command (internal standard input to the re-read to the end of the pipe).

return value

Successful return file pointer, NULL on error

Features

By creating a pipeline, calling fork () generates a child process, then execute the command cmdstring by the child.

function

int pclose(FILE* fp);

return value

cmdstring termination status, error -1

Features

Close pipeline

Remark

  ① use popen () to create a pipeline must be used pclose () is closed. In fact, popen / pclose and standard file input / output streams fopen / fclose very similar.

  Common packaging operation ② conduit.

[Experiment] programming library using standard read and write operations conduit

//popen_rw.c

Copy the code

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

/ * File using the pipeline operator * /

int main(void)
{
    FILE* fp;
    // command execution result is placed in the cache structure pointed to by fp
    fp = popen("cat /etc/passwd", "r");
    
    char buf[512];
    memset(buf, 0, sizeof(buf));
    while(fgets(buf, sizeof(buf), fp) != NULL){
        printf("%s", buf);
    }

    pclose(fp);

    printf("-----------------------------------------\n");
    // provide statistical data for the wc command
    fp = popen("wc -l", "w");
    // write data to the cache fp points (since the type is "w", so that data is written to the pipeline)
    fprintf (fp, "line1 \ nline2 \ nline3 \ n"); // 3 provides data lines, as wc to statistical data sources!
    pclose(fp);

    return 0;
}

Copy the code

2.5  Command pipe (FIFO)

(1) FIFO creation

head File

#include <sys/types.h>

#include <sys/stat.h>

function

int mkfifo(const char* pathname, mode_t mode);

parameter

Pipeline file name to be created: ①pathname

②mode: Permissions (mode% ~ umask)

return value

(1) return 0 if successful, -1 error

(2) FIFO -related error messages

  ①EACCES (no access) ②EEXIST (specified file does not exist)

  ③ENAMETOOLONG (pathname too long) ④ENOENT (directory contains does not exist)

  ⑤ENOSPC (enough space left on the file system) (invalid file path) ⑥ENOTDIR

  ⑦EROFS (specified file exists in the read-only file system)

Remark

 

(2) Notes

  ① As long as there is adequate access to the FIFO, FIFO can be used in any process two have nothing to communicate.

  ② essentially a cache in the kernel , which is present in a special device file (pipe) file system .

  ③ in the file system is only one index block to store the file path, there is no data block , all the data stored in the kernel.

  ④ named pipe must be open simultaneously read or write , or read or write individual alone can cause obstruction .

  ⑤ command mkfifo create a named pipe (Command mkfifo internal call function)

  ⑥ operation is the same as ordinary files to the FIFO.

  Once created mkfifo ⑦ has a FIFO used, it can be opened by Open, a general file I / O functions (close, read, write and unlink the like) can be used FIFO.

[Programming] literacy test pipe file

(1) Before running this example of two processes, you must first create a named pipe mkfifo file (such as s.pipe)

(2)不管先运行读还是写的进程。如果命名管道只被打开一端(读或写),则另一个进程会被阻塞。可以通过先运行读或写进程来观察进程被阻塞的现象

//fifo_write.c ==>编译成单独的可执行文件

Copy the code

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

/*向命名管道写入数据*/

int main(int argc, char* argv[])
{
    if(argc < 2){
        printf("usage: %s fifo\n", argv[0]);
        exit(1);
    }

    printf("open fifo write...\n");
    //打开命名管道
    int fd = open(argv[1], O_WRONLY);
    if( fd < 0 ){
        perror("open error");
        exit(1);
    }else{
        printf("open fifo success: %d\n", fd);
    }

    char* s = "1234567890";
    size_t size = strlen(s);
    if(write(fd, s, size) != size){
        perror("write error");
    }

    close(fd);

    return 0;
}
/*输出结果:
 [root@localhost]# bin/fifo_write s.pipe //要先mkfifo s.pipe创建命名管道文件
 open fifo write...
 open fifo success: 3
 */

Copy the code

//fifo_read.c  ==>编译成单独的可执行文件

Copy the code

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

/*从命名管道中读取数据*/

int main(int argc, char* argv[])
{
    if(argc < 2){
        printf("usage: %s fifo\n", argv[0]);
        exit(1);
    }

    printf("open fifo read...\n");
    //打开命名管道
    int fd = open(argv[1], O_RDONLY);
    if(fd < 0){
        perror("open error");
        exit(1);
    }else{
        printf("open file sucess: %d\n", fd);
    }

    //从命名管道中读取数据
    char buf[512];
    memset(buf, 0, sizeof(buf));
    while(read(fd, buf, sizeof(buf)) < 0){
        perror("read error");
    }
    printf("%s\n", buf);

    close(fd);

    return 0;
}
/ * Output:
 [root@localhost]# bin/fifo_read s.pipe
 open fifo read...
 open file sucess: 3
 1234567890
 */

Copy the code

2.6  write command pipeline and anonymous

(1) anonymous pipes and named pipes to read and write the same point

Same point

Explanation

Blocking characteristics

The default is obstructive to read and write

Telecommunication

Apply to the network communication socket

Incomplete obstruction pipeline

① when read alone, after all the data is read, read returns 0, to indicate that reached the end of the file.

② When the simple write SIGPIPE signal is generated, if the signal is ignored or capture the signal and returns to the processing program, write returns -1 errno set EPIPE.

Complete blockage pipeline

① when read alone, either blocking or read data

② simply write, write to errors when the pipeline is full

Non-blocking is not complete pipeline

① direct error when reading simple

② When the simple write SIGPIPE signal is generated, if the signal is ignored or capture the signal and returns to the processing program, write returns -1 errno set EPIPE.

Non-blocking full pipeline

① when simply reading directly error.

② simple when written, is written to be wrong when the pipeline is full.

(2) anonymous pipes and named pipes to read and write different

difference

Explanation

Open

Open inconsistent

Set blocking properties

①pipe set O_NONBLOCK fcntl by non-blocking system call to read.

②FIFO call or open function is provided by a non-blocking system fcntl read.

 

Original connection: https://www.cnblogs.com/5iedu/p/6579907.html

 

Published 25 original articles · won praise 4 · views 20000 +

Guess you like

Origin blog.csdn.net/zhou8400/article/details/97142715