#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <ctype.h>
#define MSG_SIZE 1024 // 消息数据最大长度
#define SERVER_TYPE 1 // 客户端发送给服务器的消息类型
#define CLIENT_TYPE 2 // 服务器返回给客户端的消息类型
#define EXIT_STR "exit" // 退出指令
// 消息结构体
typedef struct {
long mtype; // 消息类型
char mtext[MSG_SIZE]; // 消息内容
} msgbuf;
// 将字符串转为大写
void to_upper(char *str) {
while (*str) {
*str = toupper(*str);
str++;
}
}
int main() {
key_t msg_key;
int msgid;
pid_t pid;
msgbuf msg;
ssize_t recv_len;
// 生成消息队列关键字
msg_key = ftok(".", 'm');
if (msg_key == -1) {
perror("ftok failed");
exit(EXIT_FAILURE);
}
// 创建消息队列(权限0666)
msgid = msgget(msg_key, IPC_CREAT | 0666);
if (msgid == -1) {
perror("msgget failed");
exit(EXIT_FAILURE);
}
// 创建子进程(客户端)
pid = fork();
if (pid == -1) {
perror("fork failed");
msgctl(msgid, IPC_RMID, NULL);
exit(EXIT_FAILURE);
}
if (pid == 0) { // 客户端进程
while (1) {
// 从标准输入读取消息
printf("客户端输入(输入exit退出):");
fflush(stdout);
if (fgets(msg.mtext, MSG_SIZE, stdin) == NULL) {
perror("fgets failed");
exit(EXIT_FAILURE);
}
// 去除换行符
msg.mtext[strcspn(msg.mtext, "\n")] = '\0';
// 设置消息类型为服务器接收类型
msg.mtype = SERVER_TYPE;
// 发送消息到消息队列
if (msgsnd(msgid, &msg, strlen(msg.mtext) + 1, 0) == -1) {
perror("msgsnd failed");
exit(EXIT_FAILURE);
}
// 若输入exit,等待服务器返回后退出
if (strcmp(msg.mtext, EXIT_STR) == 0) {
// 接收服务器返回的消息
recv_len = msgrcv(msgid, &msg, MSG_SIZE, CLIENT_TYPE, 0);
if (recv_len == -1) {
perror("msgrcv failed");
exit(EXIT_FAILURE);
}
printf("客户端收到:%s\n", msg.mtext);
break;
}
// 接收服务器返回的大写消息
recv_len = msgrcv(msgid, &msg, MSG_SIZE, CLIENT_TYPE, 0);
if (recv_len == -1) {
perror("msgrcv failed");
exit(EXIT_FAILURE);
}
printf("客户端收到大写消息:%s\n", msg.mtext);
}
exit(EXIT_SUCCESS);
} else { // 服务器进程
while (1) {
// 接收客户端发送的消息(类型为SERVER_TYPE)
recv_len = msgrcv(msgid, &msg, MSG_SIZE, SERVER_TYPE, 0);
if (recv_len == -1) {
perror("msgrcv failed");
msgctl(msgid, IPC_RMID, NULL);
exit(EXIT_FAILURE);
}
printf("服务器收到:%s\n", msg.mtext);
// 若消息是exit,处理后返回并退出
if (strcmp(msg.mtext, EXIT_STR) == 0) {
to_upper(msg.mtext);
msg.mtype = CLIENT_TYPE;
if (msgsnd(msgid, &msg, strlen(msg.mtext) + 1, 0) == -1) {
perror("msgsnd failed");
msgctl(msgid, IPC_RMID, NULL);
exit(EXIT_FAILURE);
}
break;
}
// 将消息转为大写
to_upper(msg.mtext);
// 设置消息类型为客户端接收类型,返回结果
msg.mtype = CLIENT_TYPE;
if (msgsnd(msgid, &msg, strlen(msg.mtext) + 1, 0) == -1) {
perror("msgsnd failed");
msgctl(msgid, IPC_RMID, NULL);
exit(EXIT_FAILURE);
}
}
// 等待客户端退出
waitpid(pid, NULL, 0);
// 清理消息队列
if (msgctl(msgid, IPC_RMID, NULL) == -1) {
perror("msgctl failed");
exit(EXIT_FAILURE);
}
printf("服务器:消息队列已清理,退出\n");
}
return 0;
}