进程间通信

管道通信

了解了,如果你在Linux环境下开发,使用管道进行进程间通信(IPC)是一个良好的选择。以下是适用于Linux的代码示例:

程序A(发送端)

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

#define BUFFER_SIZE 65536 // 最大数据大小

// 简单的校验和算法
unsigned int checksum(const char *data, size_t len) {
    unsigned int sum = 0;
    for (size_t i = 0; i < len; i++) {
        sum += (unsigned char)data[i];
    }
    return sum;
}

int main() {
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程:接收端程序B
        close(pipefd[1]); // 关闭写端

        char buffer[BUFFER_SIZE];
        ssize_t n;
        while ((n = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
            unsigned int received_checksum = *(unsigned int *)buffer;
            unsigned int data_size = *(unsigned int *)(buffer + sizeof(unsigned int));
            unsigned int calc_checksum = checksum(buffer + sizeof(unsigned int) * 2, data_size);

            printf("B: Received %zu bytes of data\n", data_size);
            if (received_checksum == calc_checksum) {
                printf("B: Checksum correct\n");
                write(pipefd[1], "OK", 2);
            } else {
                printf("B: Checksum incorrect\n");
                write(pipefd[1], "ERROR", 5);
            }
        }
        close(pipefd[0]);
        exit(EXIT_SUCCESS);
    } else { // 父进程:发送端程序A
        close(pipefd[0]); // 关闭读端

        srand(time(NULL));
        for (int i = 0; i < 10; i++) {
            size_t data_size = rand() % (BUFFER_SIZE - sizeof(unsigned int) * 2) + 1;
            char data[BUFFER_SIZE];
            for (size_t j = 0; j < data_size; j++) {
                data[j] = rand() % 256;
            }
            unsigned int data_checksum = checksum(data, data_size);

            write(pipefd[1], &data_checksum, sizeof(data_checksum));
            write(pipefd[1], &data_size, sizeof(data_size));
            write(pipefd[1], data, data_size);

            char response[5];
            read(pipefd[1], response, sizeof(response));
            if (strncmp(response, "OK", 2) == 0) {
                printf("A: B received %zu bytes of data, checksum correct\n", data_size);
            } else {
                printf("A: B received %zu bytes of data, checksum incorrect\n", data_size);
            }
            sleep(1);
        }
        close(pipefd[1]);
        wait(NULL); // 等待子进程结束
        exit(EXIT_SUCCESS);
    }
}

程序B(接收端)

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

#define BUFFER_SIZE 65536 // 最大数据大小

// 简单的校验和算法
unsigned int checksum(const char *data, size_t len) {
    unsigned int sum = 0;
    for (size_t i = 0; i < len; i++) {
        sum += (unsigned char)data[i];
    }
    return sum;
}

int main() {
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程:接收端
        close(pipefd[1]); // 关闭写端

        char buffer[BUFFER_SIZE];
        ssize_t n;
        while ((n = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
            unsigned int received_checksum = *(unsigned int *)buffer;
            unsigned int data_size = *(unsigned int *)(buffer + sizeof(unsigned int));
            unsigned int calc_checksum = checksum(buffer + sizeof(unsigned int) * 2, data_size);

            printf("Received %zu bytes of data\n", data_size);
            if (received_checksum == calc_checksum) {
                printf("Checksum correct\n");
                write(pipefd[1], "OK", 2);
            } else {
                printf("Checksum incorrect\n");
                write(pipefd[1], "ERROR", 5);
            }
        }
        close(pipefd[0]);
        exit(EXIT_SUCCESS);
    } else { // 父进程:发送端
        close(pipefd[0]); // 关闭读端

        srand(time(NULL));
        for (int i = 0; i < 10; i++) {
            size_t data_size = rand() % (BUFFER_SIZE - sizeof(unsigned int) * 2) + 1;
            char data[BUFFER_SIZE];
            for (size_t j = 0; j < data_size; j++) {
                data[j] = rand() % 256;
            }
            unsigned int data_checksum = checksum(data, data_size);

            write(pipefd[1], &data_checksum, sizeof(data_checksum));
            write(pipefd[1], &data_size, sizeof(data_size));
            write(pipefd[1], data, data_size);

            char response[5];
            read(pipefd[1], response, sizeof(response));
            if (strncmp(response, "OK", 2) == 0) {
                printf("Data received, checksum correct\n");
            } else {
                printf("Data received, checksum incorrect\n");
            }
            sleep(1);
        }
        close(pipefd[1]);
        wait(NULL); // 等待子进程结束
        exit(EXIT_SUCCESS);
    }
}

