[Programación del sistema Linux] 24. Pipeline, pipe, fifo, comunicación de archivos entre procesos

Tabla de contenido

tubería

Principio de realización

rasgo

limitación

comportamiento de lectura y escritura

leer tubo

escribe pipa

tamaño del búfer

valor de retorno

Ventajas y desventajas

ventaja

defecto

tubo

parámetro pipefd[2]

valor de retorno

código de prueba 1

Resultados de la prueba

Código de prueba 2

Resultados de la prueba

Código de prueba 3

Resultados de la prueba

quinceañera

Método de creación

nombre de ruta del parámetro

modo de parámetro

valor de retorno

Código de prueba 4

Resultados de la prueba

Código de prueba 5

Resultados de la prueba

comunicación de archivos entre procesos

Código de prueba 6

Resultados de la prueba

tubería

Principio de realización

El mecanismo de cola de anillo del núcleo se implementa mediante el búfer del núcleo, que es relativamente simple.

rasgo

  1. documento falso.

  2. Los datos de la tubería solo se pueden leer una vez.

  3. Los datos en proceso solo pueden fluir en una dirección.

limitación

  1. Solo puedes escribir tú mismo, no leerlo tú mismo.

  2. Los datos no se pueden leer repetidamente.

  3. comunicación semidúplex.

  4. Disponible entre procesos de parentesco.

comportamiento de lectura y escritura

leer tubo

La canalización tiene datos: leer devuelve el número de bytes realmente leídos.

Tubería sin datos:

  1. Todos los extremos de escritura están cerrados y la función de lectura devuelve 0.

  2. El final de escritura no está cerrado y la función de lectura se bloquea y espera.

escribe pipa

Todos los extremos de lectura están cerrados, terminación anormal causada por la señal SIGPIPE.

El final de lectura no está cerrado:

  1. Los datos de la tubería están llenos, lo que bloquea la espera.

  2. Si los datos de la canalización no están completos, devuelve el número de bytes escritos.

tamaño del búfer

ulimit -a

man 3 fpathconf

 

valor de retorno

Éxito: el tamaño de la tubería.

Fallido: -1.

Ventajas y desventajas

ventaja

En comparación con las señales, los sockets implementan la comunicación entre procesos, que es mucho más simple.

defecto

  1. Sólo es posible la comunicación unidireccional y es necesario establecer dos canales para la comunicación bidireccional.

  2. Sólo se puede utilizar para la comunicación entre procesos padre-hijo y hermanos (con un ancestro común). El problema se resolvió posteriormente utilizando tuberías con nombre quince.

tubo

Cree y abra una canalización.

man 2 pipe

parámetro pipefd[2]

pipefd[0]: fin de lectura.

pipefd[1]: fin de escritura.

valor de retorno

Éxito: 0

Fallido: -1

código de prueba 1

El proceso principal usa la tubería para escribir contenido, el proceso secundario usa la tubería para leer el contenido y envía el contenido leído al terminal.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int GuanDao_flag; //管道标志位
    int pipefd[2];
    char data[1024];   //接收的数据
    int leng;          //接收数据的长度
    pid_t JinCheng_ID; //进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建管道!\n");
    GuanDao_flag = pipe(pipefd); //创建管道
    if (GuanDao_flag == -1)
    {
        perror("创建管道错误");
    }
    printf("开始创建进程!\n");
    JinCheng_ID = fork();
    if (JinCheng_ID > 0) //父进程
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d。\n", getpid(), JinCheng_ID);
        close(pipefd[0]);                                             //关闭读端
        write(pipefd[1], "你好,世界!\n", strlen("你好,世界!\n")); //通过管道向子进程发送数据
        sleep(1);
        close(pipefd[1]);
        printf("这是父进程,父进程结束。\n");
    }
    else if (JinCheng_ID == 0) //子进程
    {
        printf("这是子进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(), getppid());
        close(pipefd[1]);                           //子进程关闭写端
        leng = read(pipefd[0], data, sizeof(data)); //接收父进程发送的数据
        write(STDOUT_FILENO, data, leng);           //将数据写到终端上
        close(pipefd[0]);
        printf("这是子进程,子进程结束。\n");
    }
    return 0;
}

Resultados de la prueba

Código de prueba 2

