寒假(一)
请使用消息队列实现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 2
typedef 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 12345
typedef 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() {
// 生成唯一Key
key_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;
}