请使用消息队列实现2个终端之间互相聊天
终端一
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>#define MSG_SIZE 64
#define MSG_TYPE_1 1
#define MSG_TYPE_2 2typedef struct {long change; // 消息类型(频道)char dup[MSG_SIZE]; // 消息内容
} msg_data;key_t key; // 消息队列的键值
int msg_id; // 消息队列的ID// 信号处理函数
void handler(int signum) {if (signum == SIGINT) {printf("\n程序退出,销毁消息队列...\n");msgctl(msg_id, IPC_RMID, NULL); // 销毁消息队列exit(0);}
}// 消息写入函数
void msg_w() {msg_data arr;while (1) {arr.change = MSG_TYPE_1; // 设置消息类型printf("请输入:");scanf("%s", arr.dup); // 读取用户输入if (msgsnd(msg_id, &arr, strlen(arr.dup) + 1, 0) == -1) {perror("msgsnd");break;}}
}// 消息读取函数
void msg_r() {msg_data arr;while (1) {if (msgrcv(msg_id, &arr, sizeof(arr.dup), MSG_TYPE_2, 0) == -1) {perror("msgrcv");break;}printf("\b\b\b\b\b\b\b\b收到的消息为:%s\n", arr.dup);memset(arr.dup, 0, sizeof(arr.dup)); // 清空消息缓冲区}
}// 线程函数
void* pthread_main(void* arg) {msg_w();return NULL;
}// 清理函数
void cleanup() {printf("清理消息队列...\n");msgctl(msg_id, IPC_RMID, NULL);
}int main(int argc, const char *argv[]) {pthread_t pthread_id;// 注册信号处理函数signal(SIGINT, handler);// 注册清理函数atexit(cleanup);// 生成消息队列的键值key = ftok("1.txt", 1);if (key == -1) {perror("ftok");exit(1);}// 创建消息队列msg_id = msgget(key, IPC_CREAT | 0664);if (msg_id == -1) {perror("msgget");exit(1);}// 创建线程if (pthread_create(&pthread_id, NULL, pthread_main, NULL) != 0) {perror("pthread_create");exit(1);}pthread_detach(pthread_id); // 设置线程为分离状态// 主线程负责读取消息msg_r();return 0;
}
终端二
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <signal.h>
#include <pthread.h>#define MSG_TYPE_SEND 1 // 本终端发送的消息类型
#define MSG_TYPE_RECV 2 // 本终端接收的消息类型
#define MSG_BUFFER_SIZE 64
#define KEY_FILE_PATH "msgq_chat.key"
#define PROJECT_ID 12345typedef struct {long mtype; // 消息类型char mtext[MSG_BUFFER_SIZE]; // 消息内容
} msg_data;static int msg_id = -1;// 信号处理函数:清理消息队列
void handle_signal(int signum) {if (signum == SIGINT) {printf("\n正在清理消息队列...\n");if (msg_id != -1) {msgctl(msg_id, IPC_RMID, NULL);}exit(EXIT_SUCCESS);}
}// 消息发送线程函数
void* send_thread(void *arg) {msg_data msg;while (1) {msg.mtype = MSG_TYPE_SEND;printf("[You] > ");if (fgets(msg.mtext, MSG_BUFFER_SIZE, stdin) == NULL) {perror("fgets");break;}// 去除换行符并计算真实长度size_t len = strcspn(msg.mtext, "\n");msg.mtext[len] = '\0';if (msgsnd(msg_id, &msg, len + 1, IPC_NOWAIT) == -1) { // 非阻塞发送perror("消息发送失败");usleep(100000); // 发送失败时等待100ms}}return NULL;
}// 消息接收处理
void receive_messages() {msg_data msg;while (1) {ssize_t ret = msgrcv(msg_id, &msg, MSG_BUFFER_SIZE, MSG_TYPE_RECV, 0);if (ret == -1) {perror("消息接收失败");break;}printf("\r[Other] > %s\n[You] > ", msg.mtext);fflush(stdout); // 确保立即刷新输出}
}int main() {// 生成唯一Keykey_t key = ftok(KEY_FILE_PATH, PROJECT_ID);if (key == -1) {perror("无法生成消息队列Key");exit(EXIT_FAILURE);}// 创建/获取消息队列msg_id = msgget(key, IPC_CREAT | 0666);if (msg_id == -1) {perror("无法创建消息队列");exit(EXIT_FAILURE);}// 注册信号处理signal(SIGINT, handle_signal);// 创建发送线程pthread_t tid;if (pthread_create(&tid, NULL, send_thread, NULL) != 0) {perror("无法创建发送线程");exit(EXIT_FAILURE);}pthread_detach(tid);// 主线程处理接收printf("--- 聊天室已启动 (Ctrl+C退出) ---\n");receive_messages();return EXIT_SUCCESS;
}