Utilice tuberías para implementar el comando ls | wc -l.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int GuanDao_flag; //管道标志位
    int pipefd[2];
    char data[1024];   //接收的数据
    int leng;          //接收数据的长度
    pid_t JinCheng_ID; //进程ID

    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());

    printf("开始创建管道!\n");
    GuanDao_flag = pipe(pipefd); //创建管道
    if (GuanDao_flag == -1)
    {
        perror("创建管道错误");
        exit(1);
    }
    printf("创建管道完成!\n");

    printf("开始创建进程!\n");
    JinCheng_ID = fork();
    if (JinCheng_ID == 0) //子进程
    {
        printf("这是子进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(), getppid());
        close(pipefd[1]);              //子进程关闭写端
        dup2(pipefd[0], STDIN_FILENO); //终端输入重定向到管道的读端
        execlp("wc", "wc", "-l", NULL);
        perror("子进程错误");
    }
    else if (JinCheng_ID > 0) //父进程
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d。\n", getpid(), JinCheng_ID);
        close(pipefd[0]);               //关闭读端
        dup2(pipefd[1], STDOUT_FILENO); //终端输出重定向到管道的写端
        execlp("ls", "ls", NULL);
        perror("父进程错误");
    }
    else if (JinCheng_ID == -1)
    {
        perror("创建进程错误");
        exit(1);
    }
    return 0;
}

Resultados de la prueba

Código de prueba 3

Implemente el comando ls | wc -l utilizando el interproceso entre hermanos.

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

