8.29练习

进程间通信示例

使用消息队列在两个独立的 C 程序之间进行进程间通信。每个程序都包含父进程和子进程,父进程用于写消息到消息队列,子进程用于从消息队列读取消息。

程序1 (s1.c)

#include <myhead.h> 

// 定义消息缓冲区结构体
struct msgbuf {
    long mtype; // 消息类型
    char mtext[1000]; // 消息正文
};

#define LENG (sizeof(struct msgbuf) - sizeof(long)) // 计算消息正文的长度

int main() {
    key_t key1 = ftok("./", 'A'); // 创建key值1
    key_t key2 = ftok("./", 'B'); // 创建key值2
    if (key1 == -1 || key2 == -1) {
        perror("ftok"); 
        return -1;
    }

    int msgID1 = msgget(key1, IPC_CREAT | 0664); // 创建或获取消息队列1
    int msgID2 = msgget(key2, IPC_CREAT | 0664); // 创建或获取消息队列2
    if (msgID1 == -1 || msgID2 == -1) {
        perror("msgget"); 
        return -1;
    }

    pid_t pid = fork(); // 创建子进程
    if (pid > 0) {
        // 父进程发送消息到队列1
        struct msgbuf send;
        while (1) {
            printf("s1父进程:请输入消息类型:\n");
            scanf("%ld", &send.mtype); // 读取消息类型
            getchar(); // 清除输入缓冲区中的换行符
            printf("s1父进程:请输入消息的内容:\n");
            fgets(send.mtext, sizeof(send.mtext), stdin); // 读取消息内容
            send.mtext[strlen(send.mtext) - 1] = '\0'; // 去掉换行符
            msgsnd(msgID1, &send, LENG, 0); // 发送消息到队列1
            printf("s1父进程:发送消息:类型=%ld,内容=%s\n", send.mtype, send.mtext);
            if (strcmp(send.mtext, "quit") == 0) { // 如果消息内容是"quit",则退出循环
                break;
            }
        }

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

        // 删除消息队列1
        if (msgctl(msgID1, IPC_RMID, NULL) == -1) {
            perror("msgctl"); 
            return -1;
        }
        printf("s1父进程:消息队列1已删除\n");
    } else if (pid == 0) {
        // 子进程读取消息从队列2
        struct msgbuf rcv;
        while (1) {
            msgrcv(msgID2, &rcv, LENG, 0, 0); // 从队列2读取消息,第一个0:读取第一个信息不论类型,第二个0:阻塞接收
            printf("s1子进程:收到消息:类型=%ld,内容=%s\n", rcv.mtype, rcv.mtext);
            if (strcmp(rcv.mtext, "quit") == 0) { // 如果消息内容是"quit",则退出循环
                break;
            }
        }
        printf("s1子进程:退出\n");
        exit(0); // 子进程退出
    } else {
        perror("fork"); 
        return -1;
    }
    return 0;
}

程序2 (s2.c)

#include <myhead.h> // 包含自定义头文件
// 定义消息缓冲区结构体
struct msgbuf {
    long mtype; // 消息类型
    char mtext[1000]; // 消息正文
};

#define LENG (sizeof(struct msgbuf) - sizeof(long)) // 计算消息正文的长度

int main() {
    key_t key1 = ftok("./", 'A'); // 创建key值1
    key_t key2 = ftok("./", 'B'); // 创建key值2
    if (key1 == -1 || key2 == -1) {
        perror("ftok"); 
        return -1;
    }

    int msgID1 = msgget(key1, IPC_CREAT | 0664); // 创建或获取消息队列1
    int msgID2 = msgget(key2, IPC_CREAT | 0664); // 创建或获取消息队列2
    if (msgID1 == -1 || msgID2 == -1) {
        perror("msgget"); 
        return -1;
    }

    pid_t pid = fork(); // 创建子进程
    if (pid > 0) {
        // 父进程发送消息到队列2
        struct msgbuf send;
        while (1) {
            printf("s2父进程:请输入消息类型:\n");
            scanf("%ld", &send.mtype); // 读取消息类型
            getchar(); // 清除输入缓冲区中的换行符
            printf("s2父进程:请输入消息的内容:\n");
            fgets(send.mtext, sizeof(send.mtext), stdin); // 读取消息内容
            send.mtext[strlen(send.mtext) - 1] = '\0'; // 去掉换行符
            msgsnd(msgID2, &send, LENG, 0); // 发送消息到队列2
            printf("s2父进程:发送消息:类型=%ld,内容=%s\n", send.mtype, send.mtext);
            if (strcmp(send.mtext, "quit") == 0) { // 如果消息内容是"quit",则退出循环
                break;
            }
        }
        // 等待子进程结束
        wait(NULL);

        // 删除消息队列2
        if (msgctl(msgID2, IPC_RMID, NULL) == -1) {
            perror("msgctl"); 
            return -1;
        }
        printf("s2父进程:消息队列2已删除\n");
    } else if (pid == 0) {
        // 子进程读取消息从队列1
        struct msgbuf rcv;
        while (1) {
            msgrcv(msgID1, &rcv, LENG, 0, 0); // 从队列1读取消息,第一个0:读取第一个信息不论类型,第二个0:阻塞接收
            printf("s2子进程:收到消息:类型=%ld,内容=%s\n", rcv.mtype, rcv.mtext);
            if (strcmp(rcv.mtext, "quit") == 0) { // 如果消息内容是"quit",则退出循环
                break;
            }
        }
        printf("s2子进程:退出\n");
        exit(0); // 子进程退出
    } else {
        perror("fork"); 
        return -1;
    }
    return 0;
}

解释

  1. 定义消息缓冲区结构体

    struct msgbuf {
        long mtype; // 消息类型
        char mtext[1000]; // 消息正文
    };
    
  2. 计算消息正文的长度

    #define LENG (sizeof(struct msgbuf) - sizeof(long))
    
  3. 主函数

    • 使用 ftok 生成两个唯一的键值。
    • 使用 msgget 创建或获取两个消息队列。
    • 使用 fork 创建子进程。
  4. 父进程发送消息

    • 父进程负责发送消息到消息队列。
    • 循环读取用户输入的消息类型和消息正文,并发送到消息队列。
    • 如果消息正文是 “quit”,则退出循环并等待子进程结束。
    • 删除消息队列。
  5. 子进程读取消息

    • 子进程负责从消息队列中读取消息。
    • 循环接收消息队列中的消息,并打印消息类型和消息正文。
    • 如果消息正文是 “quit”,则退出循环。

这两个程序,每个程序都包含父进程和子进程,父进程用于写消息到消息队列,子进程用于从消息队列中读取消息,实现了两个程序之间的进程间通信。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值