沫颖 的学生作业:
代码
// 封装函数版本
#include
#include
#include
#include
#include
#include
#include
#include
#include
// 定义用于ftok的路径和项目ID
#define PATHNAME "."
#define PROID 24
// 消息类型
#define MSG_TYPE_A 100
#define MSG_TYPE_B 200
// 消息内容最大长度
#define MSG_SIZE 128
// 消息结构体
struct msgbuf
{
long mtype;
char mtext[MSG_SIZE];
};
// 信号处理函数
void sigterm_a_handler(int signum)
{
printf("Received SIGTERM, Process A exiting...\n");
exit(EXIT_SUCCESS);
}
void sigterm_b_handler(int signum)
{
printf("Received SIGTERM, Process B exiting...\n");
exit(EXIT_SUCCESS);
}
// 注册信号处理函数 (sigtype 1: A, 2: B)
void register_signal_handler(const int sigtype)
{
__sighandler_t sig_ret;
sig_ret = sigtype == 1 ? signal(SIGTERM, sigterm_a_handler) : signal(SIGTERM, sigterm_b_handler);
if (sig_ret == SIG_ERR)
{
perror("[ERROR] signal():");
exit(EXIT_FAILURE);
}
}
// 接收消息
struct msgbuf receive_message(int msgid, long msgtype)
{
// 接收的消息结构体
struct msgbuf rcv_msg;
ssize_t rbytes;
// 从消息队列中接收消息
rbytes = msgrcv(msgid, (void *)&rcv_msg, MSG_SIZE, msgtype, 0);
if (rbytes == -1)
{
perror("[ERROR] msgrcv() :");
}
return rcv_msg;
}
// 发送消息
void send_messages(int msgid, const char *input)
{
struct msgbuf send_msg_a, send_msg_b;
send_msg_a.mtype = MSG_TYPE_A;
strcpy(send_msg_a.mtext, input);
send_msg_b.mtype = MSG_TYPE_B;
strcpy(send_msg_b.mtext, input);
int ret_a = msgsnd(msgid, (void *)&send_msg_a, strlen(send_msg_a.mtext) + 1, 0);
int ret_b = msgsnd(msgid, (void *)&send_msg_b, strlen(send_msg_b.mtext) + 1, 0);
if (ret_a == -1 || ret_b == -1)
{
perror("[ERROR] msgsnd():");
exit(EXIT_FAILURE);
}
}
int main(int argc, char const *argv[])
{
key_t key;
int msgid;
// 创建消息队列的key
key = ftok(PATHNAME, PROID);
if (key == -1)
{
perror("[ERROR] ftok() :");
exit(EXIT_FAILURE);
}
// 创建消息队列
msgid = msgget(key, IPC_CREAT | 0666);
pid_t cpid;
// 创建进程
cpid = fork();
if (cpid == -1)
{
perror("[ERROR] fork() A:");
exit(EXIT_FAILURE);
}
else if (cpid == 0)
{
// 注册自定义信号处理函数
register_signal_handler(1);
// 接收的消息结构体
struct msgbuf rcv_msg_a;
// 子进程A,负责接收消息类型为 100 的消息
while (1)
{
// 从消息队列中接收消息
rcv_msg_a = receive_message(msgid, MSG_TYPE_A);
printf("rcv_msg_a.mtype = %ld\n", rcv_msg_a.mtype);
printf("rcv_msg_a.mtext = %s\n", rcv_msg_a.mtext);
}
}
else if (cpid > 0)
{
pid_t cpidB;
// 创建进程
cpidB = fork();
if (cpidB == -1)
{
perror("[ERROR] fork() B:");
exit(EXIT_FAILURE);
}
else if (cpidB == 0)
{
// 注册自定义信号处理函数
register_signal_handler(2);
// 接收的消息结构体
struct msgbuf rcv_msg_b;
// 子进程A,负责接收消息类型为 100 的消息
while (1)
{
// 从消息队列中接收消息
rcv_msg_b = receive_message(msgid, MSG_TYPE_B);
printf("rcv_msg_b.mtype = %ld\n", rcv_msg_b.mtype);
printf("rcv_msg_b.mtext = %s\n", rcv_msg_b.mtext);
}
}
else if (cpidB > 0)
{
sleep(1);
// 循环向消息队列中发送消息
while (1)
{
// 获取用户输入,作为消息,发送至消息队列
char input[MSG_SIZE];
printf("Please input a message: \n");
if (fgets(input, MSG_SIZE, stdin) == NULL)
{
perror("[ERROR] fgets() :");
exit(EXIT_FAILURE);
}
// 处理输入,去除换行符
size_t len = strlen(input);
if (len > 0 && input[len - 1] == '\n')
{
input[len - 1] = '\0';
}
// 当输入quit时退出
if (strcmp(input, "quit") == 0)
{
// 结束子进程
kill(cpid, SIGTERM);
kill(cpidB, SIGTERM);
waitpid(cpid, NULL, 0);
waitpid(cpidB, NULL, 0);
// 删除消息队列
if (msgctl(msgid, IPC_RMID, NULL) == -1)
{
perror("[ERROR] msgctl() :");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
// 发送消息
send_messages(msgid, input);
}
}
}
return 0;
}
效果
【图片】