Linux inter-process communication-Pipelines

Source: Internet
Author: User
Document directory
  • In Linux, famous pipelines can be created in two ways: Command Line mknod System Call and function mkfifo.
Linux inter-process communication mechanism:

1. Communication between processes on the same host:

Unix: famous pipe fifo, unknown PIPE, Signal

SystemV: semaphore, message queue, and shared memory

2. Network Communication: RPC (Remote Procedure Call) and Socket

MPs queue

The pipeline is the oldest method of inter-process communication. It includes two types: anonymous pipeline and famous pipeline. The former can be used for inter-process communication with kinship, it can be used for communication between the parent process and the child process. The latter overcomes the restriction that the MPs queue has no name. Therefore, in addition to the functions of the former, it also allows communication between unrelated processes and can be used for communication between any two processes running on the same machine.

The unknown pipeline is created by the pipe () function:

# I nclude <unistd. h>
Int pipe (int filedis [2]);

The filedis parameter returns two file descriptors: filedes [0] is read and filedes [1] is write. Output of filedes [1] is the input of filedes [0. An unknown pipeline occupies two file descriptors and cannot be shared by non-kinship processes. It is generally used in parent and child processes.

Features:

Half-duplex one-way, parent-child process, write a read segment at one end, no name, limited buffer, no data format

Unknown pipelines are often used in parent and child processes. They can be simply divided into one-way pipeline stream models and two-way pipeline stream models. one-Way MPs queue streams are divided into the MPs queue that flows from the parent process to the child process and the MPs queue that flows from the child process to the parent process.

The following is an example of data flow from the parent process to the child process: the parent process writes a line of characters to the pipe, and the child process reads and prints the data

On the screen.

[Bill @ billstone Unix_study] $ cat pipe1.c

# Include <unistd. h>

# Include <stdio. h>

# Include <sys/types. h>

# Include <assert. h>

Int main ()

{

Int fildes [2];

Pid_t pid;

Int I, j;

Char buf [256];

Assert (pipe (fildes) = 0); // create an MPS queue

Assert (pid = fork ()> = 0); // create a sub-process

If (pid = 0) {// sub-process

Close (fildes [1]); // The sub-process closes the pipeline output.

Memset (buf, 0, sizeof (buf ));

J = read (fildes [0], buf, sizeof (buf ));

Fprintf (stderr, "[child] buf = [% s] len [% d] \ n", buf, j );

Return;

}

Close (fildes [0]); // The parent process closes the pipeline input.

Write (fildes [1], "hello! ", Strlen (" hello! "));

Write (fildes [1], "world! ", Strlen (" world! "));

Return 0;

}

[Bill @ billstone Unix_study] $ make pipe1

Cc pipe1.c-o pipe1

[Bill @ billstone Unix_study] $./pipe1

[Child] buf = [hello! World!] Len [12] // The data written by two parent processes can be read at one time by the sub-process

[Bill @ billstone Unix_study] $

As shown above, close fildes [0] in the parent process, write data to fildes [1], and disable filedes [1] In the child process.

Fildes [0] can read data from the parent process to the child process pipeline.

In the process communication, we cannot determine the number of packets in each communication, that is, we cannot split the data stream by ourselves, in the ear, the preceding neutron process reads messages sent by the parent process twice at a time.

Pipeline is a one-way communication method between processes. To achieve two-way communication between processes, you must use two pipelines. The creation process of two-way pipeline flow is as follows:

(1) Create an MPS queue and return the file descriptors fildes1 and fildes2 of the two unnamed MPs Queues:

(2) create a sub-process that inherits the pipelines fildes1 and fildes2.

(3) The parent process closes the read-only file descriptor fildes1 [0] And writes only the descriptor fildes2 [1].

(4) Write-only file descriptor fildes1 [1], read-only descriptor fildes2 [0]

The creation result is as follows:

Parent process -- write --> fildes1 [1] -- MPs queue --> fildes1 [0] -- read --> sub-process

Parent Process <-- read -- fildes2 [0] <-- MPs queue -- fildes2 [1] <-- write -- sub process

Here is an example of two-way communication between parent and child processes: the parent process sends data twice to the child process, and then receives the data transmitted by the child process.

.

In order to correctly split the time, the pipe from the parent process to the child process uses the 'fixed length' method to transmit data; from the child process to the child process

The pipe of the parent process uses the 'explicit length' method to return data.

(1) Fixed Length

Char bufG [255];

Void WriteG (int fd, char * str, int len ){

Memset (bufG, 0, sizeof (bufG ));

Sprintf (bufG, "% s", str );

Write (fd, bufG, len );

}

Char * ReadG (int fd, int len ){

Memset (bufG, 0, sizeof (bufG ));

Read (fd, bufG, len );

Return (bufG );

}

In this design, the Parent and Child programs need to specify the length of each data transmission, and the length cannot exceed 255 characters.

(2) Explicit Length

Char bufC [255];

Void WriteC (int fd, char str []) {

Sprintf (bufC, "% 04d % s", strlen (str), str );

Write (fd, bufC, strlen (bufC ));

}

Char * ReadC (int fd ){

Int I, j;

Memset (bufC, 0, sizeof (bufC ));

J = read (fd, bufC, 4 );

I = atoi (bufC );

J = read (fd, bufC, I );

Return (bufC );

}

The parent-child process specifies the message length before sending a message.

(3) Main Program

# Include <unistd. h>

# Include <stdio. h>

# Include <assert. h>

# Include <sys/types. h>

Int main ()

{

Int fildes1 [2], fildes2 [2];

Pid_t pid;

Char buf [255];

Assert (pipe (fildes1) = 0 );

Assert (pipe (fildes2) = 0 );

Assert (pid = fork ()> = 0 );

If (pid = 0 ){

Close (fildes1 [1]);

Close (fildes2 [0]);

Strcpy (buf, ReadG (fildes1 [0], 10 ));

Fprintf (stderr, "[child] buf = [% s] \ n", buf );

WriteC (fildes2 [1], buf );

Strcpy (buf, ReadG (fildes1 [0], 10 ));

Fprintf (stderr, "[child] buf = [% s] \ n", buf );

WriteC (fildes2 [1], buf );

Return (0 );

}

Close (fildes1 [0]);

Close (fildes2 [1]);

WriteG (fildes1 [1], "hello! ", 10 );

WriteG (fildes1 [1], "world! ", 10 );

Fprintf (stderr, "[father] buf = [% s] \ n", ReadC (fildes2 [0]);

Fprintf (stderr, "[father] buf = [% s] \ n", ReadC (fildes2 [0]);

Return 0;

}

The execution result is as follows:

[Bill @ billstone Unix_study] $ make pipe2

Cc pipe2.c-o pipe2

[Bill @ billstone Unix_study] $./pipe2

[Child] buf = [hello!]

[Child] buf = [world!]

[Father] buf = [hello!]

[Father] buf = [world!]

[Bill @ billstone Unix_study] $

Dup dup2 copy file descriptor

In Linux, famous pipelines can be created in two ways: Command Line mknod System Call and function mkfifo.

The following two channels generate a famous pipe named myfifo under the current directory:

Method 1: mkfifo ("myfifo", "rw ");

Method 2: mknod myfifo p

After a famous pipeline is generated, you can use common file I/O functions such as open, close, read, and write to operate it.

Pipeline is the oldest tool for inter-process communication in UNIX. It provides a one-way communication method between processes.

Popen Model

From the previous program, we can see that it takes multiple steps to create a pipe to connect to the standard I/O, which requires a lot of code.

To simplify this operation, it provides a set of function implementations. The prototype is as follows:

# Include <stdio. h>

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

Int pclose (FILE * stream );

When the function popen is called successfully, a standard I/O FILE stream is returned. Its read/write attribute is determined by the parameter type.

Here is an instance that simulates the shell command 'ps-ef | grep init.

[Bill @ billstone Unix_study] $ cat pipe3.c

# Include <stdio. h>

# Include <assert. h>

Int main ()

{

FILE * out, * in;

Char buf [255];

Assert (out = popen ("grep init", "w "))! = NULL); // create a write pipeline stream

Assert (in = popen ("ps-ef", "r "))! = NULL); // create a read pipeline stream

While (fgets (buf, sizeof (buf), in) // read ps-ef results

Fputs (buf, out); // forward to grep init

Pclose (out );

Pclose (in );

Return 0;

}

[Bill @ billstone Unix_study] $ make pipe3

Cc pipe3.c-o pipe3

[Bill @ billstone Unix_study] $./pipe3

Root 1 0 0 Apr15? 00:00:04 init

Bill 1392 1353 0 Apr15? 00:00:00/usr/bin/ssh-agent/etc/X11/xinit/Xclients

Bill 14204 14203 0 00:00:00 pts/0 grep init

[Bill @ billstone Unix_study] $ ps-ef | grep init

Root 1 0 0 Apr15? 00:00:04 init

Bill 1392 1353 0 Apr15? 00:00:00/usr/bin/ssh-agent/etc/X11/xinit/Xclients

Bill 14207 1441 0 00:00:00 pts/0 grep init

[Bill @ billstone Unix_study] $

You can compare the execution results with the Shell command 'ps-ef | grep init.

Famous pipe FIFO

FIFO can be used throughout the system.

In Shell, you can use the mknod or mkfifo command to create an MPS queue. In C Programs, you can use the mkfifo function to create a famous MPs queue.

To use a famous Pipeline, You need to perform the following steps:

(1) Create an MPS queue File

(2) Open the MPs queue file in write-only mode in a process and write the MPs queue.

(3) Open the MPs queue file in read-only mode in a process and read the MPs queue.

(4) Close the MPs queue.

Both the low-level file programming library and the standard file programming library can operate the pipeline. The two ends must be opened at the same time before the pipeline performs the read/write operation. No

The process that executes an operation to open the pipeline will be blocked until a process opens the pipeline in the opposite direction.

C code

  1. /* Writable oserver. c: write information to FIFO */
  2. # Include <sys/types. h>
  3. # Include <sys/stat. h>
  4. # Include <errno. h>
  5. # Include <fcntl. h>
  6. # Define export o_server "FIFO4"
  7. Main (int argc, char ** argv)
  8. {
  9. Int fd = 0;
  10. Char w_buf [4096];
  11. Int real_wnum;
  12. Memset (w_buf, 0,4096 );
  13. If (mkfifo (kerbero_server, O_CREAT | O_EXCL | 0666) <0) & (errno! = EEXIST ))
  14. Printf ("cannot create external oserver \ n ");
  15. /* Open dependency exists here, that is, if no read end opens the FIFO, the write end will be blocked on the write end */
  16. Fd = open (kerbero_server, O_WRONLY );
  17. If (fd =-1)
  18. Printf ("open error; no reading process \ n ");
  19. Printf ("% d \ n", fd );
  20. Real_wnum = write (fd, w_buf, 2048 );
  21. If (real_wnum =-1)
  22. Printf ("write to fifo error; try later \ n ");
  23. Else
  24. Printf ("real write num is % d \ n", real_wnum );
  25. /* Data written to the FIFO is atomic. If there is not enough space, it will wait, instead of writing. */
  26. Real_wnum = write (fd, w_buf, 4096 );
  27. If (real_wnum =-1)
  28. Printf ("write to fifo error; try later \ n ");
  29. Else
  30. Printf ("real write num is % d \ n", real_wnum );
  31. }

C code

  1. /* Define oclient. c: read data from the FIFO */
  2. # Include <sys/types. h>
  3. # Include <sys/stat. h>
  4. # Include <errno. h>
  5. # Include <fcntl. h>
  6. # Define export o_server "FIFO4"
  7. Main (int argc, char ** argv)
  8. {
  9. Char r_buf [4096];
  10. Int fd;
  11. Int r_size;
  12. Int ret_size;
  13. R_size = atoi (argv [1]);
  14. Memset (r_buf, 0, sizeof (r_buf ));
  15. Fd = open (FIFO_SERVER, O_RDONLY );
  16. If (fd =-1)
  17. {
  18. Printf ("open % s for read error \ n ");
  19. Exit (1 );
  20. }
  21. Printf ("% d \ n", fd );
  22. While (1)
  23. {
  24. Ret_size = read (fd, r_buf, r_size );
  25. If (ret_size =-1)
  26. Printf ("no data avlaible \ n ");
  27. Else
  28. Printf ("real read bytes % d \ n", ret_size );
  29. Sleep (1 );
  30. }
  31. Unlink (kerbero_server );
  32. }

The following is a simple example.

First, write process: Create a FIFO file, open the write port, read the standard input, and send the input information to the MPs queue.

When 'exit 'or 'quit' is input in the disk, the program exits.

[Bill @ billstone Unix_study] $ cat export o1.c

# Include <stdio. h>

# Include <assert. h>

# Include <sys/types. h>

# Include <sys/stat. h>

# Include <sys/errno. h>

Extern int errno;

Int main ()

{

FILE * fp;

Char buf [255];

Assert (mkfifo ("myfifo", S_IFIFO | 0666)> 0) | (errno = EEXIST ));

While (1 ){

Assert (fp = fopen ("myfifo", "w "))! = NULL );

Printf ("please input :");

Fgets (buf, sizeof (buf), stdin );

Fputs (buf, fp );

Fclose (fp );

If (strncmp (buf, "quit", 4) = 0 | strncmp (buf, "exit", 4) = 0)

Break;

}

