Comunicación entre procesos de Linux | comunicación de tubería

Comunicación de canalización

1. Introducción a las canalizaciones

Una tubería es una forma de comunicación entre procesos en Linux, que conecta la salida de un programa directamente con la entrada de otro programa. Hay dos tipos principales de tuberías: tuberías sin nombre y tuberías con nombre.

Tubería sin nombre Pipa famosa
Un método primitivo de comunicación por tubería en Linux Una mejora de la tubería sin nombre
Solo se puede utilizar para la comunicación entre procesos relacionados Dos procesos no relacionados pueden comunicarse entre sí
Modo de comunicación simplex con extremos fijos de lectura y escritura Puede especificar el modo de lectura y escritura al abrir la canalización
Puede usar read () / write (), no pertenece al sistema de archivos y solo existe en la memoria Mediante la operación de E / S de archivo, el contenido se almacena en la memoria

Tuberías sin nombre y tuberías con nombre
Tuberías sin nombre y tuberías con nombre

2. Tubería sin nombre

2.1 Creación y cierre de tuberías sin nombre

El método de comunicación basado en el descriptor de archivo cuando se usa la tubería sin nombre. Cuando se crea una tubería, creará dos descriptores de archivo: fd [0] y fd [1], donde fd [0] es fijo para la tubería de lectura y fd [1] es fijo para la tubería de escritura. Esto constituye un canal de datos unidireccional.
La creación de una tubería se puede lograr mediante pipe ()

/*****pipe()函数*****/
函数原型:int pipe(int fd[])
传 入 值:fd[]是包含两个元素的数组,存放管道对应的文件描述符
返 回 值:成功返回0;失败返回-1

Cuando la tubería está cerrada, simplemente use la función close () para cerrar los dos descriptores de archivo.

2.2 Lectura y escritura de tubería sin nombre

Ambos extremos de la tubería creada con la función pipe () están en un proceso. Dado que las canalizaciones se utilizan principalmente para la comunicación entre diferentes procesos, normalmente se crea una canalización primero y luego se llama a la función fork () para crear un proceso hijo, que heredará la canalización del proceso padre. En este momento, la relación correspondiente entre los descriptores de archivo de la canalización del proceso principal-secundario se muestra en la figura de la izquierda a continuación.
Debido al modo de trabajo simplex de las tuberías sin nombre, el proceso solo puede leer la tubería o escribir en la tubería. Por lo tanto, solo se puede usar uno de ellos (por ejemplo, se puede acordar que el proceso padre lee la tubería y el proceso hijo escribe la tubería). De esta manera, los descriptores de archivos de lectura o escritura no utilizados deben cerrarse. Como se muestra en la figura de la derecha a continuación, el final de escritura del proceso padre y el final de lectura del proceso hijo se cierran y se establece una canalización de "el proceso hijo escribe en el proceso padre para leer".
Inserte la descripción de la imagen aquí
Atención de lectura y escritura en canalización

  • Solo tiene sentido escribir datos en la tubería cuando existe el extremo de lectura de la tubería. De lo contrario, el proceso que escribe datos en la canalización recibirá la señal SIGPIPE del kernel.
  • Al escribir datos en la tubería, Linux no garantizará la atomicidad de la escritura. Siempre que el búfer de la tubería tenga espacio, el proceso de escritura intentará escribir datos en la tubería. Si el búfer de la canalización está lleno, la operación de escritura siempre se bloqueará
  • Cuando los procesos padre e hijo se están ejecutando, su orden no está garantizado. Para garantizar que los procesos padre e hijo y los descriptores de archivo correspondientes estén cerrados, la función sleep () se puede llamar en los dos procesos

Programa de ejemplo

/*****pipe.c*****/
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_DATA_LEN 256

int main(){
    
    
	pid_t pid;
	int pipe_fd[2];
	char buf[MAX_DATA_LEN];
	const char data[] = "Pipe test program";
	int real_read,real_write;
	
	memset(buf,0,sizeof(buf));
	if(pipe(pipe_fd) < 0){
    
    		//创建管道
		perror("fail to pipe");
		exit(-1);
	}
	if((pid = fork()) == 0){
    
    	//创建子进程
		/*子进程关闭写描述符,并通过是子进程暂停1s等待父进程关闭相应的读描述符*/
		close(pipe_fd[1]);
		sleep(1);
		/*子进程读取管道内容*/
		if((real_read = read(pipe_fd[0],buf,MAX_DATA_LEN)) > 0)
			printf("%d bytes read from the pipe is '%s'\n",real_read,buf);
		close(pipe_fd[0]);	//关闭子进程读描述符
		exit(0);
	}else if(pid > 0){
    
    
		close(pipe_fd[0]);	//父进程关闭读描述符
		if((real_write = write(pipe_fd[1],data,strlen(data))) != -1)
			printf("parent wrote %d bytes:'%s'\n",real_write,data);
		close(pipe_fd[1]);	//父进程关闭写描述符
		waitpid(pid,NULL,0); //收集子进程退出信息
		exit(0);
	}
}

