Process chapter - inter process communication: pipe(), mkfifo()

explain:
   this article aims to summarize the backup and facilitate future query. As it is a personal summary, if there is any error, please correct it; In addition, most of the content comes from the Internet, books, and various manuals. If you infringe, please inform us and delete the post immediately to apologize.
   QQ group No.: 513683159 [mutual learning]
Content source:
   Linux system programming, Linux network programming
  The concept of pipeline in Linux,[Linux] Linux pipeline

pipe

   pipeline is the oldest way of process communication in UNIX family. It is also a file in essence, but different from general files, it does not occupy disk or other external storage space, and occupies memory space in implementation. Therefore, pipeline is actually a kind of: the operation mode is the memory buffer of file.
  the kernel is used to establish channels between two processes, connect the standard input and standard output between the two processes, and transfer data between processes by reading and writing.

1, Anonymous pipeline:

  it can also be called nameless pipe and half duplex pipe
   use "|" in the shell to represent the pipe.
  a way to communicate between processes with common ancestors:
     the parent process creates a pipeline file before generating the child process, so that the child process can obtain the file descriptor by copying the address space of the parent process. The file of the file descriptor is shared and set by both parent and child processes, and only one party can write and the other party can read. Then the file is called a pipeline. The parent and child processes use the file (pipeline) to achieve the purpose of communication.
   summary: because the file has no file name, the non parent process cannot be opened and can only be used for the communication of relative processes. Because there is no file name, it is called anonymous pipeline.

(1) pipe() function

   1. Function introduction: create one-way communication channel (pipeline)
     if successful, two file descriptors will be stored in pipes, and the bytes written to pipes [1] can be read from pipes [0].

project explain
Function prototype extern int pipe (int __pipedes[2]) __THROW __wur;
Header file unistd.h
Parameter description __ Pipes [2]: file descriptor
Return value 0 if successful
If it fails, - 1 is returned
be careful ① fildes[0] is a file descriptor with the read only attribute
② fildes[1] is a file descriptor with a write only attribute

   2. Example practice:
     < 1 > source code: pipe.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

int main (int argc,char *argv[])
{
	/* Step 1 initialization */
	pid_t pid;						// PID value
	int result = 1;					//Pipe creation results
	int fd[2];						//File descriptor
	int nbytes;						//Number of characters
	char string[]="Hello,The Conduit";
	char readbuffer[80];		
	/*File descriptor 0 is used for reading and file descriptor 1 is used for writing*/
	int *read_fd=&fd[0];			//Read file descriptor
	int *write_fd= &fd[1];			//Write file descriptor
	
	/* Step 2 Establish pipeline */
	result = pipe(fd);			
	if(result == -1)				//Pipe creation failed
	{
		printf("Failed to establish pipeline\n"); 
		return -1;						
	}	

	/* Step 3 New process */
	pid = fork();			
	if( pid == -1)					//New process failed
	{
		printf("fork Process failed\n");
		return -1;			
	}

	/*Step 4 Communication between parent and child processes*/
	if(pid == 0)					/* Subprocess */	
	{	
		close(*read_fd);			//Close the reader
		/*Write character to pipe end*/
		result = write(*write_fd,string,strlen(string));
		return 0;
	}
	else							/* Parent process */	
	{
		close(*write_fd);			//Close write side
		/*Read value from pipe*/
		nbytes = read(*read_fd,readbuffer,sizeof(readbuffer));
		printf("Received%d Data, content:%s\n",nbytes,readbuffer);
				
	}
	return 0;
}

     < 2 > compilation run and output results:
       ① compile: gcc pipe.c -o pipe
       ② operation:. / pipe
        ③ output result: 13 data received, the content is: Hello, pipeline

(2) Pipe blockage and atomicity of pipe

  1 ️⃣ When the write end of the pipe is not closed:
   ① if the number of bytes of write request is greater than the threshold pipe_ At buf,
     the return value of write operation is the current number of data bytes in the pipeline
   ② if the number of bytes of write request is not greater than the threshold pipe_ At buf,
     the return value of write operation is the number of existing data bytes in the pipeline (the amount of data in the pipeline is less than the requested amount of data)
     the return value of write operation is the number of bytes requested and the number of data bytes (the amount of data in the pipeline is not less than the amount of data requested)
  2 ️⃣ When writing to a pipeline:
   ① if the number of written data is less than 128K, the writing is non atomic.
   ② if the number of bytes written twice in the parent process is changed to 128K (when the amount of data written to the pipeline is greater than 128K), the data in the buffer will be continuously written to the pipeline until all the data are written. If no process reads the data, it will be blocked all the time.
  PS:
    PIPE_BUF is defined in include/Linux/limits.h. different kernel versions may differ.
  3 ️⃣ Example practice:
     ① source file: test.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define K 1024
