請使用消息隊列實現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;
}