运行说明

  1. 编译这两个程序:gcc -o sender sender.cgcc -o receiver receiver.c
  2. 先运行接收端(./receiver),然后运行发送端(./sender)。接收端会处理数据和校验,发送端会发送数据并检查结果。

这个示例在Linux环境下利用管道实现了基本的进程间通信和数据校验功能。

修改(crc校验和定期发送)

要使进程A每隔 n 秒发送一次消息,可以在 while 循环中使用 sleep 函数来实现定时发送。你需要在 while 循环中添加一个延时操作,sleep(n) 可以使进程每隔 n 秒发送一次消息。以下是更新后的代码示例:

更新后的程序A(发送端)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <zlib.h> // for crc32

#define BUFFER_SIZE 65536

int main() {
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程:接收端
        close(pipefd[1]); // 关闭写端
        char buffer[BUFFER_SIZE];
        ssize_t n;

        while (1) {
            n = read(pipefd[0], buffer, sizeof(buffer));
            if (n <= 0) break; // 退出循环条件

            uint32_t received_crc = *(uint32_t *)buffer;
            uint32_t data_size = *(uint32_t *)(buffer + sizeof(uint32_t));
            uint32_t calc_crc = crc32(0L, (const unsigned char *)buffer + sizeof(uint32_t) * 2, data_size);

            printf("B: Received %zu bytes of data\n", data_size);
            if (received_crc == calc_crc) {
                printf("B: CRC correct\n");
                write(pipefd[1], "OK", 2);
            } else {
                printf("B: CRC incorrect\n");
                write(pipefd[1], "ERROR", 5);
            }
        }
        close(pipefd[0]);
        exit(EXIT_SUCCESS);
    } else { // 父进程:发送端
        close(pipefd[0]); // 关闭读端
        srand(time(NULL));
        char data[BUFFER_SIZE];
        int delay = 5; // 发送间隔,单位:秒

        while (1) {
            size_t data_size = rand() % (BUFFER_SIZE - sizeof(uint32_t) * 2) + 1;
            for (size_t j = 0; j < data_size; j++) {
                data[j] = rand() % 256;
            }
            uint32_t data_crc = crc32(0L, (const unsigned char *)data, data_size);

            write(pipefd[1], &data_crc, sizeof(data_crc));
            write(pipefd[1], &data_size, sizeof(data_size));
            write(pipefd[1], data, data_size);

            char response[5];
            read(pipefd[1], response, sizeof(response));
            if (strncmp(response, "OK", 2) == 0) {
                printf("A: B received %zu bytes of data, CRC correct\n", data_size);
            } else {
                printf("A: B received %zu bytes of data, CRC incorrect\n", data_size);
            }
            sleep(delay); // 模拟延时,n秒
        }
        close(pipefd[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);
    }
}

在这个示例中,delay 变量定义了发送间隔时间(单位为秒)。你可以根据需要调整 delay 的值。

B端代码

当然,以下是更新后的程序B的代码,用于接收和验证来自程序A的数据。这个接收端程序将从管道读取数据,并计算其CRC值与发送的CRC值进行比较。

更新后的程序B(接收端)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <zlib.h> // for crc32

#define BUFFER_SIZE 65536