Después de compilar y ejecutar, el resultado es el siguiente

linux@linux-virtual-machine:~/andy/proc$ ./pipe
parent wrote 17 bytes:'Pipe test program'
17 bytes read from the pipe is 'Pipe test program'

3. Tubos famosos

3.1 Creación de una pipa famosa

Se puede crear una tubería conocida (FIFO) utilizando la función mkfifo (), que es similar a la operación open () en un archivo, y puede especificar la ruta y los derechos de acceso de la tubería. Después de que la canalización se haya creado con éxito, se pueden usar las funciones open (), read () y write (). Al igual que con los archivos ordinarios, O_RDONLY se puede configurar en open () para tuberías abiertas para lectura, y O_WRONLY se puede configurar en open () para tuberías abiertas para escritura.

/*****mkfifo()函数*****/
函数原型:int mkfifo(const char *filename, mode_t mode)
传 入 值:filename 要创建的管道名
		 mode 管道的访问权限
返 回 值:成功返回0;失败返回-1
Mensaje de error FIFO sentido
EACCESO La ruta del directorio especificada por el nombre de archivo del parámetro no tiene permisos de ejecución
EEXIST El archivo especificado por el nombre de archivo del parámetro ya existe
ENAMETOOLONG El nombre de la ruta del nombre de archivo del parámetro es demasiado largo
ENOENT El archivo contenido en el nombre del archivo de parámetros no existe
ENOSPC Espacio libre insuficiente en el sistema de archivos
ENOTDIR El directorio en la ruta del nombre de archivo de parámetros existe pero no es un directorio real
EROFS El archivo especificado por el nombre de archivo del parámetro existe en el sistema de archivos de solo lectura

Programa de ejemplo

/*****fifo_write.c*****/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#define MYFIFO	"/tmp/myfifo"	//有名管道文件名

int main(int argc, char *argv[]){
    
    	//参数为即将写入的字符串
	int fd;
	int nwrite;
	
	if(argc < 2){
    
    
		printf("Usage: ./fifo_write string\n");
		exit(-1);
	}

	if((fd = open(MYFIFO,O_WRONLY)) < 0){
    
    	//以只写方式打开FIFO管道
		perror("fail to open fifo");
		exit(-1);
	}

	if((nwrite = write(fd,argv[1],strlen(argv[1]+1))) >0)	//向管道写入字符串
		printf("Write '%s' to FIFO\n",argv[1]);
	close(fd);

	return 0;
}
/*****fifo_read.c*****/
/*头文件和宏定义同fifo_write.c*/
int main(){
    
    
	char buf[256];
	int fd, nread;
	/*判断有名管道是否已经存在,若为创建则以相应的权限创建*/
	if(access(MYFIFO,F_OK) == -1){
    
    	//管道文件不存在
		perror("fail to mkfifo");
		exit(-1);
	}

	if((fd = open(MYFIFO,O_RDONLY)) < 0){
    
    
		perror("fail to open fifo");
		exit(-1);
	}

	while(1){
    
    
		memset(buf,0,sizeof(buf));
		if((nread = read(fd,buf,256)) > 0)
			printf("Read '%s' from FIFO\n",buf);
	}
	close(fd);

	return 0
}

Ejecute los dos programas anteriores en dos terminales respectivamente. Primero, inicie el programa de canalización de lectura. Una vez que se establece la canalización, el proceso de lectura comienza a leer el contenido de la canalización de forma cíclica. Si no hay datos en la canalización actual, se bloquea hasta que el proceso de la canalización de escritura escribe datos en la canalización. Después de ejecutar el programa de canalización de escritura, el proceso de lectura puede leer la entrada del usuario desde la canalización. Los resultados de ejecución del programa son los siguientes. La
terminal 1 es la siguiente

linux@linux-virtual-machine:~/andy/proc$ ./fifo_read
Read 'FIFO' from FIFO
Read 'Test' from FIFO

La terminal dos es la siguiente

linux@linux-virtual-machine:~/andy/proc$ ./fifo_write FIFO
Write 'FIFO' to FIFO
linux@linux-virtual-machine:~/andy/proc$ ./fifo_write Test
Write 'Test' to FIFO

Supongo que te gusta

Origin blog.csdn.net/Chuangke_Andy/article/details/108305695
Recomendado
Clasificación