[UNIX Network Programming] inter-process communication pipeline

Source: Internet
Author: User

A pipe is the earliest form of communication between Unix processes. It exists in all UNIX implementations. You need to know the following about pipelines:

1. It is half-duplex, that is, data can only flow in one direction. Although pipelines can be full-duplex in Some UNIX implementations, some system settings are required. In Linux, it is half-duplex.

2. It has no name, so it can only be used between processes with common ancestor. It is usually used between parent and child processes. Although this is corrected with the addition of the "famous pipe FIFO", we should regard them as two different inter-process communication methods.

3. It is created by the pipe function, accessed by the Read and Write Functions, and provides one-way data stream. In addition to pipe, in the C function library, another function, popen, is used to create a new pipeline, start a new process, disable the unused end of the pipeline, execute shell commands, and wait for command termination.


Pipeline example:

In shell commands, we often use commands such as "cmd1 | cmd2". cmd1 and cmd2 are connected through pipelines. Shell is responsible for standard input and standard output of two commands:

The standard input of cmd1 comes from the terminal keyboard.

The standard output of cmd1 is passed to cmd2 as its standard input.

The standard output of cmd2 is connected to the terminal screen.


Knowledge Point 1: pipe Function

# Include <unistd. h> int pipe (int fd [2]); // return value: if the operation succeeds, 0 is returned. If the operation fails,-1 is returned.

The process calls the pipe function to create an MPS queue. The pipe function parameter is a pointer to an array consisting of two integer file descriptors. This function successfully fills in two new file descriptors in the array and returns 0. If the file fails,-1 is returned and errno is set to indicate the cause of the failure. The errno value has three possibilities:

Emfile: The process uses too many file descriptors.

Enfile: The system file table is full.

Efault: The file descriptor is invalid.