Return 0;

}

[Bill @ billstone Unix_study] $ make every O1

Cc unzip o1.c-o unzip O1

[Bill @ billstone Unix_study] $

Then the read process: Open the read port of the MPs queue, read information from the MPs Queue (in behavior units), and print the information to the screen.

The program exits when 'exit 'or 'quit' is obtained.

[Bill @ billstone Unix_study] $ cat export o2.c

# Include <stdio. h>

# Include <assert. h>

# Include <sys/types. h>

# Include <sys/stat. h>

Int main ()

{

FILE * fp;

Char buf [255];

While (1 ){

Assert (fp = fopen ("myfifo", "r "))! = NULL );

Fgets (buf, strlen (buf), fp );

Printf ("gets: [% s]", buf );

Fclose (fp );

If (strncmp (buf, "quit", 4) = 0 | strncmp (buf, "exit", 4) = 0)

Break;

}

Return 0;

}

[Bill @ billstone Unix_study] $ make writable O2

Cc fifo2.c-o fifo2

[Bill @ billstone Unix_study] $

Execute ikeo1 on one terminal, and execute ikeo2.

Enter 'hello', 'World', and then 'exit 'to exit:

[Bill @ billstone Unix_study] $./1_o1

Please input: hello

Please input: world

Please input: exit

[Bill @ billstone Unix_study] $

The read result is as follows:

[Bill @ billstone Unix_study] $./1_o2

Gets: [hello

] Gets: [world] gets: [exit] [bill @ billstone Unix_study] $

When you see the output above, you may think that I wrote a mistake. Actually, it is not. The reading result is exactly like this. In fact, according to our intention,

The correct output result should be as follows:

[Bill @ billstone Unix_study] $./1_o2

Gets: [hello

] Gets: [world

] Gets: [exit

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.