int main(int argc, char *argv[])
{
    int GuanDao_flag; //管道标志位
    int pipefd[2];
    pid_t JinCheng_ID; //进程ID
    int i;

    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());

    printf("开始创建管道!\n");
    GuanDao_flag = pipe(pipefd); //创建管道
    if (GuanDao_flag == -1)
    {
        perror("创建管道错误");
        exit(1);
    }
    printf("创建管道完成!\n");

    printf("开始创建进程!\n");
    for (i = 0; i < 2; i++)
    {
        JinCheng_ID = fork();
        if (JinCheng_ID == -1)
        {
            perror("创建进程错误");
            exit(1);
        }
        else if (JinCheng_ID == 0) //子进程
        {
            break;
        }
    }
    if(i==0){
        printf("这是子1进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(), getppid());
        close(pipefd[0]);               //子1进程关闭读端
        dup2(pipefd[1], STDOUT_FILENO); //终端输出重定向到管道的写端
        execlp("ls", "ls", NULL);
        perror("子1进程错误");
    }
    else if(i==1){
        printf("这是子2进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(), getppid());
        close(pipefd[1]);              //子2进程关闭写端
        dup2(pipefd[0], STDIN_FILENO); //终端输入重定向到管道的读端
        execlp("wc", "wc", "-l", NULL);
        perror("子进程错误");
    }
    else if(i==2){
        printf("这是父进程,当前进程的ID是%d。\n", getpid());
        close(pipefd[0]);	//父进程关闭读端、写端,保证兄弟进程之间形成单向通信
        close(pipefd[1]);
        wait(NULL);
        wait(NULL);
        printf("父进程结束。\n");
    }
    return 0;
}

Resultados de la prueba

quinceañera

        Los FIFO a menudo se denominan canalizaciones con nombre para distinguirlas de las canalizaciones. Las tuberías sólo se pueden utilizar entre procesos "relacionados con la sangre". Pero a través de FIFO, procesos no relacionados también pueden intercambiar datos. Los archivos FIFO no tienen bloques de datos en el disco y solo se usan para identificar un canal en el kernel. Cada proceso puede abrir este archivo para lectura/escritura, de hecho, lee y escribe el canal del kernel para realizar la comunicación entre procesos.

Método de creación

mkfifo 管道文件名
man 3 mkfifo

nombre de ruta del parámetro

Nombre de archivo de canalización.

modo de parámetro

Permisos de archivos de canalización.

valor de retorno

Éxito: 0

Fallido: -1

Código de prueba 4

Utilice mkfifo para crear un archivo de canalización.

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

int main(int argc, char *argv[])
{
    int flag;
    flag=mkfifo("GuanDao",0664);
    if(flag==-1){
        perror("创建管道文件错误");
    }
    return 0;
}

Resultados de la prueba

Código de prueba 5

Utilice tuberías para conectarse y comunicarse con dos procesos no relacionados.

/*
CeShi5_1.c
	接收CeShi5_2进程的数据
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int fd, leng;
    char data[4096];
    printf("程序开始运行。\n");
    printf("开始打开管道文件的读端。\n");
    fd = open(argv[1], O_RDONLY);
    if (fd == -1)
    {
        perror("打开管道文件错误");
        exit(1);
    }
    printf("打开管道文件的读端完成。\n");

    printf("开始读取管道文件读端的数据。\n");
    while (1)
    {
        leng = read(fd, data, sizeof(data));
        if (leng > 0)
        {
            //printf("读取到数据为:");
            write(STDOUT_FILENO, "读取到数据为:", strlen("读取到数据为:"));
            write(STDOUT_FILENO, data, leng);
        }
    }
    close(fd);
    return 0;
}
/*
CeShi5_2.c
	向CeShi5_1进程发送数据
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int fd, i;
    char data[4096];
    printf("程序开始运行。\n");
    printf("开始打开管道文件的写端。\n");
    fd = open(argv[1], O_WRONLY);
    if (fd == -1)
    {
        perror("打开管道文件错误");
        exit(1);
    }
    printf("打开管道文件的写端完成。\n");

    printf("开始向管道文件写端写数据。\n");
    i = 1;
    while (1)
    {
        sprintf(data, "你好,世界!这是写进程第%d次向管道写端写数据。\n", i);
        write(fd, data, strlen(data));
        printf("第%d次写成功。\n", i);
        i++;
        sleep(1);
    }
    close(fd);
    return 0;
}

Resultados de la prueba

comunicación de archivos entre procesos

Utilice archivos para completar la comunicación entre procesos no relacionados.

Código de prueba 6

/*
CeShi6_1.c
优先执行数据的写入文件
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int fd, flag;
    char *data = "你好,世界!这是CeShi6_1进程写的。\n";
    char data1[1024];
    int leng;
    printf("程序开始运行。\n");
    printf("开始打开文件。\n");
    fd = open("temp.txt", O_RDWR | O_TRUNC | O_CREAT, 0664);
    if (fd == -1)
    {
        perror("打开文件错误");
        exit(1);
    }
    printf("打开文件完成。\n");

    printf("开始文件写数据。\n");
    write(fd, data, strlen(data));
    printf("写的数据是:%s", data);
    printf("文件写数据完成。\n");

    printf("开始睡大觉。\n");
    sleep(5);
    printf("睡醒了,康康文件的数据。\n");
    lseek(fd, 0, SEEK_SET); //设置偏移量从头开始
    leng = read(fd, data1, sizeof(data1));
    flag=write(STDOUT_FILENO,data1,leng);
    if(flag==-1){
        perror("输出错误");
        exit(1);
    }
    printf("我真是服了,把我数据给改了,CeShi6_2你个老6。\n");
    close(fd);
    return 0;
}
/*
CeShi6_2.c
读取文件数据和修改文件数据
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int fd, flag;
    char *data = "你好,世界!这是CeShi6_2进程写的。\n";
    char data1[1024];
    int leng;
    printf("程序开始运行。\n");

    printf("开始睡大觉。\n");
    sleep(2);
    printf("睡醒了,我是老6,把你CeShi6_1进程写的数据给改了。\n");

    printf("开始打开文件。\n");
    fd = open("temp.txt", O_RDWR);
    if (fd == -1)
    {
        perror("打开文件错误");
        exit(1);
    }
    printf("打开文件完成。\n");

    printf("让我康康你写了啥。\n");
    leng = read(fd, data1, sizeof(data1));
    write(STDOUT_FILENO, data1, leng);
    printf("哦豁,写了这玩意。\n");

    printf("开始文件写数据。\n");
    lseek(fd, 0, SEEK_SET); //设置偏移量从头开始
    write(fd, data, strlen(data));
    printf("写的数据是:%s", data);
    printf("文件写数据完成。\n");

    close(fd);
    return 0;
}

Resultados de la prueba

Supongo que te gusta

Origin blog.csdn.net/CETET/article/details/132267338
Recomendado
Clasificación