Two newly filled file descriptors: FD [0] is opened for reading, and FD [1] is opened for writing. The output of FD [1] is the input of FD [0. That is to say, all data written to fd [1] using the write function can be read from Fd [0. Example:

#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#define MAXLINE 2048intmain(int argc, char **argv){int fd[2];int data;char buff[MAXLINE];const char some_data[] = "123";memset(buff, '\0', sizeof(buff));if(pipe(fd) == -1){exit(EXIT_FAILURE);}else{data = write(fd[1], some_data, strlen(some_data));data = read(fd[0], buff, data);printf("read %d bytes : %s\n", data, buff);exit(EXIT_SUCCESS);}}

Program running result:

[email protected]:/work/tmp/unp$ ./a.out read 3 bytes : 123

The above example shows how to use pipelines in the same process, but it is rarely used in actual use. Generally, it is used to communicate between two different processes (usually parent-child processes. Example of using pipelines between two processes:

# Include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <string. h> # define maxline 2048 intmain (INT argc, char ** argv) {int FD [2]; int data; pid_t child_pid; char buff [maxline]; const char some_data [] = "123"; memset (buff, '\ 0', sizeof (buff); If (pipe (FD) = 0) {child_pid = fork (); If (child_pid =-1) {fprintf (stderr, "fork error. "); exit (exit_failure);} else if (child_pid = 0) {close (FD [1]); // disable the write-side data = read (FD [0], buff, maxline) of the sub-process; // read data from the read segment of the sub-process printf ("read % d Bytes: % s \ n ", Data, buff); exit (exit_success);} else {close (FD [0]); // close the read segment data = write (FD [1], some_data, strlen (some_data) of the parent process )); // write data printf ("wrote % d bytes \ n", data) from the writing end of the parent process; }}exit (exit_success );}

The program running result is:

[email protected]:/work/tmp/unp$ ./a.out wrote 3 bytesread 3 bytes: 123

Or

[email protected]:/work/tmp/unp$ ./a.out wrote 3 bytes[email protected]:/work/tmp/unp$ read 3 bytes: 123
This is because if the parent process ends before the child process, a shell prompt is displayed. As shown in the preceding example, to complete the communication between parent and child processes through the MPs queue, the parent process first creates an MPS queue and then calls fork to derive a copy of itself. Then, the parent process closes the Reading end of the MPs queue, and the child process closes the writing end of the same MPs queue. This provides a one-way data flow between parent and child processes.

When one end of the MPs queue is closed, the following two rules apply:

1. When a write end has been closed, when all data is read, read returns 0 to indicate that the end of the file has been reached.

2. if you write a read-end closed pipeline, the sigpipe signal is generated. If this signal is ignored or captured and returned from its handler, write returns-1 and errno is set to epipe.


The two examples above are half-duplex, that is, one-way, and only one direction of data flow is provided. When a two-way data flow is required, two pipelines must be created, one in each direction. The actual steps are as follows:

1. Create MPs queue 1 and MPs queue 2

2. Fork

3. The parent process closes the Reading end of MPs queue 1 and the writing end of MPs queue 2.

3. The sub-process closes the write end of MPs queue 1 and the read end of MPs queue 2.

After creating two pipelines, you can complete a simple client-server example. For related examples, click here.


Knowledge Point 2: popen and pclose Functions

The popen and pclose functions are not implemented in Unix. They are provided by the standard I/O library. When they are implemented, they create a pipeline and call fork to generate a sub-process, close the unused end of the MPs queue, execute a shell to run the command, and wait for the command to terminate.

# Include <stdio. h> file * popen (const char * character string, const char * type); // return value: If successful, the file pointer is returned. If an error occurs, the nullint pclose (File * FP) is returned ); // return value: the termination status of the consumer string. If an error occurs,-1 is returned.
The function popen executes fork first, then calls exec to execute explain string, and returns a standard I/O file pointer. If the type is "r", the file pointer is connected to the standard output of the response string, and the returned file pointer is readable. If the type is "W", the file pointer is connected to the standard input of objective string, and the returned file pointer can be written. The popen is shown as follows:

If the type is "r", the output of the called program can be used by the calling program. The calling program can use the File pointer returned by the popen function to use common stdio library functions (such as fread) to read the output of the called program. If the type is "W", the calling program can use fwrite to send data to the called program, the called program can read the data on its own standard input.
The example program of type R is as follows:
# Include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <string. h> intmain (INT argc, char ** argv) {file * read_fp; char buff [bufsiz + 1]; int chars_read; memset (buff, '\ 0 ', sizeof (buff); read_fp = popen ("uname-a", "R"); // open the pipeline that connects to the uname command, set the pipeline to readable and point read_fp to this command to output if (read_fp! = NULL) {chars_read = fread (buff, sizeof (char), bufsiz, read_fp); If (chars_read> 0) printf ("output was: -\ n % s \ n ", buff); pclose (read_fp); exit (exit_success );}
Running result:
Output was : -Linux book-desktop 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:04:26 UTC 2009 i686 GNU/Linux
The example program of type W is as follows:
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>intmain(int argc, char **argv){FILE *fp;char buffer[BUFSIZ + 1];sprintf(buffer, "Once upon a time there was ...\n");fp = popen("od -c", "w");if(fp != NULL){fwrite(buffer, sizeof(char), strlen(buffer), fp);pclose(fp);exit(EXIT_SUCCESS);}exit(EXIT_SUCCESS);}
The program result is as follows:
0000000   O   n   c   e       u   p   o   n       a       t   i   m   e0000020       t   h   e   r   e       w   a   s       .   .   .  \n0000037
The above pipe function can also be used to implement client-server programs. Click this link for sample code.
Reference: 1. the illustration above: http://blog.csdn.net/to_be_it_1/article/details/28138063
2. Linux Program Design Neil Matthew & Richard stones3, Unix environment advanced programming, Richard Steven son4, UNIX Network Programming volume 2, Richard Steven son





Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.