这个(privatechat)部分总是有问题,功能实现有bug,各位能帮我看下怎么改啊
/* "head.h" */
#include<time.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/mman.h>
#include<fcntl.h>
int qid;
int pid;
//个人信息
struct person{
char name[100]; //客户端姓名
long intype; //接受客户端信息使用的mtype
long outtype; //向客户端发送信息使用的mtype
int has_group; //1:客户端正在聊天室,0:客户端不在聊天室
int has_log; //1:客户端已登陆,0:客户端未登录
pid_t pid; //用于存放监听客户端消息的子进程的pid
};
//消息结构体
struct msg_buf{
long mtype;
char msg_text[512]; //消息内容
char msg_name[100]; //发送消息人的姓名
char msg_time[100]; //发送消息的时间
int message_type; //消息类型,1.进入聊天室消息,2.普通消息,3.退出聊天室,4.退出客户端,5.获取用户信息
};
//登陆信息结构体
struct msg_key{
long mtype;
char name[100]; //客户端名称
long intype; //客户端输入mtype
long outtype; //客户端输出mtype
int number; //客户端序号
};
/* client.c */
/*
* 客户端向服务器端请求 mtype = 1
* 服务器端向客户端返回指定mtype时,mtype = 0
* 客户端退出时 mtype = 3
* */
#include "head.h"
char myname[100];
int oper;
pid_t pid;
struct msg_buf msgb;
struct msg_key msgk;
long intype;
long outtype;
void chatgroup();
void privatechat();
void privatelisten();
//捕获信号
void ctrl_c{
if(pid == 0)
exit(0);
kill(pid, SIGINT);
exit(0);
}
int main()
{
//捕获SIGINT信号
signal(SIGINT, ctrl_c);
system("clear");
//获取qid
qid = msgget(ftok("/", 'a'), IPC_CREAT | 0666);
//初始化数据
printf("请输入你的名字:");
scanf("%s", msgk.name);
msgk.mtype = 1;
//向服务器发送请求
msgsnd(qid, &msgk, sizeof(struct msg_key), 0);
//服务器相应请求
msgrcv(qid, &msgk, sizeof(struct msg_key), 2, 0);
//设置发送与接受的mtype
intype = msgk.intype;
outtype = msgk.outtype;
msgb.mtype = outtype;
strcpy(msgb.msg_name, msgk.name);
// printf("in = %ld, out = %ld\n", intype, outtype);
while (1)
{
system("clear");
printf("\n\n\t\t*********************************************\t\t\n");
printf("\t\t\t\t单主机聊天室\n");
printf("\t\t*********************************************\t\t\n");
printf("\n\n\n\t\t\t1.聊天室.");
printf("\n\t\t\t2.私聊.");
printf("\n\t\t\t0.退出程序.");
printf("\n\n\t\t\t\t选择所要操作:");
scanf("%d", &oper);
if (oper == 1)
{
system("clear");
printf("\n\n\t\t*********************************************\t\t\n");
printf("\t\t\t\t欢迎来到集体聊天室\n");
printf("\t\t*********************************************\t\t\n");
pid = fork();
//创建子进程进入聊天室,父进程挂起
if(pid == 0)
chatgroup();
wait();
}
else if (oper == 2)
{
system("clear");
printf("\n\n\t\t*********************************************\t\t\n");
printf("\t\t\t\t请选择私聊对象\n");
printf("\t\t*********************************************\t\t\n");
pid = fork();
//出啊昂见子进程进入私聊,父进程挂起
if (pid == 0)
privatechat();
wait();
}
else if (oper == 0)
{
//发送退出客户端消息
msgb.message_type = 4;
msgsnd(qid, &msgb, sizeof(struct msg_buf), 0);
exit(0);
}
else
{
printf("\n\n\t\t\t\terror:操作码错误,请重新输入\n");
printf("\n\n\t\t\t\t选择所要操作:");
}
}
}
void chatgroup()
{
time_t t;
pid = fork();
//子进程监听消息
if (pid == 0)
{
//子进程监听消息
while (1)
{
msgrcv(qid, &msgb, sizeof(struct msg_buf), intype, 0);
if (msgb.message_type == 1)
{
//message_type=1,登录消息
printf("%s\n**********用户 %s 加入聊天室**********\n", msgb.msg_time, msgb.msg_name);
continue;
}
else if (msgb.message_type == 3)
{
//message_type=3,退出消息
printf("%s\n**********用户 %s 退出聊天室**********\n", msgb.msg_time, msgb.msg_name);
continue;
}
else
{
//普通消息
printf("%s%s: %s\n\n", msgb.msg_time, msgb.msg_name, msgb.msg_text);
memset(msgb.msg_name, 0, strlen(msgb.msg_name));
memset(msgb.msg_text, 0, strlen(msgb.msg_text));
}
}
}
else //父进程发送消息
{
//设置消息结构体的内容,加入聊天室
time(&t);
//发送进入聊天室消息
msgb.message_type = 1;
ctime_r(&t, msgb.msg_time);
msgsnd(qid, &msgb, sizeof(struct msg_buf), 0);
getchar();
while (1)
{
//读取输入,并获取时间
gets(msgb.msg_text);
time(&t);
ctime_r(&t, msgb.msg_time);
//若输入 “exit”
if (strcmp(msgb.msg_text, "exit") == 0)
{
kill(pid, SIGINT); //子进程向子进程发送信号
memset(msgb.msg_text, 0, strlen(msgb.msg_text));
msgb.message_type = 3;
//发送退出聊天室消息
msgsnd(qid, &msgb, sizeof(struct msg_buf), 0);
exit(0);
}
//发送普通消息
msgb.message_type = 2;
msgsnd(qid, &msgb, sizeof(struct msg_buf), 0);
memset(msgb.msg_text, 0, strlen(msgb.msg_text));
}
}
}
void privatechat()
{
pid = fork();
if (pid != 0)
{
//子进程
sleep(1);
//接受消息
msgrcv(qid, &msgk, sizeof(struct msg_key), intype, 0);
//向父进程发消息,使其退出
kill(pid, SIGINT);
system("clear");
printf("\n\n\t\t*********************************************\t\t\n");
printf("\t\t\t\t欢迎来到私聊室\n");
printf("\t\t*********************************************\t\t\n");
//从消息中获取输出mtype
msgb.mtype = msgk.outtype;
pid = fork();
if (pid == 0)
{
//子进程监听消息
while (1)
{
msgrcv(qid, &msgb, sizeof(struct msg_buf), intype, 0);
if (strcmp(msgb.msg_text, "exit") == 0)
{
//退出
kill(getppid(), SIGINT);
exit(0);
}
ctime_r(&t, msgb.msg_time);
printf("%s%s: %s\n\n", msgb.msg_time, msgb.msg_name, msgb.msg_text);
memset(msgb.msg_name, 0, strlen(msgb.msg_name));
memset(msgb.msg_text, 0, strlen(msgb.msg_text));
}
}
time_t t;
while (1)
{
//父进程发送消息
scanf("%s", msgb.msg_text);
ctime_r(&t, msgb.msg_time);
msgsnd(qid, &msgb, sizeof(struct msg_buf), 0);
if (strcmp(msgb.msg_text, "exit") == 0)
{
kill(pid, SIGINT);
exit(0);
}
}
}
int i;
int t;
struct person per[10];
//发送消息请求用户信息
msgb.message_type = 5;
msgsnd(qid, &msgb, sizeof(struct msg_buf), 0);
printf("\n\n");
for (i = 1;; i++)
{
//展示用户信息
msgrcv(qid, &msgk, sizeof(struct msg_key), intype, 0);
per[i].intype = msgk.intype;
per[i].outtype = msgk.outtype;
strcpy(per[i].name, msgk.name);
printf("\n\t\t\t%d. %s", i, per[i].name);
//退出
if (msgk.number == 0)
break;
}
printf("\n\t\t\t0.退出私聊.");
printf("\n\n\t\t\t\t选择所要操作:");
scanf("%d", &t);
if (t == 0)
return;
else
{
//向目标用户和父进程发送消息
msgk.mtype = per[t].outtype;
msgk.outtype = intype;
msgsnd(qid, &msgk, sizeof(struct msg_key), 0);
msgk.mtype = intype;
msgk.outtype = per[t].outtype;
msgsnd(qid, &msgk, sizeof(struct msg_key), 0);
sleep(1);
}
}
/* server.c */
/*
* server 发送的所有信息mtype=1
* 客户端 发送的所有信息mtype=0
* */
#include "head.h"
void daemonize(); //创建守护进程
void creatmmap(); //创建内存映射,用于子父进程之间通信
void userlogin(); //接受用户登陆的消息
void message(int t); //接受消息
void signal_int(); //捕获SIGINT信号
int len; //用于存放per数组的字节长度
struct person *per; //用于存放用户信息
int number_per; //用于记录用户个数
int main()
{
//生成消息队列
qid = msgget(ftok("/", 'a'), IPC_CREAT | 0666);
//初始化number_per从10开始
number_per = 10;
//捕获SIGINT信号
signal(SIGINT, signal_int);
//成为守护进程
// daemonize();
//创建共享内存
creatmmap();
//第一个子进程,用来创建用户
pid = fork();
if (pid < 0)
{
perror("进程创建失败");
exit(1);
}
if (pid == 0)
{
printf("开始监听\n");
userlogin();
}
//父进程用来监听退出
int i;
while (1)
{
//收到-1
scanf("%d", &i);
if (i == -1)
{
kill(pid, SIGINT);
int j = 0;
for (; j < 105; j++)
{
//向所有子进程发送SIGKILL
if (per[j].has_log == 1)
kill(per[j].pid, SIGINT);
}
break;
}
}
memset(per, 0, sizeof(per));
//断开共享内存链接
munmap((void *)per, len);
return 0;
}
void signal_int()
{
//是子进程退出
if (pid == 0)
{
//断开共享内存
munmap((void *)per, len);
exit(0);
}
//父进程向子进程发送信号后退出
kill(pid, SIGINT);
//断开共享内存
munmap((void *)per, len);
exit(0);
}
void daemonize() //cheng'wei
{
if (pid = fork() < 0)
{
perror("fork");
exit(1);
}
else if (pid != 0)
exit(0);
if (chdir("/") < 0)
{
perror("chdir");
exit(1);
}
close(0);
open("/dev/null", O_RDWR);
dup2(0, 1);
dup2(0, 2);
}
void creatmmap() //创建共享内存
{
//打开文件
int fd = open("mmap.dat", O_CREAT | O_RDWR, 0666);
if (fd == -1)
{
perror("文件打开失败");
exit(1);
}
//获取想要的长度
len = sizeof(struct person) * 105;
//文件长度设置
ftruncate(fd, len);
//共享内存
per = (struct person *)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (per == MAP_FAILED)
perror("mmap file");
int i = 0;
//设置状态位都为0
for (; i < 105; i++)
{
per[i].has_log = 0;
per[i].has_group = 0;
}
//关闭文件描述符
close(fd);
}
void userlogin()
{
struct msg_key msg;
int i;
while (1)
{
//只接受mtype = 0的消息
//若有登陆请求
msgrcv(qid, &msg, sizeof(struct msg_key), 1, 0);
printf("新建用户 %s\n", msg.name);
//设置第number_per用户的intype和outtype
per[number_per].intype = number_per;
per[number_per].outtype = number_per + 200;
per[number_per].has_log = 1;
//返回对应in/outtype,mtype=2
msg.intype = number_per + 200;
msg.outtype = number_per;
strcpy(per[number_per].name, msg.name);
printf("%s的intype = %ld, outtype = %ld\n", msg.name, msg.intype, msg.outtype);
msg.mtype = 2;
msgsnd(qid, &msg, sizeof(struct msg_key), 0);
//返回消息,创建一个子进程监听消息
pid = fork();
if (pid == 0)
{
message(number_per);
break;
}
//记录pid
per[number_per].pid = pid;
number_per++;
}
}
void message(int t)
{
struct msg_buf msg;
strcpy(msg.msg_name, per[t].name);
int i;
while (1)
{
while (1)
{
//监听消息
msgrcv(qid, &msg, sizeof(struct msg_buf), per[t].intype, 0);
printf("收到 %s 的消息:%s\n messagetype=%d\n", msg.msg_name, msg.msg_text, msg.message_type);
if (msg.message_type == 1)
{
// msg.message_type == 1, 进入聊天室
for (i = 10; i < 20; i++)
{
if (per[i].has_group == 1)
{
msg.mtype = per[i].outtype;
msgsnd(qid, &msg, sizeof(struct msg_buf), 0);
}
}
per[t].has_group = 1;
}
else if (msg.message_type == 2)
{
// msg.message_type == 2, 普通消息进行广播消息
for (i = 10; i < 20; i++)
{
if (per[i].has_group == 1 && i != t)
{
msg.mtype = per[i].outtype;
msgsnd(qid, &msg, sizeof(struct msg_buf), 0);
printf("%s 为 %s 发送成功\n", msg.msg_name, per[i].name);
}
}
memset(msg.msg_name, 0, strlen(msg.msg_name));
memset(msg.msg_text, 0, strlen(msg.msg_text));
}
else if (msg.message_type == 3)
{
// msg.message_type == 3, 退出聊天室
for (i = 10; i < 20; i++)
{
if (per[i].has_group == 1 && i != t)
{
msg.mtype = per[i].outtype;
msgsnd(qid, &msg, sizeof(struct msg_buf), 0);
}
}
per[t].has_group = 0;
continue;
}
else if (msg.message_type == 4)
{
// msg.message_type == 4, 退出程序
per[t].has_log = 0;
kill(per[t].pid, SIGINT);
exit(0);
}
else if (msg.message_type == 5)
{
//请求私聊,发送所有人的信息
int i;
struct msg_key msgk;
msgk.mtype = per[t].outtype;
int number = 0;
//查找在线人数
for (i = 10; i < 20; i++){
if (per[i].has_log == 1){
number++;
}
}
msgk.number = 1;
printf("%d\n", number);
int s = 0;
number--;
for (i = 10; i < 20; i++)
{
if (per[i].has_log == 1 && i != t)
{
s++;
msgk.intype = per[i].intype;
msgk.outtype = per[i].outtype;
strcpy(msgk.name, per[i].name);
if (s == number)
msgk.number = 0;
msgsnd(qid, &msgk, sizeof(struct msg_key), 0);
printf("%s 信息已发送 %ld %d\n", msgk.name, msgk.mtype, msgk.number);
}
}
}
}
}
}
server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>
#include <errno.h>
#define CLIENT_LOGIN 100 //用户登录
#define CLIENT_CHAT 200 //用户群聊
#define CLIENT_QUIT 300 //用户下线
#define SERVER_CHAT 400 //服务器消息
#define SERVER_QUIT 500 //服务器退出
#define PRINT_ONLINE 600 //显示在线用户
#define PRIVATE_CHAT 700 //私聊消息
#define CLIENT_MSG 1000 //用户消息(用于消息类型)
#define SERVER_MSG 2000
//存储用户信息的链表节点
struct node
{
pid_t pid; //进程号
char name[20]; //用户名
struct node *next;
};
//消息包
struct message
{
long mtype; //主类型
int type; //次类型
pid_t pid; //进程号
char name[20]; //用户名
char peer_name[20]; //私聊对方用户名
char mtext[100]; //消息内容
};
struct node *create_list(void);
void insert_list(struct node *, pid_t , char *);
void delete_list(struct node *, pid_t );
void child_recv(int , struct node *);
void father_send(int , pid_t );
void client_login(int , struct node *, struct message );
void client_chat(int ,struct node *, struct message );
void client_quit(int , struct node *, struct message );
void server_msg(int , struct node *, struct message );
void server_quit(int , struct node *, struct message );
void brocast_msg(int , struct node *, struct message );
void print_online(int , struct node *, struct message );
void private_chat(int , struct node *, struct message );
void father_func(int sig_no)
{
return ;
}
//创建链表,用于存储登录用户信息
struct node *create_list(void)
{
struct node *head;
head = (struct node *)malloc(sizeof(struct node));
head->next = NULL;
return head;
}
//插入链表节点,用于用户登录
void insert_list(struct node *head, pid_t pid, char *name)
{
struct node *new;
new = (struct node *)malloc(sizeof(struct node));
new->pid = pid;
strcpy(new->name, name);
new->next = head->next;
head->next = new;
return ;
}
//删除链表节点,用于用户下线
void delete_list(struct node *head, pid_t pid)
{
struct node *p = head->next;
struct node *q = head;
while (p != NULL)
{
if (p->pid == pid)
break;
p = p->next;
q = q->next;
}
q->next = p->next;
return ;
}
int main(int argc, const char *argv[])
{
key_t key;
pid_t pid;
int msg_id;
struct node *head;
if ((key = ftok(".", 'a')) < 0)
{
perror("failed to get key");
exit(-1);
}
//创建消息队列
if ((msg_id = msgget(key, 0666 | IPC_CREAT | IPC_EXCL)) < 0)
{
if (errno == EEXIST)
{
if ((msg_id = msgget(key, 0666)) < 0)
{
perror("failed to get msg_id");
exit(-1);
}
}
}
head = create_list(); //建立链表
if ((pid = fork()) < 0)
{
perror("failed to fork pid");
exit(-1);
}
if (pid == 0)
child_recv(msg_id, head); //子进程接收消息并进行处理
else
father_send(msg_id, pid); //发送服务器消息
return 0;
}
void child_recv(int msg_id, struct node *head)
{
struct message msg;
while (1)
{
memset(&msg, 0, sizeof(msg));
//接收CLIENT_MSG类型的消息
if (msgrcv(msg_id, &msg, (sizeof(msg)- sizeof(long)), CLIENT_MSG, 0) < 0)
{
perror("failed to recv message");
exit(-1);
}
//根据消息的次类型进行分别处理
switch(msg.type)
{
case CLIENT_LOGIN:
client_login(msg_id, head, msg); //用户登录消息
break;
case CLIENT_CHAT:
client_chat(msg_id, head, msg); //用户群聊消息
break;
case CLIENT_QUIT:
client_quit(msg_id, head, msg); //用户离线消息
break;
case SERVER_CHAT:
server_msg(msg_id, head, msg); //服务器消息
break;
case SERVER_QUIT:
server_quit(msg_id, head, msg); //服务器退出消息
break;
case PRINT_ONLINE:
print_online(msg_id, head, msg); //显示当前在线用户消息
break;
case PRIVATE_CHAT:
private_chat(msg_id, head, msg); //私聊消息
break;
default:
break;
}
}
return ;
}
void father_send(int msg_id, pid_t pid)
{
struct message msg;
char buf[100];
signal(SIGUSR1, father_func); //注册用户自定义信号
while (1)
{
memset(buf, 0, sizeof(buf));
memset(&msg, 0, sizeof(msg));
usleep(500);
printf(">");
fgets(buf, sizeof(buf),stdin);
buf[strlen(buf) - 1] = 0;
//填充消息包的内容
msg.mtype = CLIENT_MSG;
msg.type = SERVER_CHAT;
strcpy(msg.mtext, buf);
strcpy(msg.name, "server");
//服务器退出处理
if (strncmp(buf, "quit", 4) == 0)
{
msg.type = SERVER_QUIT;
//发送消息给各个在线用户,令他们先退出
if (msgsnd(msg_id, &msg, (sizeof(msg) - sizeof(long)), 0) < 0)
{
perror("failed to send quit message");
exit(-1);
}
pause(); //等待消息群发成功
//杀死并回收处理子进程
kill(pid, SIGKILL);
waitpid(pid, NULL, 0);
//删除消息队列
if (msgctl(msg_id, IPC_RMID, NULL) < 0)
{
perror("faield to delete msg queue");
exit(-1);
}
exit(0);
}
if (msgsnd(msg_id, &msg, (sizeof(msg) - sizeof(long)), 0) < 0)
{
perror("failed to send server message");
exit(-1);
}
}
return ;
}
//用户登录时,将用户信息插入链表,并群发用户登录消息
void client_login(int msg_id, struct node *head, struct message msg)
{
printf("########## User Login ##########\n");
printf("User %s is Login in\n", msg.name);
printf("################################\n");
insert_list(head, msg.pid, msg.name);
brocast_msg(msg_id, head, msg);
return ;
}
//群聊时,群发用户群聊消息
void client_chat(int msg_id, struct node *head, struct message msg)
{
printf("***********Client Group Msg **********\n");
printf("user name : %s\n", msg.name);
printf("message : %s\n", msg.mtext);
printf("**************************************\n");
brocast_msg(msg_id, head, msg);
return ;
}
//用户下线时,删除该用户在链表中的信息,并群发该用户下线通知
void client_quit(int msg_id, struct node *head, struct message msg)
{
printf("*********** Client Quit Msg **********\n");
printf("User %s is Quit\n", msg.name);
printf("**************************************\n");
delete_list(head, msg.pid);
brocast_msg(msg_id, head, msg);
return ;
}
//接收到系统消息,群发系统消息
void server_msg(int msg_id, struct node *head, struct message msg)
{
brocast_msg(msg_id, head, msg);
return ;
}
//服务器退出时,群发服务器退出消息
void server_quit(int msg_id, struct node *head, struct message msg)
{
brocast_msg(msg_id, head, msg);
return ;
}
//群发消息的过程:遍历整个链表,以用户的pid为消息类型,向各个用户发送消息
void brocast_msg(int msg_id, struct node *head, struct message msg)
{
struct node *p = head->next;
//遍历链表,发送消息
while (p != NULL)
{
if (p->pid == msg.pid)
{
if(msg.type == CLIENT_LOGIN)
{
p = p->next;
continue;
}
}
msg.mtype = p->pid;
if (msgsnd(msg_id, &msg, (sizeof(msg) - sizeof(long)), 0) < 0)
{
perror("failed to brocast message");
exit(-1);
}
p = p->next;
}
if (msg.type == SERVER_QUIT)
kill(getppid(), SIGUSR1);
return ;
}
//显示当前在线用户:遍历链表提取各个节点的用户名
void print_online(int msg_id, struct node *head, struct message msg)
{
struct node *p = head->next;
char buf[100];
printf("user %s request to print online clinet\n", msg.name);
memset(buf, 0, sizeof(buf));
if (p != NULL)
{
sprintf(buf, "%s ", p->name);
}
p = p->next;
while (p != NULL)
{
strcat(buf, p->name);
strcat(buf, " ");
p = p->next;
}
strcpy(msg.name, "server");
strcpy(msg.mtext, buf);
msg.mtype = msg.pid;
if (msgsnd(msg_id, &msg, (sizeof(msg) - sizeof(long)), 0) < 0)
{
perror("failed to send print_online message");
exit(-1);
}
return ;
}
//私聊消息:遍历链表查找对方用户名的节点,提取出对方用户名的pid号,从而以对方pid号为消息类型,将消息转发给他
void private_chat(int msg_id, struct node *head, struct message msg)
{
struct node *p = head->next;
int type;
printf("******** Private Msg********\n");
printf("from %s\n", msg.name);
printf("to %s\n", msg.peer_name);
printf("msg: %s\n", msg.mtext);
printf("****************************\n");
//遍历链表查找对方用户名的pid号
while (p != NULL)
{
if (strcmp(p->name, msg.peer_name) == 0)
{
type = p->pid;
break;
}
p = p->next;
}
msg.mtype = type; //以对方pid号作为消息类型
if (msgsnd(msg_id, &msg, (sizeof(msg) - sizeof(long)), 0) < 0)
{
perror("failed to send private message");
exit(-1);
}
}
在代码中,你定义了一个函数 ctrl_c
,但是没有加上函数名后面的括号,应该改为 void ctrl_c()
。另外,在 main
函数中,你调用了 ctrl_c
函数,但是也没有加上括号,应该改为 signal(SIGINT, ctrl_c)
。此外,你在 main
函数中调用了 chatgroup
和 privatechat
函数,但是这两个函数的定义没有给出,你需要补充这两个函数的定义。最后,你在 main
函数中定义了一个 pid
变量,但是没有初始化,你需要给 pid
变量赋值。
回答:
要实现主机版Linux聊天室中的privatechat功能,可以使用消息队列来实现。消息队列是一个异步通信机制,它可以用于在进程之间进行通信,特别是在多个不同进程之间传递数据。
首先需要创建一个消息队列,并定义消息结构体,然后在私人聊天中将消息发送到消息队列,接收方进程则可以从该队列中接收到消息。下面是示例代码:
1.创建消息队列
使用msgget()函数在系统中创建一个消息队列。该函数有两个参数,一个是键值,另一个是标志,用于指示是否创建新的消息队列。在本例中,我们使用IPC_PRIVATE,通过一个键值来创建一个新的消息队列。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAXSIZE 1024
struct msgbuf {
long mtype;
char mtext[MAXSIZE];
};
int main()
{
int msqid;
size_t msgsize;
struct msgbuf msg;
msqid = msgget(IPC_PRIVATE, 0666|IPC_CREAT);
return 0;
}
2.发送消息到消息队列
使用msgsnd()函数向消息队列中发送消息。该函数有四个参数,消息队列标识符、消息指针(即指向消息结构体的指针)、消息长度和消息类型。在本例中,我们通过setMessage()函数向消息队列中发送一条文本消息。
void setMessage(struct msgbuf *q, int msgtype, char *msgtext)
{
q->mtype = msgtype;
strcpy(q->mtext, msgtext);
}
int main()
{
int msqid;
size_t msgsize;
struct msgbuf msg;
msqid = msgget(IPC_PRIVATE, 0666|IPC_CREAT);
setMessage(&msg, 1, "Hello World!");
msgsize = strlen(msg.mtext) + 1;
msgsnd(msqid, &msg, msgsize, IPC_NOWAIT);
return 0;
}
3.接收从消息队列中接收到的消息
使用msgrcv()函数从消息队列中接收消息。该函数有五个参数,分别是消息队列标识符、消息指针、消息长度、消息类型和标志。在本例中,我们通过getMessage()函数从消息队列中接收到文本消息。
void getMessage(struct msgbuf *q, int msgtype)
{
msgrcv(msqid, q, MAXSIZE, msgtype, 0);
}
int main()
{
int msqid;
size_t msgsize;
struct msgbuf msg;
msqid = msgget(IPC_PRIVATE, 0666|IPC_CREAT);
setMessage(&msg, 1, "Hello World!");
msgsize = strlen(msg.mtext) + 1;
msgsnd(msqid, &msg, msgsize, IPC_NOWAIT);
getMessage(&msg, 1);
printf("%s", msg.mtext);
return 0;
}
4.在聊天室程序中实现privatechat功能
在聊天室程序中,当用户希望与另一个用户进行私人聊天时,程序需要向消息队列中发送私人聊天请求,接收方则从队列中获取请求进行回应。如果接收方同意开启private chat,则MSGFLG标志将被设置为IPC_NOWAIT,这意味着发送方可以立即开始私人聊天。如果接收方拒绝了请求,发送方则将得到拒绝回应。
示例代码:
struct msgbuf msg;
// 发送私人聊天请求
setMessage(&msg, 2, "Hello, would you like to chat privately?");
msgsnd(msqid, &msg, msgsize, IPC_NOWAIT);
// 接收私人聊天请求
getMessage(&msg, 2);
if (strcmp(msg.mtext, "Yes") == 0) {
// 私人聊天开启
...
// 关闭私人聊天
} else {
// 拒绝私人聊天
}