I. Concepts
Inter-process communication is to spread or exchange messages between different processes. Pipelines, or anonymous pipelines, are one of the most common communication methods between processes in Linux. They are a channel for data flow between two processes. Advantages: ease of use; disadvantages: simple functions.
Pipelines are the original communication methods between processes in Linux/Unix systems. Data flows between processes in a data stream mode. The anonymous MPs queue does not have a real name in the system. You cannot view the MPs queue in any way in the file system. The MPs queue is only a resource of the process and is cleared by the system as the process ends. Two file descriptors are generated when a pipeline is created, but there is no path name, that is, there is no meaningful file. The file descriptor here is only two file descriptors associated with an index node in the memory.
Ii. Pipeline communication features:
1. No name. It is an anonymous pipeline.
2. half-duplex communication. When duplex communication is required, a connection pipe needs to be established.
3. It can only be used between parent and child processes and brothers.
4. A separate file system exists in the memory.
5. Write content at the end of the MPs queue buffer and read it from the MPs queue buffer header.
6. Limited buffer size
7. The pipeline transmits a non-formatted byte stream.
3. Create and close Pipelines
In Linux, use the pipe function to create a pipeline: intpipe (int fd [2]). If 0 is returned successfully,-1 is returned if the pipeline fails. the FD [2] parameter is an array of file descriptors with a length of 2. FD [0] is the file descriptor of the Reading end, and FD [1] is the file descriptor of the writing end. After the function is successfully returned, a channel from Fd [1] to fd [0] is automatically maintained. Use the close function to close the MPs queue.
Program 1 demonstrates how to create and close pipelines and transmit data using pipelines. When the program ends, the file resources occupied by the pipelines are released.
# Include <unistd. h> # include <stdio. h> # include <stdlib. h> int main (void) {intfd [2];/* file descriptor array of the MPs queue */Char STR [256]; If (pipe (FD) <0) {printf ("create the pipe failed! \ N "); exit (1);/* pipe error exits */} write (FD [1]," create the pipe successfully! \ N ", 31);/* write data to the pipe writer */read (FD [0], STR, sizeof (STR )); /* read data from the pipe reader */printf ("% s", STR); printf ("pipe file descriptors are % d, % d \ n ", FD [0], FD [1]); close (FD [0]);/* close the reader file descriptor of the Pipeline */close (FD [1]); /* close the write end file descriptor of the Pipeline */return 0 ;}
Iv. Pipeline read/write
You can use the Read and Write Functions to read and write the pipeline. Note that the two segments of the pipeline are fixed, that is, the reading end of the pipeline can only be used to read data, the Data Writing end of the MPs queue can only be used to write data. Common file functions can be used in MPs queues, such as close read write.
MPs queue write rules: When writing data to an MPS queue, the write process immediately tries to write data to the MPs queue if the MPs queue does not read data from the MPs queue buffer, write operations will be blocked all the time. It is meaningless for a single process to operate on one pipeline. Pipeline applications are generally between parent and child processes or sibling processes.
If you want to establish a pipeline from a parent process to a child process, you can call the pipe function first and then call the fork function. Because the child process automatically inherits the data segment of the parent process, the Parent and Child processes also have the ownership of the MPs queue. To implement the data channel from the parent process to the child process, you must disable the Reading end of the channel in the parent process and the writing end of the channel in the child process. Otherwise, the write end of the channel is disabled in the parent process and the read end of the channel is disabled in the child process. In short, using the combination of pipe and fork, You can construct all the Parent and Child processes, or the pipeline from the child process to the brother process.
Program 2: For the application example of the MPs queue in the parent and child processes, use the pipe function to create a channel, use the fork function to create a sub-process, and maintain the data flow direction of the MPs queue in the parent and child processes, in the parent process, the sub-process sends messages, receives messages in the process, and outputs the messages to the standard output.
# Include <unistd. h> # include <stdio. h> # include <sys/types. h> # include <limits. h ># define bufsize pipe_buf/* pipe_buf: the default data length for one-time read/write in the pipeline */void err_quit (char * MSG) {printf (MSG); exit (1 );} int main (void) {int FD [2]; charbuf [bufsize] = "Hello my child! \ N ";/* buffer for writing to the MPs queue */pid_t PID; int Len; If (pipe (FD) <0) /* Create Pipeline */{err_quit ("pipe failed \ n");} If (pid = fork () <0) /* create a sub-process */{err_quit ("fork failed \ n");} else if (pid> 0) {close (FD [0]); /* close the pipe Reading end in the parent process */write (FD [1], Buf, strlen (BUF )); /* the parent process writes data to the pipeline */exit (0);} else {close (FD [1]); /* write end of the sub-process to close the Pipeline */Len = read (FD [0], Buf, bufsize ); /* the sub-process reads data from the pipeline */If (LEN <0) {err_quit ("process failed when read a pipe \ n");} else {write (stdout_fileno, buf, Len);/* output to standard output */} exit (0 );}}
Program 3 is an example of an application of an MPS queue in a sibling process. Create an MPS queue in the parent process and use the fork function to create two child processes. send messages to the second child process in the first child process, read and process the message in the second child process. In the parent process, do nothing. You need to disable both ends of the channel.
# Include <unistd. h> # include <stdio. h> # include <stdlib. h> # include <sys/types. h> # include <limits. h ># define bufsize pipe_buf/* pipe_buf: the default data length for one-time read/write in the pipeline */void err_quit (char * MSG) {printf (MSG); exit (1 );} int main (void) {int FD [2]; charbuf [bufsize] = "Hello my brother! \ N ";/* buffer */pid_t PID; int Len; If (pipe (FD) <0) /* Create Pipeline */{err_quit ("pipe failed \ n");} If (pid = fork () <0) /* create the first sub-process */{err_quit ("fork failed \ n");} else if (pid = 0) /* sub-process */{close (FD [0]);/* close unused file descriptors */write (FD [1], Buf, strlen (BUF);/* write message */exit (0);} If (pid = fork () <0) /* Create the second sub-process */{err_quit ("fork failed \ n");} else if (pid> 0) /* parent process */{close (FD [0]); close (FD [1]); exit (0 );} else/* In the second child process */{close (FD [1]);/* close the unused file descriptor */Len = read (FD [0], Buf, bufsize);/* read the message */write (stdout_fileno, Buf, Len);/* output the message to the standard output */exit (0);} return 0 ;}
In the above Code, the parent process creates two sub-processes, closes the read segment of the pipeline in the sub-process, and closes the write end of the pipeline in the other sub-process, the two channels are closed in the parent process. In the program, the parent process does not close both ends of the pipeline when the first child process is created, but closes both ends after the second process is created. This is to create the second child process, sub-processes can inherit the complete channel, rather than the two-segment channel has been closed.