#define _GNU_SOURCE //启用特性,使MSG_EXCEPT宏生效
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include <sys/msg.h>
#include <signal.h>
int msgflg = IPC_NOWAIT; //切换状态时不会阻塞在msgrcv,而是立刻切换
struct st_msg{
long mtype;
char mtext[128];
};
void sig_handler(int signum){
static bool flag = true;
switch(signum){
case SIGINT:
if(flag){
msgflg |= MSG_EXCEPT;
flag = false;
}
else{
msgflg &= ~MSG_EXCEPT;
flag = true;
}
break;
case SIGQUIT: //Ctrl+\用于关闭程序
puts("quit");
exit(EXIT_SUCCESS); //退出整个进程
break;
default:
break;
}
}
void getLine(char* buf){
char ret, i = 0;
while((ret = fgetc(stdin)) != EOF && ret != '\n')
buf[i++] = ret;
}
void* task(void* args){
int *arg = args;
struct st_msg r_msg = { .mtype = arg[1] };
while(1){
memset(r_msg.mtext, 0, sizeof(r_msg.mtext));
int retval = msgrcv(arg[0], &r_msg, sizeof(r_msg.mtext), arg[1], msgflg);
if(retval != -1 && retval != 0) //有消息才打印到终端
puts(r_msg.mtext);
}
}
int main(int argc, const char *argv[])
{
if(argc != 3){
puts("Invalid number of arguments");
return 1;
}
puts("Ctrl+\\ to quit");
int r_msgtype = atoi(argv[1]); //读的消息类型为argv[1]
printf("msgtype %d for read\n", r_msgtype);
int w_msgtype = atoi(argv[2]); //写的消息类型为argv[2]
printf("msgtype %d for write\n", w_msgtype);
if(access("./ipckey", F_OK))
system("touch ipckey");
key_t key = ftok("./ipckey", 1);
if(-1 == key){
perror("ftok");
return 1;
}
int msgid = msgget(key, IPC_CREAT|0666);
if(-1 == msgid){
perror("msgget");
return 1;
}
pthread_t pid;
int arg[2] = {msgid, r_msgtype}; //用于给线程传参
pthread_create(&pid, NULL, task, arg);
pthread_detach(pid);
signal(SIGINT, sig_handler); //注册信号及处理函数
signal(SIGQUIT, sig_handler);
struct st_msg msg = { .mtype = w_msgtype };
while(1){
memset(msg.mtext, 0, sizeof(msg.mtext));
getLine(msg.mtext);
msgsnd(msgid, &msg, strlen(msg.mtext), 0);
}
return 0;
}