Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How Linux communicates between processes through anonymous pipes

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces how Linux carries out inter-process communication through anonymous channels, which has a certain reference value. Interested friends can refer to it. I hope you will gain a lot after reading this article. Let's take a look at it.

1. What is a pipeline

If you have used the Linux command, you must be familiar with the term pipe, because we usually use the symbol "|" to use pipes, but what is the real definition of management? A pipeline is a channel through which data flows from one process to another, and it is usually used as an input for piping the output of one process to another.

For example, enter the command in shell: ls-l | grep string. We know that the ls command (which is actually a process) lists all the files in the current directory, but it does not output directly. Instead, the data that is supposed to be output to the screen is piped to the grep process as input to the grep process, which then filters the input information. Print the string (in behavioral units) of the information that exists in string on the screen.

Second, use popen function

1. Introduction of popen function and pclose function

Where there is stillness, there is movement. Similarly, the function corresponding to popen function is pclose function. Their prototypes are as follows:

# include FILE* popen (const char * command, const char * open_mode); int pclose (FILE* stream_to_close)

The poen function allows a program to start another program as a new process and can pass data to it or receive data through it. Command is the name of the program to run and the corresponding parameters. Open_mode can only be one of "r (read only)" and "w (write only)". Note that the return value of the popen function is a pointer of type FILE, while Linux treats everything as a file, which means that we can manipulate it using the file handler in the stdio I hand O library.

If open_mode is "r", the main caller can use the output of the called program, and the output of the program can be read through the stdio function (such as fread) through the FILE pointer returned by the function. If open_mode is "w", the main caller can send data to the called program, that is, write data to the called program through stdio functions such as fwrite, and the called program can read the data in its own standard input.

The pclose function closes the associated file stream created by popen. Pclose returns only after the process started by popen ends, and if the called process is still running when pclose is called, the pclose call will wait for the process to finish. It returns the exit code of the process in which the file stream is closed.

2. Examples

In many cases, we don't know the length of the output data at all. in order to avoid defining a very large array as a buffer, we can send data in blocks, reading data one block at a time and sending data one block at a time. Until all the data is sent. The following example is how data is read and sent in this way. The source file is named popen.c and the code is as follows:

# include # include int main () {FILE * read_fp = NULL; FILE * write_fp = NULL; char buffer [BUFSIZ + 1]; int chars_read = 0; / initialize buffer memset (buffer,'\ 0buffer, sizeof (buffer)); / / Open ls and grep processes read_fp = popen ("ls-l", "r"); write_fp = popen ("grep rwxrwxr-x", "w") / / both processes have successfully opened if (read_fp & & write_fp) {/ / read a data block chars_read = fread (buffer, sizeof (char), BUFSIZ, read_fp); while (chars_read > 0) {buffer [chars _ read] ='\ 0buffer; / / write data to grep process fwrite (buffer, sizeof (char), chars_read, write_fp) / / there is still data to read. Read the data in a loop until all data is read chars_read = fread (buffer, sizeof (char), BUFSIZ, read_fp);} / / close the file stream pclose (read_fp); pclose (write_fp); exit (EXIT_SUCCESS);} exit (EXIT_FAILURE);}

The running results are as follows:

From the running results, it achieves the purpose of information screening. The program reads the data in the process ls, and then sends the data to the process grep for filtering processing, which is equivalent to directly entering the command in shell: ls-l | grep rwxrwxr-x.

3. The implementation of popen and its advantages and disadvantages.

When a popen call is requested to run a program, it first starts shell, the sh command in the system, and then passes the command string to it as an argument.

This brings an advantage and a disadvantage. The advantage is that all parameter extensions in Linux are done by shell. So start shell to analyze the command string before starting the program (the command program in command), so that all kinds of shell extensions (such as wildcards) can be completed before the program starts, so that we can start very complex shell commands through popen.

Its disadvantage is: for each popen call, not only to start a requested program, but also to start a shell, that is, each popen call will start two processes, from the perspective of efficiency and resources, the call of the popen function is slower than the normal way.

3. Pipe call

If popen is a high-level function, pipe is an underlying call. Unlike the popen function, it does not need to start a shell to interpret the request command to pass data between two processes, and it also provides more control over reading and writing data.

The prototype of the pipe function is as follows:

# include int pipe (int file_descriptor [2])

We can see that the definition of the pipe function is very special. It returns 0 after two new file descriptors on the wall of the array, returns-1 if it returns, and sets errno to explain the reason for the failure.

The two file descriptors in the array are concatenated in a special way. The data is based on the first-in-first-out principle, and all data written to file_descriptor [1] can be read back from file_descriptor [0]. Because the data is based on the first-in-first-out principle, the data read is consistent with the data written.

Special reminder:

1. From the prototype of the function, we can see that a major difference between it and the popen function is that the popen function is based on the file stream (FILE), while the pipe is based on the file descriptor, so after using pipe, the data must be read and sent using the underlying read and write calls.