#define WRITELEN (128*K)
int main (int argc,char *argv[])
{
	/* Step 1 initialization */
	pid_t pid;							// PID value
	int result = 1;						//Pipe creation results
	int fd[2];							//File descriptor
	int nbytes;							//Number of characters
	char string[WRITELEN]="Hello,The Conduit";
	char readbuffer[10*K]={0};		   		//Read buffer
	/*File descriptor 0 is used for reading and file descriptor 1 is used for writing*/
	int *read_fd=&fd[0];				//Read file descriptor
	int *write_fd= &fd[1];				//Write file descriptor
	


	/* Step 2 Establish pipeline */
	result = pipe(fd);			
	if(result == -1)					//Pipe creation failed
	{
		printf("Failed to establish pipeline\n"); 
		return -1;						
	}	

	/* Step 3 New process */
	pid = fork();				
	if( pid == -1)						//New process failed
	{
		printf("fork Process failed\n");
		return -1;			
	}

	/*Step 4 Communication between parent and child processes*/
	if(pid == 0)						/* Subprocess */	
	{	
		int write_size = WRITELEN;		//Write length
		result = 0;						//result
		close(*read_fd);				//Close the reader
		/*Write character to pipe end*/
		while (write_size >= 0)
		{
			result = write(*write_fd,string,write_size);
			if (result > 0)				/* Write successful */
			{
				write_size -= result;	//Write length	
				printf("write in%d Data, remaining%d Data\n",result,write_size);
			}
			else						/* Write failed */
			{
				sleep(10);				//Wait for 10s, and the reader will read out the data
			}
		}
		return 0;
	}
	else							/* Parent process */	
	{
		close(*write_fd);			//Close write side
		/*Read value from pipe*/
		while (1)					//Keep reading data
		{
			nbytes = read(*read_fd,readbuffer,sizeof(readbuffer));
			if (nbytes <= 0)		//Failed to read data
			{
				printf("No data has been written\n");
				break;				//Exit loop
			}	
			printf("Received%d Data, content:%s\n",nbytes,readbuffer);
		}		
	}
	return 0;
}

     ② compilation operation and results:
          < 1 > compile: gcc test.c -o test
       < 2 > run:. / test
       < 3 > results:

10240 data received, the content is:Hello,The Conduit
 10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
10240 data received, the content is:
8192 data received, the content is:
131072 data are written, and 0 data remain

     ③ analysis:
        it can be found that the parent process reads 10K bytes of data every time, reads all the data 13 times, and reads only 8K data in the last time. Because there is only 8K data left in the buffer.
The        word process writes 128K bytes of data at one time. When the parent process reads all the data, the write() function of the child process prints the corresponding information.

2, Named pipe:

   because the anonymous pipeline has no file name, it cannot realize the communication between different processes, so a named pipeline is generated.
   because the named pipeline does not support file positioning operations such as lseek(), it strictly abides by the first in first out principle to transmit data, that is, the data is always returned from the beginning when reading the pipeline, and the data is always added to the end when writing it, so this pipeline is also called FIFO file
   the named pipeline provides a path name associated with it. It exists in the file system in the form of FIFO file. A physical file is generated in the file system. As long as other processes access the file path, they can communicate with each other through the pipeline. Open the pipeline file in read-only mode on the read data side and write only mode on the write data side
  named pipes are different from ordinary pipes.
     ① in the file system, named pipes exist in the form of equipment special files.
     ② different processes can share data through named pipes.
   difference between FIFO file (named pipeline) and ordinary file:
     ① ordinary files cannot be managed in byte stream mode, and accessing shared resources among multiple processes will cause unexpected problems;
     ② FIFO files are managed in byte stream mode, following the principle of first in first out, and does not involve access to shared resources.

(1) Create FIFO

   ① shell creation, instruction:: mkfifo
Create a named pipe named namedfifo under the directory / ipc

mkfifo /ipc/namedfifo
ls -l /ipc/namedfifo

   ② created in C language, function mkfifo() function

#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char* pathname,mode_t mode);

(2) FIFO operation

   for named pipeline FIFO, IO operation is basically the same as ordinary pipeline IO operation, and there is a main difference between them.
     in FIFO, an open() function must be used to explicitly establish a channel connected to the pipeline.
     generally speaking, FIFO is always blocked. That is, if the read permission is set when the named pipeline FIFO is opened, the read process will be "blocked" until other processes open the FIFO and write data to the pipeline. This blocking action is also true in turn. If a process opens a pipeline to write data, when no process reads data from the pipeline, the operation of writing to the pipeline is also blocked. The write operation can not be carried out until the written data is read out. If you don't want to block the named pipe operation, you can use o in the open() call_ Nonblock flag to turn off the default blocking action.

Tags: Linux Operation & Maintenance Embedded system server

Posted on Sun, 28 Nov 2021 04:17:41 -0500 by brattt