int main() {
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程:接收端
        close(pipefd[1]); // 关闭写端
        char buffer[BUFFER_SIZE];
        ssize_t n;

        while (1) {
            n = read(pipefd[0], buffer, sizeof(buffer));
            if (n <= 0) break; // 退出循环条件

            // 读取CRC值和数据大小
            uint32_t received_crc = *(uint32_t *)buffer;
            uint32_t data_size = *(uint32_t *)(buffer + sizeof(uint32_t));
            char *data = buffer + sizeof(uint32_t) * 2;

            // 计算数据的CRC值
            uint32_t calc_crc = crc32(0L, (const unsigned char *)data, data_size);

            // 打印接收到的数据大小
            printf("B: Received %zu bytes of data\n", data_size);

            // 检查CRC值是否匹配
            if (received_crc == calc_crc) {
                printf("B: CRC correct\n");
                write(pipefd[1], "OK", 2);
            } else {
                printf("B: CRC incorrect\n");
                write(pipefd[1], "ERROR", 5);
            }
        }
        close(pipefd[0]);
        exit(EXIT_SUCCESS);
    } else { // 父进程:发送端
        close(pipefd[0]); // 关闭读端
        wait(NULL); // 等待子进程结束
        close(pipefd[1]);
        exit(EXIT_SUCCESS);
    }
}

说明

  1. 管道:程序B使用管道来接收来自程序A的数据。它读取数据、计算CRC值并与接收到的CRC值进行比较,然后将结果返回到程序A。

  2. 数据处理

    • 从管道中读取数据并解析出CRC值、数据大小和实际数据。
    • 使用 crc32 函数计算数据的CRC值,并将其与接收到的CRC值进行比较。
    • 根据CRC值是否匹配,返回"OK"或"ERROR"到程序A。
  3. 通信

    • 程序B的接收端需要读取来自管道的数据,并在处理后将结果写回到管道中以通知程序A。

这个代码片段假设程序A和程序B在同一进程中运行,并且它们通过管道进行通信。你可以根据需要调整和测试这些代码。

父子进程管道通信

当然,这里是一个示例程序,展示了父子进程如何使用管道进行循环通信。在这个示例中,父进程将字符串发送到子进程,子进程接收到数据后将其返回给父进程。

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

#define BUFFER_SIZE 100