2. Do not write data with file_descriptor [0], nor read data with file_descriptor [1]. Its behavior is undefined, but on some systems-1 may be returned to indicate call failure. Data can only be read from file_descriptor [0], and data can only be written to file_descriptor [1], not backwards.

Example:

First, we create a pipe in the original process, then call fork to create a new process, and finally pass data between the two processes through the pipe. The source file is named pipe.c and the code is as follows:

# include # include int main () {int data_processed = 0; int filedes [2]; const char data [] = "Hello pipe!"; char buffer [BUFSIZ + 1]; pid_t pid; / / clear buffer memset (buffer,'\ 0buffer, sizeof (buffer)) If (pipe (filedes) = = 0) {/ / create pipeline successfully / / create child process pid = fork () by calling fork; if (pid = =-1) {fprintf (stderr, "Fork failure"); exit (EXIT_FAILURE) } if (pid = = 0) {/ / read data in child process data_processed = read (filedes [0], buffer, BUFSIZ); printf ("Read% d bytes:% s\ n", data_processed, buffer); exit (EXIT_SUCCESS) } else {/ / parent process / / write data data_processed = write (filedes [1], data, strlen (data)); printf ("Wrote% d bytes:% s\ n", data_processed, data) / / hibernate for 2 seconds, mainly to wait for the child process to finish first, and this is simply to output a good look / / there is no need for the parent process to wait for the child process to end sleep (2); exit (EXIT_SUCCESS);}} exit (EXIT_FAILURE);}

The running result is:

It can be seen that the child process reads the data written by the parent process to filedes [1]. If there is no sleep statement in the parent process, the parent process may end before the end of the child process, so you may see a command prompt separation between the two inputs.

IV. Use pipes as standard input and standard output

Here's a more concise way to pipe two processes. We can set the file descriptor to a known value, typically standard input 0 or standard output 1. The biggest advantage of this is that you can call standard programs, that is, programs that don't need to take a file descriptor as a parameter.

In order to do this, we also need the assistance of two functions, namely the dup function or the dup2 function, whose prototypes are as follows

# include int dup (int file_descriptor); int dup2 (int file_descriptor_one, int file_descriptor_two)

The dup call creates a new file descriptor that points to the same file or pipe as the existing file descriptor as its parameter. For the dup function, the new file description always takes the lowest available value. The new file descriptor created by dup2 is either the same as int file_descriptor_two, or the first one greater than the available value of this parameter. So when we first close the file descriptor 0 and then call dup, the new file descriptor will be the number 0. 0.

Examples

In the following example, first open the pipe, then fork a child process, then in the child process, make the standard input point to the read pipeline, then close the read and write pipes in the child process, leaving only the standard input, and finally call the execlp function to start a new process od, but od does not know whether its data source is a pipe or a terminal. The parent process is relatively simple, first closing the read pipeline, then writing data in the write pipeline, and then closing the write pipeline to complete its task. The source file is pipe2.c and the code is as follows:

# include # include int main () {int data_processed = 0; int pipes [2]; const char data [] = "123"; pid_t pid; if (pipe (pipes) = = 0) {pid = fork (); if (pid = =-1) {fprintf (stderr, "Fork failure!\ n"); exit (EXIT_FAILURE) } if (pid = = 0) {/ / child process / / make standard input point to fildes [0] close (0); dup (pipes [0]); / / close pipes [0] and pipes [1], leaving only standard input close (pipes [0]); close (pipes [1]) / / start a new process od execlp ("od", "od", "- c", 0); exit (EXIT_FAILURE);} else {/ / close pipes [0] because the parent process does not need to read data close (pipes [0]); data_processed = write (pipes [1], data, strlen (data)) / / after writing the data, close pipes [1] close (pipes [1]); printf ("% d-Wrote% d bytes\ n", getpid (), data_processed);}} exit (EXIT_SUCCESS);}

The running result is:

You can see from the running results that the od process has done its job correctly, just as typing od-c and 123 into shell has the same effect.

Discussion on the read operation after the pipeline is closed

Now there is a problem: what happens to the child process if the parent process writes data to the pipeline file_pipe [1] and the child process reads the data in the pipeline file_pipe [0], and when the parent process does not write data to file_pipe [1], the child process has no data to read? Moreover, if the parent process shuts down file_pipe [1], how will the child process react?

When the pipe for writing data is not closed and there is no data to read, the read call usually blocks, but when the pipe for writing data is closed, the read call returns 0 instead of blocking. Note that instead of reading an invalid file descriptor, an invalid file descriptor in read returns-1.

Thank you for reading this article carefully. I hope the article "how Linux communicates between processes through anonymous channels" shared by the editor will be helpful to everyone. At the same time, I also hope that you will support and follow the industry information channel. More related knowledge is waiting for you to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report