主机版Linux聊天室怎么实现privatechat(用消息队列)

这个(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 函数中调用了 chatgroupprivatechat 函数,但是这两个函数的定义没有给出,你需要补充这两个函数的定义。最后,你在 main 函数中定义了一个 pid 变量,但是没有初始化,你需要给 pid 变量赋值。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    回答:

    要实现主机版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 {
        // 拒绝私人聊天
    }
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^