int main() {
    int pipefd[2];
    pid_t pid;
    char buffer[BUFFER_SIZE];

    // 创建管道
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    // 创建子进程
    if ((pid = fork()) == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {  // 子进程
        close(pipefd[1]);  // 关闭写端

        // 从管道读取数据
        ssize_t bytesRead = read(pipefd[0], buffer, BUFFER_SIZE);
        if (bytesRead > 0) {
            buffer[bytesRead] = '\0';  // 添加字符串结束符
            printf("Child received: %s\n", buffer);
            // 将数据返回到父进程
            write(pipefd[1], buffer, bytesRead);
        }
        close(pipefd[0]);  // 关闭读端
        exit(EXIT_SUCCESS);

    } else {  // 父进程
        close(pipefd[0]);  // 关闭读端

        // 写数据到管道
        const char *message = "Hello from parent";
        write(pipefd[1], message, strlen(message));
        close(pipefd[1]);  // 关闭写端

        // 等待子进程
        wait(NULL);

        // 读取子进程返回的数据
        pipefd[0];  // 重新打开读端
        ssize_t bytesRead = read(pipefd[0], buffer, BUFFER_SIZE);
        if (bytesRead > 0) {
            buffer[bytesRead] = '\0';  // 添加字符串结束符
            printf("Parent received: %s\n", buffer);
        }
        close(pipefd[0]);  // 关闭读端
    }

    return 0;
}

说明:

  1. pipe(pipefd):创建一个管道,pipefd[0] 是读端,pipefd[1] 是写端。
  2. fork():创建一个子进程。
  3. 在子进程中:
    • 关闭写端。
    • 从管道读取数据并打印。
    • 关闭读端,并写回数据。
  4. 在父进程中:
    • 关闭读端。
    • 向管道写入数据。
    • 关闭写端,并等待子进程结束。
    • 重新打开读端读取子进程返回的数据。

这个程序展示了基本的父子进程间的管道通信和循环操作。

父子进程双pipe通信

如果你希望父进程和子进程之间能够一直进行通信,可以使用一个循环来持续交换消息。下面是一个示例程序,其中父进程和子进程通过管道进行循环通信,直到满足某个条件(例如,发送了特定的退出消息)为止:

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

#define BUFFER_SIZE 100
#define EXIT_MESSAGE "exit"

void parent_process(int write_fd, int read_fd);
void child_process(int write_fd, int read_fd);

int main() {
    int pipefd1[2]; // 用于父子进程的管道
    int pipefd2[2]; // 用于子父进程的管道
    pid_t pid;

    // 创建两个管道
    if (pipe(pipefd1) == -1 || pipe(pipefd2) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    // 创建子进程
    if ((pid = fork()) == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {  // 子进程
        close(pipefd1[1]); // 关闭写端
        close(pipefd2[0]); // 关闭读端

        child_process(pipefd2[1], pipefd1[0]);

        close(pipefd1[0]); // 关闭读端
        close(pipefd2[1]); // 关闭写端
        exit(EXIT_SUCCESS);

    } else {  // 父进程
        close(pipefd1[0]); // 关闭读端
        close(pipefd2[1]); // 关闭写端

        parent_process(pipefd1[1], pipefd2[0]);

        close(pipefd1[1]); // 关闭写端
        close(pipefd2[0]); // 关闭读端

        // 等待子进程结束
        wait(NULL);
    }

    return 0;
}

void parent_process(int write_fd, int read_fd) {
    char buffer[BUFFER_SIZE];
    while (1) {
        // 从标准输入读取数据
        printf("Parent: ");
        fflush(stdout);
        fgets(buffer, BUFFER_SIZE, stdin);

        // 移除换行符
        buffer[strcspn(buffer, "\n")] = '\0';

        // 发送数据到子进程
        write(write_fd, buffer, strlen(buffer) + 1);

        if (strcmp(buffer, EXIT_MESSAGE) == 0) {
            break;
        }

        // 从子进程读取数据
        read(read_fd, buffer, BUFFER_SIZE);
        printf("Parent received: %s\n", buffer);
    }
}

void child_process(int write_fd, int read_fd) {
    char buffer[BUFFER_SIZE];
    while (1) {
        // 从父进程读取数据
        read(read_fd, buffer, BUFFER_SIZE);
        printf("Child received: %s\n", buffer);

        if (strcmp(buffer, EXIT_MESSAGE) == 0) {
            break;
        }

        // 发送数据到父进程
        write(write_fd, buffer, strlen(buffer) + 1);
    }
}

说明:

  1. 创建两个管道pipefd1 用于父进程到子进程的通信,pipefd2 用于子进程到父进程的通信。
  2. 子进程和父进程
    • 子进程在 child_process 函数中运行,通过 pipefd1 读取父进程的数据,通过 pipefd2 发送数据回父进程。
    • 父进程在 parent_process 函数中运行,通过 pipefd2 读取子进程的数据,通过 pipefd1 发送数据给子进程。
  3. 循环通信:父进程和子进程都在循环中发送和接收消息,直到接收到退出消息 ("exit") 为止。

在终端中运行该程序时,父进程等待用户输入数据并发送给子进程,子进程处理接收到的数据并将其返回给父进程,直到输入 "exit" 为止,进程才会退出。

非循环crc

如果父进程发送的数据长度不固定,可以通过以下步骤处理:

  1. 先发送数据长度:在发送实际数据之前,先发送数据的长度。
  2. 接收数据长度:子进程接收数据长度,然后接收相应长度的数据。

这里是调整后的示例代码:

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

#define BUFFER_SIZE 1024
#define POLYNOMIAL 0xEDB88320L

// CRC-32计算函数
uint32_t crc32(uint32_t crc, const unsigned char *buf, size_t len) {
    crc = ~crc;
    while (len--) {
        crc ^= *buf++;
        for (int i = 0; i < 8; i++) {
            if (crc & 1)
                crc = (crc >> 1) ^ POLYNOMIAL;
            else
                crc >>= 1;
        }
    }
    return ~crc;
}

void parent_process(int write_fd, int read_fd) {
    char buffer[BUFFER_SIZE];
    uint32_t crc;
    size_t data_len;

    // 准备数据
    snprintf(buffer, BUFFER_SIZE, "Hello from parent! This is a test.");
    data_len = strlen(buffer);

    // 计算CRC
    crc = crc32(0, (unsigned char*)buffer, data_len);

    // 发送数据长度
    write(write_fd, &data_len, sizeof(data_len));
    // 发送数据
    write(write_fd, buffer, data_len);
    // 发送CRC
    write(write_fd, &crc, sizeof(crc));

    // 从子进程读取验证结果
    int status;
    read(read_fd, &status, sizeof(status));
    if (status) {
        printf("CRC check passed\n");
    } else {
        printf("CRC check failed\n");
    }
}

void child_process(int write_fd, int read_fd) {
    char buffer[BUFFER_SIZE];
    uint32_t received_crc, computed_crc;
    size_t data_len;

    // 从父进程读取数据长度
    read(read_fd, &data_len, sizeof(data_len));
    // 从父进程读取数据
    read(read_fd, buffer, data_len);
    buffer[data_len] = '\0'; // 确保字符串结束
    // 从父进程读取CRC
    read(read_fd, &received_crc, sizeof(received_crc));

    // 计算接收到数据的CRC
    computed_crc = crc32(0, (unsigned char*)buffer, data_len);

    // 校验CRC
    int status = (computed_crc == received_crc) ? 1 : 0;
    write(write_fd, &status, sizeof(status)); // 发送校验结果
}

int main() {
    int pipefd1[2];  // 用于父子进程的管道
    int pipefd2[2];  // 用于子父进程的管道
    pid_t pid;

    // 创建两个管道
    if (pipe(pipefd1) == -1 || pipe(pipefd2) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    // 创建子进程
    if ((pid = fork()) == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {  // 子进程
        close(pipefd1[1]); // 关闭写端
        close(pipefd2[0]); // 关闭读端

        child_process(pipefd2[1], pipefd1[0]);

        close(pipefd1[0]); // 关闭读端
        close(pipefd2[1]); // 关闭写端
        exit(EXIT_SUCCESS);

    } else {  // 父进程
        close(pipefd1[0]); // 关闭读端
        close(pipefd2[1]); // 关闭写端

        parent_process(pipefd1[1], pipefd2[0]);

        close(pipefd1[1]); // 关闭写端
        close(pipefd2[0]); // 关闭读端

        // 等待子进程结束
        wait(NULL);
    }

    return 0;
}

修改点

  1. 发送数据长度:父进程先发送数据长度。
  2. 接收数据长度:子进程先接收数据长度,然后再接收数据和CRC码。

这样,无论数据长度多长,子进程都能正确处理。

父子进程随机发送数据

下面是一个使用 pipe 实现父子进程通信的示例程序,包含数据的传输和 CRC 校验功能。

1. CRC 校验函数

#include <stdint.h>

uint32_t crc32(const void *data, size_t length) {
    static const uint32_t table[256] = {
        // CRC-32表的内容
        // 这里应该填入实际的CRC-32表数据
    };
    
    uint32_t crc = 0xFFFFFFFF;
    const uint8_t *byte = (const uint8_t *)data;

    for (size_t i = 0; i < length; i++) {
        uint8_t table_index = (crc ^ byte[i]) & 0xFF;
        crc = (crc >> 8) ^ table[table_index];
    }
    
    return crc ^ 0xFFFFFFFF;
}

2. 父子进程通信代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <time.h>

#define BUFFER_SIZE 1024  // 缓冲区大小

// CRC 校验函数声明
uint32_t crc32(const void *data, size_t length);

int main() {
    int pipefd[2];
    pid_t pid;
    char buffer[BUFFER_SIZE];
    uint32_t crc;
    ssize_t bytes_written, bytes_read;

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    if ((pid = fork()) == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {  // 子进程
        close(pipefd[1]);  // 关闭写端

        // 从管道读取数据
        bytes_read = read(pipefd[0], buffer, sizeof(buffer));
        if (bytes_read == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }

        // 读取 CRC
        uint32_t received_crc;
        memcpy(&received_crc, buffer + bytes_read - sizeof(received_crc), sizeof(received_crc));

        // 计算 CRC
        uint32_t computed_crc = crc32(buffer, bytes_read - sizeof(received_crc));

        // 验证 CRC
        if (computed_crc == received_crc) {
            printf("子进程: 数据接收并验证成功\n");
        } else {
            printf("子进程: 数据验证失败\n");
        }

        close(pipefd[0]);  // 关闭读端
    } else {  // 父进程
        close(pipefd[0]);  // 关闭读端

        // 生成随机数据
        size_t data_size = (rand() % (BUFFER_SIZE - 1)) + 1;
        for (size_t i = 0; i < data_size; i++) {
            buffer[i] = rand() % 256;
        }

        // 计算 CRC
        crc = crc32(buffer, data_size);

        // 发送数据和 CRC
        memcpy(buffer + data_size, &crc, sizeof(crc));
        bytes_written = write(pipefd[1], buffer, data_size + sizeof(crc));
        if (bytes_written == -1) {
            perror("write");
            exit(EXIT_FAILURE);
        }

        close(pipefd[1]);  // 关闭写端
    }

    return 0;
}

3. 编译和运行

编译并运行程序:

gcc -o parent_child_communication parent_child_communication.c
./parent_child_communication

4. 解释

  1. 父进程:生成随机数据,计算其 CRC 值,并将数据及 CRC 值通过管道发送给子进程。
  2. 子进程:从管道读取数据和 CRC 值,计算数据的 CRC 值,并与接收到的 CRC 值进行比较,验证数据完整性。

确保 CRC 表的内容正确并适配你的 CRC 校验需求。

crc库实现

使用 zlib 库的 crc32 函数可以简化 CRC 校验的实现。以下是基于 zlib 的父子进程通信示例程序:

1. 父子进程通信代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <zlib.h>  // 包含 zlib 库

#define BUFFER_SIZE 1024  // 缓冲区大小

int main() {
    int pipefd[2];
    pid_t pid;
    char buffer[BUFFER_SIZE];
    uint32_t crc;
    ssize_t bytes_written, bytes_read;

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    if ((pid = fork()) == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {  // 子进程
        close(pipefd[1]);  // 关闭写端

        // 从管道读取数据
        bytes_read = read(pipefd[0], buffer, sizeof(buffer));
        if (bytes_read == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }

        // 读取 CRC
        uint32_t received_crc;
        memcpy(&received_crc, buffer + bytes_read - sizeof(received_crc), sizeof(received_crc));

        // 计算 CRC
        uint32_t computed_crc = crc32(0L, Z_NULL, 0);  // 初始化 CRC
        computed_crc = crc32(computed_crc, (const Bytef *)buffer, bytes_read - sizeof(received_crc));

        // 验证 CRC
        if (computed_crc == received_crc) {
            printf("子进程: 数据接收并验证成功\n");
        } else {
            printf("子进程: 数据验证失败\n");
        }

        close(pipefd[0]);  // 关闭读端
    } else {  // 父进程
        close(pipefd[0]);  // 关闭读端

        // 生成随机数据
        size_t data_size = (rand() % (BUFFER_SIZE - 1)) + 1;
        for (size_t i = 0; i < data_size; i++) {
            buffer[i] = rand() % 256;
        }

        // 计算 CRC
        crc = crc32(0L, Z_NULL, 0);  // 初始化 CRC
        crc = crc32(crc, (const Bytef *)buffer, data_size);

        // 发送数据和 CRC
        memcpy(buffer + data_size, &crc, sizeof(crc));
        bytes_written = write(pipefd[1], buffer, data_size + sizeof(crc));
        if (bytes_written == -1) {
            perror("write");
            exit(EXIT_FAILURE);
        }

        close(pipefd[1]);  // 关闭写端
    }

    return 0;
}

2. 编译和运行

确保已安装 zlib 库。编译并运行程序:

gcc -o parent_child_communication parent_child_communication.c -lz
./parent_child_communication

3. 解释

  1. 父进程:生成随机数据,计算其 CRC 值,并将数据和 CRC 值通过管道发送给子进程。
  2. 子进程:从管道读取数据和 CRC 值,计算数据的 CRC 值,并与接收到的 CRC 值进行比较,以验证数据的完整性。

zlib 提供了高效的 CRC 计算,简化了校验逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值