聊天室(C语言)- 基于文件编程、网络通信、数据库实现

聊天室(C语言)

源码连接
https://download.csdn.net/download/G1842965496/83970608

——基于文件编程、网络通信、数据库实现

一、项目功能介绍

1.登录、注册、密码修改
2.私聊
3.群聊:在群聊中若收到私密消息,会以消息闪烁形式通知
4.文件传输
5.管理员权限:禁言、解除禁言、踢人
6.VIP用户:独特显示用户名、不可被禁言和踢出群聊
7.心跳检测:当一用户推出聊天室或掉线,其他在线用户会收到该用户下线通知
用户上线时,其他在线用户也会接到通知

二、使用须知

所有文件

1.注册用户初始为普通用户,可手动添加为管理员或VIP用户

2.文本说明 :
1).root.txt:存放管理员
2). R_num.txt:存放管理员数量
3). VIP.txt:存放VIP用户
4).V_num.txt:存放VIP用户数量
5).log.txt:群聊记录
6).info.db:存放已注册用户

3.提醒:
管理员和VIP用户均需要先注册为普通用户后,在手动添加到相应文本中

4.注意:!!!
1).由于中文字符所占字节数和英文不同,发送中文靠右边打印会出现打印错位
所需要发送中文,请在聊天函数中,将发送消息靠右打印,改为靠左打印
2).若被禁言,则为永久禁言,直到被管理员解除禁言,或服务器重启
3).若被踢出群聊,退出聊天框后重新进入即可

三、项目演示:

聊天室

四、界面展示

1.登录
聊天室(C语言)- 基于文件编程、网络通信、数据库实现_第1张图片
2.聊天室功能界面
聊天室(C语言)- 基于文件编程、网络通信、数据库实现_第2张图片

3.群聊(管理员界面)
聊天室(C语言)- 基于文件编程、网络通信、数据库实现_第3张图片

五、代码展示

1.服务器

#include  //服务器
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int serverfd; //服务器socket

int clientfd[100]; //客户端的socketfd,100个元素,clientfd[0]~clientfd[99]

int size = 50; //用来控制进入聊天室的人数为50以内

char *IP = "192.168.12.13"; //主机ip地址

short PORT = 6666; //端口号

typedef struct sockaddr meng;

time_t nowtime;

struct client //创建结构体
{
    int flag;          //功能标志位  -1:退出群聊   0:通知所有在线用户   1:私聊   2:群聊   3.发送文件   4.修改密码
    int root;          //权限标志位  -1:首次进入聊天室   0:普通用户   1:管理员  2:VIP用户
    int forbit;        //管理员权限   1:禁言   2:解除禁言   3:踢人
    char name[50];     //账号名
    char password[20]; //密码
    char msg[500];     //聊天信息
    char to_name[50];  //操作对象
    struct client *next;
};

struct Forbit //存放被禁言人员
{
    char name[50];
    struct Forbit *next;
};

struct Root //存放管理员名单
{
    char root[50]; //管理员用户
    struct Root *next;
};

struct VIP //存放vip用户名单
{
    char name[50]; //管理员用户
    struct VIP *next;
};

struct user //用来存放已登录用户
{
    int c_fd;
    char name[50];
    struct user *next;
};

struct Group //存放群内成员
{
    char name[50]; //群内成员用户
    struct Group *next;
};

struct i_fd
{
    int i;
    int c_fd;
};

struct Node //存放已注册用户
{
    char name[50];
    char password[20];
    struct Node *next;
};

int personalflag[500] = {-1};
sem_t sem[500];
sem_t sem1[500];
struct user *h;  //已登录用户头节点
struct Node *h1; //已注册用户头节点
pthread_t pti1[500];
struct Forbit *F_head;            //禁言人员头节点
struct Root *r_head;              //管理员人员头节点
struct Group *G_head;             //群内成员头结点
struct VIP *V_head;               //VIP用户头结点
void insert_fp(struct Root *root) //把文件里的存到链表里,每次打开时初始化使用
{
    int cnt;
    FILE *fp;
    FILE *dp;
    dp = fopen("./R_num.txt", "r");
    fscanf(dp, "%d", &cnt);
    fclose(dp);
    fp = fopen("./root.txt", "a+");

    while (cnt != 0)
    {
        struct Root *newcilent = (struct Root *)malloc(sizeof(struct Root)); //申请空间
        if (NULL == newcilent)
        {
            return;
        }
        fscanf(fp, "%s \n", newcilent->root);
        newcilent->next = NULL;
        root->next = newcilent;
        root = root->next;
        cnt--;
    }
    fclose(fp);
}

int r_init(struct Root **root) //创建管理员用户链表头节点
{
    struct Root *newcilent = (struct Root *)malloc(sizeof(struct Root));
    if (NULL == newcilent)
    {
        return -1;
    }

    newcilent->next = NULL;
    *root = newcilent;
    int cnt = 0; //计数储存文件初始化
    FILE *dp;
    char ch;
    dp = fopen("./R_num.txt", "a"); //如果没有,则创建一个,而且不会覆盖原有的数据
    fclose(dp);
    dp = fopen("./R_num.txt", "r"); //关闭之后,再以只读模式打开
    ch = fgetc(dp);
    fclose(dp);

    if (ch == EOF) //如果ch=EOF,则证明文件为空,初始化应该存个零进去
    {
        dp = fopen("./R_num.txt", "w"); //写会覆盖
        fprintf(dp, "%d", cnt);
        fclose(dp);
    }
    else if (ch != EOF) //如果不为空,则把之前存的文件放进链表
    {

        insert_fp(*root);
    }
}

void V_insert_fp(struct VIP *vip) //把文件里的存到链表里,每次打开时初始化使用
{
    int cnt;
    FILE *fp;
    FILE *dp;
    dp = fopen("./V_num.txt", "r");
    fscanf(dp, "%d", &cnt);
    fclose(dp);
    fp = fopen("./VIP.txt", "a+");

    while (cnt != 0)
    {
        struct VIP *newcilent = (struct VIP *)malloc(sizeof(struct VIP)); //申请空间
        if (NULL == newcilent)
        {
            return;
        }
        fscanf(fp, "%s \n", newcilent->name);
        newcilent->next = NULL;
        vip->next = newcilent;
        vip = vip->next;
        cnt--;
    }
    fclose(fp);
}

int V_init(struct VIP **vip) //创建VIP用户链表头节点
{
    struct VIP *newcilent = (struct VIP *)malloc(sizeof(struct VIP));
    if (NULL == newcilent)
    {
        return -1;
    }

    newcilent->next = NULL;
    *vip = newcilent;
    int cnt = 0; //计数储存文件初始化
    FILE *dp;
    char ch;
    dp = fopen("./V_num.txt", "a"); //如果没有,则创建一个,而且不会覆盖原有的数据
    fclose(dp);
    dp = fopen("./V_num.txt", "r"); //关闭之后,再以只读模式打开
    ch = fgetc(dp);
    fclose(dp);

    if (ch == EOF) //如果ch=EOF,则证明文件为空,初始化应该存个零进去
    {
        dp = fopen("./V_num.txt", "w"); //写会覆盖
        fprintf(dp, "%d", cnt);
        fclose(dp);
    }
    else if (ch != EOF) //如果不为空,则把之前存的文件放进链表
    {

        V_insert_fp(*vip);
    }
}

int init(struct user **head) //创建已登录用户链表头节点
{
    struct user *newnode = (struct user *)malloc(sizeof(struct user));
    if (NULL == newnode)
    {
        return -1;
    }
    newnode->c_fd = 0;
    newnode->name[0] = 0;
    newnode->next = NULL;
    *head = newnode;
}

int init1(struct Node **head) //创建已注册用户链表头节点
{
    struct Node *newnode = (struct Node *)malloc(sizeof(struct Node));
    if (NULL == newnode)
    {
        return -1;
    }
    newnode->name[0] = 0;
    newnode->password[0] = 0;
    newnode->next = NULL;
    *head = newnode;
}

int F_init(struct Forbit **head) //创建被禁言人员链表头节点
{
    struct Forbit *newnode = (struct Forbit *)malloc(sizeof(struct Forbit));
    if (NULL == newnode)
    {
        return -1;
    }
    newnode->name[0] = 0;
    newnode->next = NULL;
    *head = newnode;
}

int G_init(struct Group **head) //创建群内成员链表头节点
{
    struct Group *newnode = (struct Group *)malloc(sizeof(struct Group));
    if (NULL == newnode)
    {
        return -1;
    }
    newnode->name[0] = 0;
    newnode->next = NULL;
    *head = newnode;
}

int insert_forbit(struct Forbit *head, char *name) //添加被禁言人员
{
    struct Forbit *newnode = (struct Forbit *)malloc(sizeof(struct Forbit));
    if (NULL == newnode)
    {
        return -1;
    }
    strcpy(newnode->name, name);
    newnode->next = NULL;
    while (head->next != NULL)
    {
        if (strcmp(head->next->name, name) == 0)
        {
            return 1;
        }
        head = head->next;
    }
    head->next = newnode;
    return 0;
}

int insert_group(struct Group *head, char *name) //添加群内成员
{
    struct Group *newnode = (struct Group *)malloc(sizeof(struct Group));
    if (NULL == newnode)
    {
        return -1;
    }
    strcpy(newnode->name, name);
    newnode->next = NULL;
    while (head->next != NULL)
    {
        if (strcmp(head->next->name, name) == 0)
        {
            return 1;
        }
        head = head->next;
    }
    head->next = newnode;
    return 0;
}

int delete_forbit(struct Forbit *head, char *name) //移除被禁言人员
{

    int count = 0;
    while (head->next != NULL)
    {
        if (strcmp(head->next->name, name) == 0)
        {
            struct Forbit *ptr = head->next;
            head->next = ptr->next;
            free(ptr);
            count++;
        }
        else
        {
            head = head->next;
        }
    }
    if (count == 0)
    {
        return 1; //该用户未被禁言
    }
    return 0;
}

int delete_group(struct Group *head, char *name) //移除群内成员
{

    int count = 0;
    while (head->next != NULL)
    {
        if (strcmp(head->next->name, name) == 0)
        {
            struct Group *ptr = head->next;
            head->next = ptr->next;
            free(ptr);
            count++;
        }
        else
        {
            head = head->next;
        }
    }
    if (count == 0)
    {
        return 1; //该用户不在群内
    }
    return 0;
}

struct user *insert_tail(struct user *head, int c_fd, char *name) //添加已登录用户
{
    struct user *newnode = (struct user *)malloc(sizeof(struct user));
    if (NULL == newnode)
    {
        return NULL;
    }
    newnode->c_fd = c_fd;
    strcpy(newnode->name, name);
    newnode->next = NULL;
    while (head->next != NULL)
    {
        head = head->next;
    }
    head->next = newnode;
    return newnode;
}

struct Node *insert(struct Node *head, char *name, char *password) //添加注册用户
{
    struct Node *newnode = (struct Node *)malloc(sizeof(struct Node));
    if (NULL == newnode)
    {
        return NULL;
    }
    strcpy(newnode->name, name);
    strcpy(newnode->password, password);
    newnode->next = NULL;
    while (head->next != NULL)
    {
        head = head->next;
    }
    head->next = newnode;
    return newnode;
}

int searchuser(struct user *head, char *name) //搜索存在用户名是否存在,存在返回线程号
{
    while (head->next != NULL)
    {
        if (strcmp(head->next->name, name) == 0)
        {
            return head->next->c_fd;
        }
        else
        {
            head = head->next;
        }
    }
    //int flag = 0;
    int flag = search1(name);
    return flag;
}

void Init() //初始化
{
    serverfd = socket(PF_INET, SOCK_STREAM, 0);
    printf("\033[0;34m创建socket成功!\033[0m\n");
    if (serverfd == -1)
    {
        perror("\033[0;31m创建socket失败\033[0m");
        exit(-1);
    }

    //为套接字设置ip协议 设置端口号  并自动获取本机ip转化为网络ip
    struct sockaddr_in addr;              //存储套接字的信息
    addr.sin_family = PF_INET;            //地址族
    addr.sin_port = htons(PORT);          //设置server端端口号,你可以随便设置,当sin_port = 0时,系统随机选择一个未被使用的端口号
    addr.sin_addr.s_addr = inet_addr(IP); //把127.0.0.1改为自己的server端的ip地址,当sin_addr = INADDR_ANY时,表示从本机的任一网卡接收数据

    //绑定套接字
    if (bind(serverfd, (meng *)&addr, sizeof(addr)) == -1)
    {
        perror("\033[0;31m绑定失败\033[0m");
        exit(-1);
    }
    //printf("\033[0;34m绑定套接字成功!\033[0m\n");

    if (listen(serverfd, 100) == -1)
    { //监听最大连接数

        perror("\033[0;31m设置监听失败!\033[0m");
        exit(-1);
    }
    //printf("\033[0;34m监听成功!\033[0m\n");
}

void insertdb(struct Node *head)
{
    char sql[500] = "\0";
    sprintf(sql, "insert into user (name,password) values('%s','%s');", head->name, head->password); //插入,修改,删除都可以用这条语句
    carryout(sql);
}

void search(char *n, char *pw) //搜索密码
{
    struct Node *head = h1;
    while (head->next != NULL)
    {
        head = head->next;
        if (strcmp(n, head->name) == 0)
        {
            strcpy(pw, head->password);
        }
    }
}

int search1(char *n) //搜索用户名是否存在
{
    int count = 0;
    struct Node *head = h1;
    while (head->next != NULL)
    {
        head = head->next;
        if (strcmp(n, head->name) == 0)
        {
            count++;
            //printf("count:%d\n", count);
        }
    }
    return count;
}

int search2(char *n) //搜索是否已经登录
{
    //printf("搜索是否已经登录\n");
    int flag = 0;
    struct user *head = h;
    while (head->next != NULL)
    {
        head = head->next;
        //printf("head.name:%s\n", head->name);
        if (strcmp(n, head->name) == 0)
        {
            //printf("已经登录\n");
            flag = 1;
            //printf("搜索完成\n");
            return 1;
        }
    }
    if (flag == 0)
    {
        return 0;
    }
    //printf("搜索完成\n");
}

int seek_Group(char *n) //搜索该成员是否为群成员
{
    struct Group *head = G_head;
    while (head->next != NULL)
    {
        head = head->next;
        if (strcmp(n, head->name) == 0) //该用户为群成员
        {
            return 1;
        }
    }
    return 0; //该用户不是群成员
}

int seek_VIP(char *n) //搜索该成员是否为VIP用户
{
    struct VIP *head = V_head;
    while (head->next != NULL)
    {
        head = head->next;
        if (strcmp(n, head->name) == 0) //该用户为VIP用户
        {
            return 1;
        }
    }
    return 0; //该用户不是VIP用户
}

int seek_forbit(char *n) //搜索该成员是否被禁言
{
    struct Forbit *head = F_head;
    while (head->next != NULL)
    {
        head = head->next;
        if (strcmp(n, head->name) == 0) //该用户被禁言
        {
            return 1;
        }
    }
    return 0; //该用户未被禁言
}

void update_pw(char *name, char *pw)
{
    struct Node *head = h1;
    while (head->next != NULL)
    {
        head = head->next;
        if (strcmp(name, head->name) == 0)
        {
            strcpy(head->password, pw);
        }
    }
}

void display(struct user *head) //显示在线用户
{
    while (head->next != NULL)
    {
        //printf("c_fd=%d\nname=%s\n", head->next->c_fd, head->next->name);
        head = head->next;
    }
}

void createtable()
{
    sqlite3 *db = NULL;
    int ret = sqlite3_open("info.db", &db); //打开数据库
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_open:");
        exit(1);
    }
    char *errmsg;
    char sql[500] = "\0"; //写入命令
    strcpy(sql, "create table user(name text,password text);");
    ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_exec:");
        printf("errmsg:%s\n", errmsg);
        exit(2);
    }
    ret = sqlite3_close(db); //关闭数据库
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_close:");
        exit(3);
    }
    return;
}

int searchtable(char *tablename)
{
    sqlite3 *db = NULL;
    int ret = sqlite3_open("info.db", &db); //打开数据库
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_open:");
        exit(1);
    }
    char sql[200] = "\0";
    sprintf(sql, "select name from sqlite_master where type='table' AND name='%s';", tablename);
    char *errmsg;
    char **result;
    int row, column;
    ret = sqlite3_get_table(db, sql, &result, &row, &column, &errmsg); //分别为文件描述符,数据库命令,查询结果,行,列,错误信息
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_exec:");
        printf("errmsg:%s\n", errmsg);
        exit(2);
    }
    if (row >= 1)
    {
        return 1;
    }
    else
    {
        return 0;
    }
    sqlite3_free_table(result); //释放内存
    ret = sqlite3_close(db);    //关闭数据库
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_close:");
        exit(3);
    }
}

void initdb()
{
    printf("正在进行初始化!\n");
    if (searchtable("user") == 0)
    {
        createtable();
    }
}

void carryout(char *sql)
{
    sqlite3 *db = NULL;
    int ret = sqlite3_open("info.db", &db); //打开数据库
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_open:");
        exit(1);
    }
    char *errmsg;
    ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_exec1:");
        printf("errmsg:%s\n", errmsg);
        exit(2);
    }
    ret = sqlite3_close(db); //关闭数据库
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_close:");
        exit(3);
    }
}

void updatedb(char *name, char *pw) //插入,修改数据库注册用户信息
{
    char sql[500] = "\0";
    sprintf(sql, "update user set password='%s' where name='%s';", pw, name); //插入,修改,删除都可以用这条语句
    carryout(sql);
}

void downdb(struct Node *head) //把已经注册的用户载入链表
{
    //printf("进入downdb\n");
    sqlite3 *db = NULL;
    int ret = sqlite3_open("info.db", &db); //打开数据库
    //printf("打开数据库\n");
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_open:");
        exit(1);
    }
    const char *sql = "select *from user;"; //写入命令
    //printf("写入命令\n");
    char *errmsg;
    char **result;
    int row = 0, column = 0;
    ret = sqlite3_get_table(db, sql, &result, &row, &column, &errmsg); //分别为文件描述符,数据库命令,查询结果,行,列,错误信息
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_exec:");
        printf("errmsg:%s\n", errmsg);
        exit(2);
    }
    printf("row=%d    column=%d\n", row, column);
    if (row == 0)
    {
        return;
    }
    int i, j;
    int num;
    char name[20] = "\0";
    char password[20] = "\0";
    printf("开始载入\n");
    for (i = 1; i <= row; i++)
    {
        for (j = 0; j < column; j++)
        {
            num = i * column + j;
            //printf("%s\n",result[num]);  //查询到的信息按一维数组的方式储存,0到2为id,name,age这些字段,3到5为第一行数据,6到8为第二行数据
            if (j == 0)
            {
                strcpy(name, result[num]);
            }
            if (j == 1)
            {
                strcpy(password, result[num]);
            }
        }
        insert(head, name, password);
    }
    sqlite3_free_table(result); //释放内存
    //printf("释放内存\n");
    ret = sqlite3_close(db); //关闭数据库
    //printf("关闭数据库\n");
    if (SQLITE_OK != ret)
    {
        perror("sqlite3_close:");
        exit(3);
    }
    return;
}

int Function(struct client head) //聊天室功能选择
{
    //printf("msg:%s\n", head.msg);
    struct Forbit *p = F_head;
    struct Root *Root = r_head;
    struct user *all = h;
    struct Group *group = G_head;
    struct VIP *vip = V_head;

    int temp = head.root;
    int flag = seek_VIP(head.name);
    if (flag == 1)
    {
        head.root = 2;
    }

    if (-1 == head.flag)
    {
        delete_group(group, head.name); //退出群聊
    }
    else if (0 == head.flag) //发送给所有在线用户
    {
        while (all->next != NULL)
        {
            all = all->next;
            if (strcmp(all->name, head.name) == 0)
            {
                if (all->next != NULL)
                {
                    all = all->next;
                }
                else
                {
                    break;
                }
            }

            if (all->c_fd != 0)
            {
                send(all->c_fd, head.msg, sizeof(head.msg), 0);
            }
        }
    }
    else if (1 == head.flag) //私聊
    {
        char buf[500];
        int toc_fd = searchuser(h, head.to_name);
        if (toc_fd == 1)
        {
            toc_fd = searchuser(h, head.name);
            sprintf(buf, "\033[0;33m该用户未登录!\033[0m\n");
            send(toc_fd, buf, sizeof(head.msg), 0);
            memset(buf, 0, sizeof(buf));
        }
        else if (toc_fd == 0)
        {
            toc_fd = searchuser(h, head.name);
            sprintf(buf, "\033[0;31m该用户不存在!\033[0m\n");
            send(toc_fd, buf, sizeof(head.msg), 0);
            memset(buf, 0, sizeof(buf));
        }
        else
        {

            int flag1 = seek_Group(head.to_name); //查找发送用户是否处在群聊
            if (flag1 == 1)
            {
                sprintf(buf, "\033[34m%s\033[35m(私密消息)\033[36m:%s\033[0m\n", head.name, head.msg);
                strcpy(head.msg, buf);
                memset(buf, 0, sizeof(buf));
            }
            else
            {
                sprintf(buf, "\033[0;34m%s\033[36m:%s\033[0m\n", head.name, head.msg);
                strcpy(head.msg, buf);
                memset(buf, 0, sizeof(buf));
            }

            if (head.root == 2)
            {
                sprintf(buf, "\033[33m(VIP)%s", head.msg);
                strcpy(head.msg, buf);
                memset(buf, 0, sizeof(buf));
            }

            if (flag1 == 1)
            {
                sprintf(buf, "\033[5m%s", head.msg);
                strcpy(head.msg, buf);
                memset(buf, 0, sizeof(buf));
            }
            send(toc_fd, head.msg, sizeof(head.msg), 0);
        }
    }
    else if (head.flag == 2) //群聊
    {
        char buf[500];
        int t_fd;
        if (temp == -1) //进入群聊
        {
            insert_group(group, head.name);
            return 0;
        }
        int flag1 = seek_Group(head.name); //查找该用户是否为群成员
        if (flag1 == 1)
        {
            int c_fd = searchuser(h, head.name);
            int ret = seek_forbit(head.name);
            if (ret == 1) //该用户处于禁言状态
            {
                sprintf(buf, "\033[0;31m发送失败!你已被禁言!\033[0m\n");
                send(c_fd, buf, sizeof(buf), 0);
                memset(buf, 0, sizeof(buf));
                return 0;
            }
            if (head.root == 2)
            {
                sprintf(buf, "\033[0;33m(VIP)%s", head.msg);
                strcpy(head.msg, buf);
                memset(buf, 0, sizeof(buf));
            }
            while (group->next != NULL) //遍历所有群成员,,发送群消息
            {
                group = group->next;
                if (strcmp(group->name, head.name) == 0)
                {
                    if (group->next != NULL)
                    {
                        group = group->next;
                    }
                    else
                    {
                        break;
                    }
                }
                t_fd = searchuser(h, group->name);
                send(t_fd, head.msg, sizeof(head.msg), 0);
            }

            //记录聊天记录
            FILE *logs = fopen("log.txt", "a+");
            if (logs == NULL)
            {
                printf("open file erroe: \n");
            }
            else
            {
                fputs(head.msg, logs);
                fclose(logs);
            }
        }
        else
        {
            t_fd = searchuser(h, head.name);
            sprintf(buf, "\033[0;31m发送失败!你不是该群成员!\033[0m\n");
            send(t_fd, buf, strlen(buf) + 1, 0);
        }
    }
    else if (3 == head.flag) //文件传输
    {
        char buf[500];
        int toc_fd = searchuser(h, head.to_name);
        printf("%s向%s发送文件!\n", head.name, head.to_name);
        sprintf(buf, "\033[0;33m%s向你发来一份文件!\033[0m\n", head.name);
        send(toc_fd, buf, sizeof(buf), 0);
        usleep(30);
        memset(buf, 0, sizeof(buf));
        strcpy(buf, "flag==3");
        send(toc_fd, buf, strlen(buf) + 1, 0); //让客户端的进行文件接收准备
        memset(buf, 0, sizeof(buf));
        printf("文件内容:\n%s\n", head.msg);
        send(toc_fd, head.msg, sizeof(head.msg), 0); //发送文件内容
    }
    else if (4 == head.flag) //修改密码
    {
        int toc_fd = searchuser(h, head.name);
        printf("等待用户进行密码修改\n");
        int flag, flag1;
        char pw1[20] = "\0";
        char pw2[20] = "\0";
        char name[20] = "\0";

        read(toc_fd, pw1, 20);
        update_pw(head.name, pw1);
        updatedb(head.name, pw1);

        printf("用户密码修改成功\n");
    }
    else if (5 == head.flag)
    {
        char buf[500];
        int c_fd = searchuser(h, head.name);
        int toc_fd = searchuser(h, head.to_name);
        if (head.forbit == 1) //禁言
        {
            int count = 0;
            while (Root->next != NULL)
            {
                if (strcmp(Root->next->root, head.to_name) == 0)
                {
                    sprintf(buf, "\033[0;31m禁言失败!用户%s为管理员!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                    count++;
                    break;
                }
                Root = Root->next;
            }

            if (count == 0)
            {
                int flag1 = seek_VIP(head.to_name);
                if (flag1 == 1)
                {
                    sprintf(buf, "\033[0;31m禁言失败!用户%s为VIP用户!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                    count++;
                }
            }

            if (count == 0)
            {
                int ret = insert_forbit(p, head.to_name);
                if (ret == 1) //该用户已处于禁言状态
                {
                    sprintf(buf, "\033[0;31m禁言失败!用户%s已处于禁言状态,不可重复禁言!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                }
                else
                {
                    sprintf(buf, "\033[0;33m禁言成功!你已将用户%s禁言!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));

                    sprintf(buf, "\033[0;31m管理员%s将你禁言!\033[0m\n", head.name);
                    send(toc_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                }
            }
        }
        else if (head.forbit == 2) //解除禁言
        {
            int ret1 = delete_forbit(p, head.to_name);

            if (ret1 == 1)
            {
                sprintf(buf, "\033[0;33m用户%s未被禁言!\033[0m\n", head.to_name);
                send(c_fd, buf, sizeof(buf), 0);
                memset(buf, 0, sizeof(buf));
            }
            else
            {
                sprintf(buf, "\033[0;33m解除成功!你已将用户%s解除禁言!\033[0m\n", head.to_name);
                send(c_fd, buf, sizeof(buf), 0);
                memset(buf, 0, sizeof(buf));

                sprintf(buf, "\033[0;33m你被管理员%s解除禁言!\033[0m\n", head.name);
                send(toc_fd, buf, sizeof(buf), 0);
                memset(buf, 0, sizeof(buf));
            }
        }
        else if (head.forbit == 3) //踢人
        {
            int count = 0;
            while (Root->next != NULL)
            {
                if (strcmp(Root->next->root, head.to_name) == 0)
                {
                    sprintf(buf, "\033[0;31m踢出群聊失败!用户%s为管理员!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                    count++;
                    break;
                }
                Root = Root->next;
            }

            if (count == 0)
            {
                int flag1 = seek_VIP(head.to_name);
                if (flag1 == 1)
                {
                    sprintf(buf, "\033[0;31m踢出群聊失败!用户%s为VIP用户!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                    count++;
                }
            }

            if (count == 0)
            {
                int ret = delete_group(group, head.to_name);
                if (ret == 1) //该用户不是该群成员
                {
                    sprintf(buf, "\033[0;31m踢出群聊失败!用户%s不是该群成员!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                }
                else
                {
                    sprintf(buf, "\033[0;33m用户%s已被你踢出群聊!\033[0m\n", head.to_name);
                    send(c_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));

                    sprintf(buf, "\033[0;33m你被管理员%s踢出群聊!\033[0m\n", head.name);
                    send(toc_fd, buf, sizeof(buf), 0);
                    memset(buf, 0, sizeof(buf));
                }
            }
        }
    }
}

void *server_thread(void *p) //接收客户端结构体,并作出处理
{
    struct client head;
    struct user *c = h;
    struct i_fd tt = *(struct i_fd *)p;
    int i = tt.i;
    int fd = tt.c_fd;
    sem_wait(&sem1[i]);
    if (personalflag[0] == 0)
    {
        char user[50] = {};
        while (1)
        {
            char buf[100] = {};

            if (recv(fd, &head, sizeof(struct client), 0) <= 0)
            {
                while (c->next != NULL)
                {
                    c = c->next;
                    if (fd == c->c_fd)
                    {
                        c->c_fd = 0;
                        memset(c->name, 0, sizeof(c->name)); //初始化
                        break;
                    }
                }

                printf("\033[0;31m退出:%s 退出了聊天室.\033[0m\n", user);

                char buf[500];
                sprintf(buf, "\033[0;31m%s退出了聊天室. \033[0m\n", user);

                head.flag = 0;
                strcpy(head.name, user);
                strcpy(head.msg, buf);
                Function(head);

                FILE *logs = fopen("log.txt", "a");

                if (logs == NULL)
                {
                    printf("open file error: \n");
                }
                else
                {
                    fputs(buf, logs);
                    fclose(logs);
                }

                pthread_exit(0);
            }
            //把服务器接受到的信息发给所有的客户端
            strcpy(user, head.name); //记录进入群聊的用户

            Function(head);
        }
    }
}

int logon(int c_fd) //登录
{

    struct Root *root;
    root = r_head;

    printf("等待用户进行登录\n");
    int flag, flag1, flag2;
    char pw1[20] = "\0";
    char pw2[20] = "\0";
    char name[20] = "\0";
    read(c_fd, name, 20);
    printf("登录时接收到的用户名:%s\n", name);
    flag2 = search1(name); //检查该用户名是否已经进行注册
    write(c_fd, &flag2, sizeof(flag2));

    if (flag2 > 0) //已经注册,可以登录
    {
        flag1 = search2(name); //查找该用户是否已经登录
        printf("用户%s的登录状态:%d\n", name, flag1);
        write(c_fd, &flag1, sizeof(flag1));
        if (flag1 == 0)
        {
            int m_root = -1;
            read(c_fd, &m_root, sizeof(m_root));

            if (m_root == 1) //管理员模式登录
            {
                printf("\033[0;33m管理员模式登录中!\033[0m\n");
                int count = 0;
                while (root != NULL)
                {
                    if (strcmp(root->root, name) == 0)
                    {
                        write(c_fd, &m_root, sizeof(m_root));
                        count++;
                        printf("\033[0;33m管理员%s进入了聊天室!\033[0m\n", name);
                        break;
                    }
                    root = root->next;
                }
                if (count == 0) //该用户不是管理员
                {
                    printf("\033[0;33m该用户不是管理员!\033[0m\n");
                    m_root = 0;
                    write(c_fd, &m_root, sizeof(m_root));
                    logon(c_fd);
                }
            }
            read(c_fd, pw1, 20);
            search(name, pw2);
            if ((strcmp(pw1, pw2)) == 0)
            {
                flag = 1;
                write(c_fd, &flag, sizeof(flag));
                insert_tail(h, c_fd, name); //存入在线用户链表

                int vip = seek_VIP(name);
                printf("vip:%d\n", vip);
                write(c_fd, &vip, sizeof(vip));

                return 1;
            }
            else if ((strcmp(pw1, pw2)) != 0)
            {
                flag = 0;
                write(c_fd, &flag, sizeof(flag)); //让客服端重新进行用户登录
                logon(c_fd);
            }
        }
        else if (flag1 != 0)
        {
            printf("该用户已经登录,等待客户机重新输入\n");
            logon(c_fd);
        }
    }
    else if (flag2 == 0)
    {
        printf("该用户不存在,等待客户机重新输入\n");
        logon(c_fd);
    }
}

int register1(int c_fd) //注册
{
    char pw[20] = "\0";
    char name[20] = "\0";
    printf("等待客户机进行注册\n");
    read(c_fd, name, 20);
    printf("读取到用户名:%s\n", name);
    int flag = search1(name); //检查该用户名是否已经存在

    write(c_fd, &flag, sizeof(flag));

    if (flag == 0) //不存在,可以注册,读取密码
    {
        read(c_fd, pw, 20);
        struct Node *text = insert(h1, name, pw);
        printf("用户注册成功\n用户名:%s\n密码:%s\n", text->name, text->password);
        insertdb(text);
        return 1;
    }
    else if (flag == 1)
    {
        printf("用户名已存在,等待客户机重新输入\n");
        register1(c_fd);
    }
}

void *r_or_l(void *tt) //登录、注册
{

    struct i_fd *iandfd = (struct i_fd *)tt;
    int c_fd = iandfd->c_fd;
    int i = iandfd->i;
    int y = 0;
    int flag, flag1;
    while (1)
    {
        int ret = read(c_fd, &y, 4);
        if (y == 1)
        {
            flag = logon(c_fd); //登录成功返回1
            if (flag)
            {
                personalflag[i] = 0;
                sem_post(&sem1[i]); //成功则向聊天功能发送一个信号量,让其取消阻塞
                break;
            }
        }
        else if (y == 2)
        {

            register1(c_fd);
        }
    }
    pthread_join(pti1[i], NULL);
}

void server() //服务器开始工作
{
    int c_fd;
    struct user *head;    //用来存放已登录用户
    struct Node *head1;   //存放已注册用户
    struct Forbit *head2; //存放被禁言人员
    struct Root *head3;   //存放管理员名单
    struct Group *head4;  //存放群内成员
    struct VIP *head5;    //存放vip用户名单
    struct i_fd iandfd;
    init(&head);
    init1(&head1);
    initdb();
    downdb(head1);
    F_init(&head2); //创建禁言人员头节点
    r_init(&head3); //创建管理员用户头节点
    G_init(&head4); //创建群内成员用户头节点
    V_init(&head5); //创建VIP用户头节点
    h = head;
    h1 = head1;
    F_head = head2;
    r_head = head3;
    G_head = head4;
    V_head = head5;

    printf("服务器启动\n");
    int i = 0;
    while (1)
    {
        struct sockaddr_in fromaddr;
        socklen_t len = sizeof(fromaddr);
        int fd = accept(serverfd, (meng *)&fromaddr, &len);
        //调用accept进入堵塞状态,等待客户端的连接

        if (fd == -1)
        {
            printf("客户端连接出错...\n");
            continue;
        }
        printf("客服端连接成功\n");

        iandfd.i = i;
        iandfd.c_fd = fd;
        int ret = pthread_create(&pti1[i], NULL, r_or_l, (void *)&iandfd);
        if (ret != 0)
        {
            perror("pthread_create1:");
            exit(1);
        }
        sem_init(&sem[i], 0, 0);
        sem_init(&sem1[i], 0, 0);
        if (clientfd[i] == 0)
        {
            //记录客户端的socket
            clientfd[i] = fd;
            printf("线程号= %d\n", fd); //

            //有客户端连接之后,启动线程给此客户服务
            pthread_t tid;
            pthread_create(&tid, 0, server_thread, &iandfd);
        }

        if (size == i)
        {
            //发送给客户端说聊天室满了
            char *str = "\033[0;31m对不起,聊天室已经满了!\033[0m\n";
            send(fd, str, strlen(str), 0);
            close(fd);
        }
        i++;
    }
}

int main()
{
    system("clear");
    Init();   //初始化
    server(); //服务器开始工作
    close(serverfd);
    return 0;
}

2.客服端

#include  //客户端
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int clientfd2; //客户端socket

char *IP = "192.168.12.13"; //服务器的IP

short PORT = 6666; //服务器服务端口

typedef struct sockaddr meng;

//char user[50]; //设置支持的用户名长度

time_t nowtime;

sem_t sem1;

int line = 8; //打印消息时候的行数

int frame = 0; //是否在聊天框内 0:处在功能选择 1:处在聊天框

void progress_bar() //进度条
{

    // ****************************** 配置 ***************************
    // 最后100%时的输出形式
    const char *LastStr = "[--------------------] 100%";

    // 进度条标志,可以改用"*"或其它符号
    const char Progressicon = '-';

    // 进度每加5,进度条就会加一格,注意Step值要和LastStr中的"-"数量相匹配,两者相乘等于100
    const int Step = 5;

    // 总共需要多少进度标志,即LastStr中"-"的数量
    const int iconMaxNum = 20;

    // 每隔100ms打印一次,这里同时每隔200ms会让进度加1
    const int Printinterval = 20000;
    // ****************************************************************

    for (int i = 0; i <= 100; ++i)
    {
        // -------------- 打印进度条 --------------
        printf("\033[0;34m[\033[0m");
        int currentindex = i / Step;
        for (int j = 0; j < iconMaxNum; ++j)
        {
            if (j < currentindex)
            {
                printf("\033[0;34m%c\033[0m", Progressicon); // 打印进度条标志
            }
            else
            {
                printf(" "); // 未达进度则打印空格
            }
        }

        printf("\033[0;34m]\033[0m ");
        // ----------------------------------------

        // -------- 打印数字进度 ----------
        printf("\033[0;34m%3d%%\033[0m", i);
        fflush(stdout);
        // -------------------------------

        usleep(Printinterval);

        for (int j = 0; j < strlen(LastStr); ++j)
        {
            printf("\b"); // 回删字符,让数字和进度条原地变化
        }
        fflush(stdout);
    }
    printf("\n");
}

struct client //创建结构体
{
    int flag;          //功能标志位 -1:退出群聊 0:通知所有在线用户 1:私聊 2:群聊 3.发送文件 4.修改密码 5.管理员权限操作
    int root;          //权限标志位 -1:首次进入聊天室 0:普通用户 1:管理员 2;VIP用户
    int forbit;        //管理员权限 1:禁言 2:解除禁言 3:踢人
    char name[50];     //账号名
    char password[20]; //密码
    char msg[500];     //聊天信息
    char to_name[50];  //私聊对象
    struct client *next;
};
struct client Head;

void Clear_news() //清除输入框内容
{
    printf("\033[33;12H"); //将光标移动回到消息发送区
    printf("\033[K");      //清除发送框内容
    printf("\033[72C");
    printf("\033[0;34m|                 |\033[0m\n");
    printf("\033[33;12H \033[0;36m"); //将光标移动回到消息发送区
    printf("\033[36m");
}

void Clear_hint() //清除系统提示信息
{
    printf("\033[31;4H"); //将光标系统提示信息头位置
    printf("\033[K");      //清除系统提示信息
    printf("\033[80C");
    printf("\033[0;34m|                 |\033[0m\n");  
    printf("\033[33;12H \033[0;36m"); //将光标移动回到消息发送区
}

int print_msg(char *msg, int flag) //打印消息
{
    if (frame == 1)
    {
        if ((*msg == '\0') || (*msg == '\n') )
        {
            return 0;
        }
            
        char i_msg[500];
        printf("\033[s"); //保存光标位置
        fflush(stdout);

        if (line == 8)
            printf(" \033[8;4H"); //消息打印位置
        else if (line == 10)
            printf(" \033[10;4H"); //消息打印位置
        else if (line == 12)
            printf(" \033[12;4H"); //消息打印位置
        else if (line == 14)
            printf(" \033[14;4H"); //消息打印位置
        else if (line == 16)
            printf(" \033[16;4H"); //消息打印位置
        else if (line == 18)
            printf(" \033[18;4H"); //消息打印位置
        else if (line == 20)
            printf(" \033[20;4H"); //消息打印位置
        else if (line == 22)
            printf(" \033[22;4H"); //消息打印位置
        else if (line == 24)
            printf(" \033[24;4H"); //消息打印位置
        else if (line == 26)
            printf(" \033[26;4H"); //消息打印位置
        else if (line == 28)
            printf(" \033[28;4H"); //消息打印位置
        else if (line == 30)
            printf(" \033[30;4H"); //消息打印位置
        else if (line == 32)       //行数到达最后一行
        {
            if ((Head.root == 1) && (Head.flag == 2))
            {
                Root_frame(&Head);
            }
            else
            {
                Chat_frame(&Head);
            }

            printf(" \033[8;4H"); //消息打印位置
        }

        if (flag == 1) //打印收到的消息
        {
            printf("%s", msg);
            //printf("\033[0;34m |\033[0m");
        }
        else if (flag == 2) //打印发送的消息
        {
            sprintf(i_msg, "\033[0;36m%s\033[0;33m:我\033[0m\n", msg);
            printf("%*s", 99, i_msg);
        }
        //printf("%*s",80,msg);
        line = line + 2;
        printf(" \033[u"); //恢复光标位置
        fflush(stdout);
    }
    else if (frame == 0)
    {
        return 0;
    }
}

void Chat_frame(struct client *head) //打印聊天框
{
   
    system("clear");
    printf("\033[1;1H");
    fflush(stdout);
    line = 8;
    frame = 1;
    char name[50];
    char to_name[50];
    printf("\033[34m +===================================================================================================+\033[0m\n");
    printf("\033[34m |                                                                                                   |\033[0m\n");
    printf("\033[34m |\033[35m*********************************************\033[33m\033[1m飞飞聊天室\033[0;35m********************************************\033[34m|\033[0m\n");
    printf("\033[34m |                                                                                         \033[35m版本:1.0\033[34m  |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------------------------|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------|                 |\033[0m\n");
    printf("\033[34m |                                                                                 |\033[33m\033[1m用户:            \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 | \033[33m\033[1mw!:\033[0;36m文件发送     \033[34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------|                 |\033[0m\n");
    printf("\033[34m |\033[33m消息输入:\033[0;36m                                                                        \033[34m|                 |\033[0m\n");
    printf("\033[34m |                                                                                 |\033[35m输入\033[31mq!\033[0;35m退出聊天框\033[34m |\033[0m\n");
    printf("\033[34m +===================================================================================================+\033[0m\n");

    if (head->root == 1)
    {
        sprintf(name, "%s(管理员)\n", head->name);
    }
    else if (head->root == 2)
    {
        sprintf(name, "%s(VIP)\n", head->name);
    }
    else
    {
        sprintf(name, "%s\n", head->name);
    }

    if (head->flag == 2)
    {
        sprintf(to_name, "群聊\n");
    }
    else
    {
        sprintf(to_name, "%s\n", head->to_name);
    }
    printf("\033[6;40H");                          //将管标移到聊天对象打印位置
    printf("\033[33m\033[1m%s\033[0m\n", to_name); // 聊天对象

    printf(" \033[9;85H");                       //将管标移到用户名打印位置
    printf("\033[36m\033[1m%s\033[0m \n", name); // 用户名

    printf(" \033[33;12H \033[0;36m"); //将光标移动回到消息发送区
}

void Root_frame(struct client *head) //打印管理员群聊框
{
   // printf("\n");
    system("clear");
    printf("\033[1;1H");
    fflush(stdout);
    line = 8;
    frame = 1;
    char name[50];
    char to_name[50];
    printf("\033[34m +===================================================================================================+\033[0m\n");
    printf("\033[34m |                                                                                                   |\033[0m\n");
    printf("\033[34m |\033[35m*********************************************\033[33m\033[1m飞飞聊天室\033[0;35m********************************************\033[34m|\033[0m\n");
    printf("\033[34m |                                                                                         \033[35m版本:1.0\033[34m  |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------------------------|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------|                 |\033[0m\n");
    printf("\033[34m |                                                                                 |\033[33m\033[1m用户:            \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 | \033[33m\033[1m管理员权限:    \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 | \033[36m\033[1m1!:禁言         \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 | \033[36m\033[1m2!:解除禁言     \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 | \033[36m\033[1m3!:踢人        \033[0;34m |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 | \033[35m输入关键字      \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 | \033[35m进入对应权限    \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 | \033[33m\033[1mw!:\033[0;36m文件发送     \033[34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------|                 |\033[0m\n");
    printf("\033[34m |\033[33m消息输入:\033[0;36m                                                                        \033[34m|                 |\033[0m\n");
    printf("\033[34m |                                                                                 |\033[35m输入\033[31mq!\033[0;35m退出聊天框\033[34m |\033[0m\n");
    printf("\033[34m +===================================================================================================+\033[0m\n");

    sprintf(name, "%s(管理员)\n", head->name);

    sprintf(to_name, "群聊\n");

    printf("\033[6;40H");                          //将管标移到聊天对象打印位置
    printf("\033[33m\033[1m%s\033[0m\n", to_name); // 聊天对象

    printf(" \033[9;85H");                       //将管标移到用户名打印位置
    printf("\033[36m\033[1m%s\033[0m \n", name); // 用户名

    printf(" \033[33;12H \033[0;36m"); //将光标移动回到消息发送区
}

void Function_frame(struct client *head)  //打印功能选择界面
{
    system("clear");
    line = 8;
    frame = 0;
    char name[50];
    printf("\033[34m +===================================================================================================+\033[0m\n");
    printf("\033[34m |                                                                                                   |\033[0m\n");
    printf("\033[34m |\033[35m*********************************************\033[33m\033[1m飞飞聊天室\033[0;35m********************************************\033[34m|\033[0m\n");
    printf("\033[34m |                                                                                         \033[35m版本:1.0\033[34m  |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------------------------|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |\033[33m\033[1m用户:            \033[0;34m|\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                    \033[0;36m1:私聊功能\033[0;34m                                   |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                    \033[0;36m2:进入群聊\033[0;34m                                   |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                    \033[0;36m3:修改密码\033[0;34m                                   |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                   \033[0;31m0:退出聊天室\033[0;34m                                  |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n"); 
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |                                                                                 |                 |\033[0m\n");
    printf("\033[34m |---------------------------------------------------------------------------------|                 |\033[0m\n");
    printf("\033[34m |\033[33m消息输入:\033[0;36m                                                                        \033[34m|                 |\033[0m\n");
    printf("\033[34m |                                                                                 |\033[0;35m输入\033[31mq!\033[0;35m返回本界面\033[0;34m |\n");
    printf("\033[34m +===================================================================================================+\033[0m\n");
   
     if (head->root == 1)
    {
        sprintf(name, "%s(管理员)\n", head->name);
    }
    else if (head->root == 2)
    {
        sprintf(name, "%s(VIP)\n", head->name);
    }
    else
    {
        sprintf(name, "%s\n", head->name);
    }
    printf(" \033[9;85H");                       //将管标移到用户名打印位置
    printf("\033[36m\033[1m%s\033[0m \n", name); // 用户名

    printf(" \033[33;12H \033[0;36m"); //将光标移动回到消息发送区
}

void print_hint(char *msg) //打印系统提示消息
{
    Clear_hint(); //清除系统提示信息
    printf("\033[31;4H"); //将光标系统提示信息头位置
    printf("%s",msg);      //打印提示内容
    printf("\033[33;12H \033[0;36m"); //将光标移动回到消息发送区
}

int fileread(char *massage) //读取文件
{
    int flag = 0;
    int i;
    FILE *fp;
    char past[20];
    char filename[20];
    char buffer[500];
    char buffer1[500];
    char msg[100];

    sprintf(msg,"\033[0;33m请输入文件路径:\033[0m\n");
    print_hint(msg);//打印系统提示信息
    memset(msg, 0, sizeof(msg));
    scanf("%s", past);
    getchar();
    Clear_news(); //清除输入框内容

    sprintf(msg,"\033[0;33m请输入文件名:\033[0m\n");
    print_hint(msg);//打印系统提示信息
    memset(msg, 0, sizeof(msg));
    scanf("%s", filename);
    getchar();
    Clear_news(); //清除输入框内容

    strcat(past, filename);
    fp = fopen(filename, "r");
    if (fp == NULL)
    {
        sprintf(msg,"\033[0;31m文件不存在!\033[35m(任意键继续,放弃请按1)\033[0m\n");
        print_hint(msg);//打印系统提示信息
        memset(msg, 0, sizeof(msg));
        scanf("%d",&flag);
        Clear_news(); //清除输入框内容
        if(flag == 1)
        {
            return 0;
        }
    }
    else
    {
        sprintf(msg,"\033[0;33m文件打开成功!\033[0m\n");
        print_hint(msg);//打印系统提示信息
        memset(msg, 0, sizeof(msg));
        fread(buffer, 1, sizeof(buffer), fp);
        sleep(1);
        //printf("\033[0;33m文件内容:\033[0;36m%s\033[0m\n", buffer);
    }
    if (strlen(buffer) == 1)
    {
        sprintf(msg,"\033[0;31m文件为空!\n是否往文件里写入信息.(写入请按1,其他任意键退出)\033[0m");
        print_hint(msg);//打印系统提示信息
        memset(msg, 0, sizeof(msg));
        scanf("%d", &i);
        getchar();
        Clear_news(); //清除输入框内容
        if (i == 1)
        {
            scanf("%s", buffer);
            getchar();
            fprintf(fp, "%s", buffer);
        }
        else
        {
            fclose(fp);
            return 0;
        }
    }
    if (strlen(buffer) != 0)
    {
        sprintf(buffer1, "%s\n%s", filename, buffer);
        //printf("buffer1:%s\n",buffer1);
        strcpy(massage, buffer1);
        fclose(fp);
        return 1;
    }
}

void filewrite(char *massage) //写文件
{
    int i = 0, len = 0, flag;
    FILE *fp;
    char filename[100] = "./gyf/";
    char filename1[100];
    char buffer[500];
    char msg[100];
    while (1)
    {
        if (massage[i] == '\n')
        {
            break;
        }
        len++;
        i++;
    }
    strncpy(filename1, massage, len);
    sprintf(msg,"\033[0;33m文件名:\033[0;36m%s\033[0m\n", filename1);
    print_hint(msg);//打印系统提示信息
    memset(msg, 0, sizeof(msg));
    sleep(1);
    strcat(filename, filename1);
    strcpy(buffer, &massage[len + 1]);
    //printf("\033[0;33m文件内容:\033[0;36m%s\033[0;36m", buffer);
    while (1)
    {
        flag = access(filename, 0);
        if (flag == -1)
        {
            break;
        }
        else if (flag == 0)
        {
            len = strlen(filename);
            while (filename[len - 1] != '.')
            {
                len--;
            }
            char post[10];
            strcpy(post, &filename[len - 1]);
            strcpy(&filename[len - 1], "\0");
            strcat(filename, "(1)");
            strcat(filename, post);
        }
    }
    fp = fopen(filename, "w+");
    fprintf(fp, "%s", buffer);
    fclose(fp);
    memset(filename, 0, sizeof(filename));
    memset(filename1, 0, sizeof(filename1));
    memset(buffer, 0, sizeof(buffer));

    Clear_hint();//清除系统提示信息
}

int search(struct client *head) //登录
{
    void log_in();  //声明
    int flag = -1;  //密码正确错误标志位     0:密码错误 1:密码正确
    int flag1 = -1; //该账号是否登录标志位   0:未登录 1:已登录
    int flag2 = -1; //该用户是否存在标志位   0:不存在 1:存在

    printf("\33[0;34m请输入用户名:\33[0m\n");
    scanf("%s", head->name);
    getchar();
    write(clientfd2, head->name, strlen(head->name));
    int readflag = read(clientfd2, &flag2, sizeof(flag2)); //读取用户是否存在的标识符
    if (flag2 > 0)
    {
        read(clientfd2, &flag1, sizeof(flag1)); //读取用户是否已经被登录的标识符
        if (flag1 == 0)                         //0为未被登录,即可进行登录
        {
            if (head->root == 1)
            {
                write(clientfd2, &head->root, sizeof(head->root));
                head->root = -1;
                read(clientfd2, &head->root, sizeof(head->root));
                if (head->root == 0)
                {
                    int key = 0;
                    printf("\033[0;31m该用户不是管理员!\033[0m\n");
                    printf("\033[0;33m是否继续以管理员身份登录?(任意键继续,按1返回初始界面!)\033[0m\n");
                    scanf("%d", &key);
                    if (key == 1)
                    {
                        log_in(head); //返回初始界面
                    }
                    else
                    {
                        search(head);
                    }
                }
            }
            else if (head->root == 0)
            {
                write(clientfd2, &head->root, sizeof(head->root));
            }

            printf("\33[0;34m请输入密码:\33[0m\n");
            scanf("%s", head->password);
            getchar();
            write(clientfd2, head->password, 20);
            read(clientfd2, &flag, sizeof(flag));
            if (flag)
            {
                printf("\033[0;34m正在登录中\033[0m");
                int vip;
                read(clientfd2, &vip, sizeof(vip)); //判断该用户是否为VIP
                if (vip == 1)
                {
                    head->root = 2;
                }
                progress_bar();

                return 1;
            }
            else if (flag == 0)
            {
                printf("\33[0;31m用户名或密码输入错误!\033[0m\n");
                printf("\33[0;31m请重新输入!\033[0m\n");
                search(head);
            }
        }
        else if (flag1 != 0)
        {
            printf("\33[0;31m该用户名已在其他客户端登录!\033[0m\n");
            printf("\33[0;31m请重新输入!\033[0m\n");
            search(head);
        }
    }
    else if (flag2 == 0)
    {
        printf("\33[0;31m该用户不存在!\33[0m\n");
        printf("\33[0;31m请重新输入!\033[0m\n");
        search(head);
    }
}

int sign_in(struct client *head) //用户帐号注册
{
    //获取注册用户名和密码
    while (1)
    {
        int flag = -1;
        // printf("flag:%d\n", flag);
        printf("\33[0;34m请输入用户名:\33[0m\n");
        scanf("%s", head->name);
        getchar();
        write(clientfd2, head->name, strlen(head->name));
        int readflag = read(clientfd2, &flag, sizeof(flag));

        if (readflag < 0)
        {
            break;
        }

        if (flag == 0)
        {
            printf("\33[0;34m请输入用户密码:\33[0m\n");
            scanf("%s", head->password);
            getchar();
            if (head->name[0] != '\0')
            {
                int ret = write(clientfd2, head->password, strlen(head->password));
                if (ret > 0)
                {
                    printf("\033[0;34m注册中\033[0m");
                    progress_bar();
                    printf("\033[0;34m注册成功!\033[0m\n");
                    printf("\033[0;36m用户名:%s\033[0m\n", head->name);
                    printf("\033[0;36m用户密码:%s\033[0m\n\n", head->password);
                    break;
                }
            }
        }
        else if (flag > 0)
        {
            printf("\033[0;31m用户名已被占用!\n请重新输入!\n\033[0m");
        }
    }
}

void n_init() //初始化
{
    clientfd2 = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
    struct sockaddr_in addr;                     //将套接字存在sockaddr_in结构体中
    addr.sin_family = PF_INET;                   //地址族
    addr.sin_port = htons(PORT);                 //端口号 可随意设置,不过不可超过规定的范围
    addr.sin_addr.s_addr = inet_addr(IP);        //inet_addr()函数将点分十进制的字符串转换为32位的网络字节顺序的ip信息

    //发起连接
    if (connect(clientfd2, (meng *)&addr, sizeof(addr)) == -1)
    {
        perror("\033[0;31m无法连接到服务器\033[0m");
        exit(-1);
    }
    printf("\033[0;33m客户端启动成功\n\033[0m");
}

void *recv_thread(void *p) //用于接收聊天信息
{
    char flag[20] = {};
    strcpy(flag, "flag==3");
    char buf[500] = {};
    char msg[100];
    while (1)
    { 
        char *str = buf;
        if (recv(clientfd2, buf, sizeof(buf), 0) <= 0)
        {
            break;
        }

        if (strcmp(buf, flag) == 0) //进行文件接收准备
        {
            recv(clientfd2, buf, 500, 0);
            while (*str == '\0')
            {
                str++;
            }
            printf("\033[s"); //保存光标位置
            fflush(stdout);

            //printf("\033[?25l");  //隐藏光标
            printf("\033[31;4H"); //将光标移动到系统提示信息头位置  
            printf("\033[0;33m文件接收中\033[0m");
            progress_bar();
            memset(msg, 0, sizeof(msg));
            //printf("\033[33;12H \033[0;36m"); //将光标移动回到消息发送区
            //print_msg(buf, 3); //打印接收文件的消息
            sprintf(msg, "\033[0;35m文件接收成功!\033[0;36m");
            print_msg(msg,1);//打印信息
            sleep(1);
            memset(msg, 0, sizeof(msg));
            filewrite(str);  //写文件
           
            //printf(" \033[u"); //恢复光标位置
            fflush(stdout);
            //Clear_news(); //清除输入框内容
            printf("\033[36m");
            //printf("1\n");
           // Clear_news(); //清除输入框内容
           printf("\033[?25h"); //显示光标
            
                   
           // printf("\033[12C \033[1A");
            
        }
        else
        {
            print_msg(buf, 1); //打印接收的消息
        }
        memset(buf, 0, sizeof(buf));
    }
}

void transfer_file(struct client *head,int temp) //文件传输
{
    char msg[100];
    if(temp == 1)  //该用户处在群聊
    {
        sprintf(msg,"\033[0;33m请输入发送对象 :\033[0m\n");
        print_hint(msg);//打印系统提示信息
        memset(msg, 0, sizeof(msg));
        scanf("%s", head->to_name);
        getchar();
        Clear_news(); //清除输入框内容
    }
    
    while (1)
    {
        int y;
        int i = fileread(head->msg);
        if(i == 0)
        {
            break;
        }
        else if (i == 1)
        {
            send(clientfd2, head, sizeof(struct client), 0);
            printf("\033[?25l");  //隐藏光标
            printf("\033[31;4H"); //将光标系统提示信息头位置
            printf("\033[0;33m文件发送中\033[0m");
            progress_bar();
            memset(msg, 0, sizeof(msg));
            printf("\033[33;12H \033[0;36m"); //将光标移动回到消息发送区
            printf("\033[?25h"); //显示光标
            sprintf(msg,"\033[0;33m文件发送成功!\033[0;35m(按任意键继续,退出请按1)\033[0;36m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            scanf("%d", &y);
            getchar();
            Clear_news(); //清除输入框内容
            //printf("1\n");
           // Clear_news(); //清除输入框内容
            printf("\033[36m");
        }
        else
        {
            sprintf(msg,"\033[0;31m文件为空,无法传送!\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
        }
        
        if (y == 1)
        {
            break;
        }
    }
}

void group_chat(struct client *head) //私聊、群聊
{
    void Chat_choose(); //声明
    
    if (1 == head->flag) //私聊
    {
        char msg[100];
        sprintf(msg,"\033[0;35m请输入私聊对象:\033[0m");
        print_hint(msg);//打印系统提示信息
        memset(msg, 0, sizeof(msg)); 
        scanf("%s", head->to_name);
        getchar();
        Clear_news(); //清除输入框内容
        //printf("\033[0;35m已进入与%s的私聊界面!\033[0m\n", head->to_name);
    }
    else if (2 == head->flag) //群聊
    {
        int temp = head->root; //记录用户root值
        head->root = -1;       //让服务器将该用户加入到群成员
        send(clientfd2, head, sizeof(struct client), 0);
        head->root = temp;
        //printf("\033[0;35m欢迎进入群聊!\033[0m\n");
    }

    Head = *head;
    //打印聊天框
    if ((head->root == 1) && (head->flag == 2))
    {
        Root_frame(head);
    }
    else
    {
        Chat_frame(head);
    }

    //消息输入
    while (1)
    {
        char buf[500] = {};
        //printf("\033[0;36m");
        scanf("%s", head->msg);
        getchar();

        //判断关键字
        if (strcmp(head->msg, "q!") == 0) //群出聊天
        {
            if (head->flag == 2)
            {
                head->flag = -1;
                send(clientfd2, head, sizeof(struct client), 0); //退出群聊
            }
            Chat_choose(head);
        }

        if (strcmp(head->msg, "w!") == 0) //发送文件
        {
            Clear_news(); //清除输入框内容
            if(head->flag == 1)
            {
                head->flag = 3;
                transfer_file(head,0); //文件传输
                head->flag = 1;
            }
            else if(head->flag == 2)
            {
                head->flag = 3;
                transfer_file(head,1); //文件传输
                head->flag = 2;
            }
            Clear_hint();//清除系统提示信息
            continue;  //结束本次循环,进入下次循环
        }

        if (strcmp(head->msg, "1!") == 0) //禁言
        {
            Clear_news(); //清除输入框内容
            if ((head->root == 1) && (head->flag == 2))
            {
                head->flag = 5;
                manage(head, 1);
                head->flag = 2;
                continue;
            }
        }
        if (strcmp(head->msg, "2!") == 0) //解除禁言
        {
            Clear_news(); //清除输入框内容
            if ((head->root == 1) && (head->flag == 2))
            {
                head->flag = 5;
                manage(head, 2);
                head->flag = 2;
                continue;
            }
        }
        if (strcmp(head->msg, "3!") == 0) //踢出群聊
        {
            Clear_news(); //清除输入框内容
            if ((head->root == 1) && (head->flag == 2))
            {
                head->flag = 5;
                manage(head, 3);
                head->flag = 2;
                continue;
            }
        }

        
        Clear_news(); //清除聊天框内容

        //靠左边打印发送的消息
        /*sprintf(buf, "\033[0;33m\033[1m我:\033[0;36m%s\033[0m\n", head->msg);
          print_msg(buf, 1); //靠左边打印发送的消息*/

        //靠右边打印发送的消息
        print_msg(head->msg, 2); //靠右边打印发送的消息

        if (head->flag == 2)
        {
            if (head->root == 1)
            {
                sprintf(buf, "\033[0;33m(管理员)\033[0;34m%s\033[0;36m:%s\033[0m\n", head->name, head->msg);
            }
            else
            {
                sprintf(buf, "\033[0;34m%s:\033[0;36m%s\033[0m\n", head->name, head->msg);
            }
            strcpy(head->msg, buf);
            memset(buf, 0, sizeof(buf));
        }

        send(clientfd2, head, sizeof(struct client), 0);
    }
}

void alter(struct client *head) //修改密码
{
    void Chat_choose();
    int flag = -1;                                   //用来判断密码输入是否正确
    send(clientfd2, head, sizeof(struct client), 0); //让服务器进入修改密码等待
    char pw[20];
    char pw1[20];
    char msg[100];
    while (1)
    {
        sprintf(msg,"\033[0;33m请输入旧密码:\033[0m\n");
        print_hint(msg);//打印系统提示信息
        memset(msg, 0, sizeof(msg));
        scanf("%s", pw);
        Clear_news(); //清除输入框内容
        if (strcmp(head->password, pw) == 0)
        {
            sprintf(msg,"\033[0;33m请输入新密码:\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            memset(pw, 0, 20);
            scanf("%s",pw);
            getchar();
            Clear_news(); //清除输入框内容

            sprintf(msg,"\033[0;33m请确认密码:\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            memset(pw1, 0, 20);
            scanf("%s", pw1);
            getchar();
            Clear_news(); //清除输入框内容

            if (strcmp(pw, pw1) == 0)
            {
                strcmp(head->password, pw);
                int ret = write(clientfd2, head->password, strlen(head->password));
                if (ret > 0)
                {
                    printf("\033[31;4H"); //将光标移动到系统提示信息头位置  
            printf("\033[0;33m服务器修改中\033[0m");
            progress_bar();
            memset(msg, 0, sizeof(msg));
                  
                    sprintf(msg,"\033[0;35m密码修改成功!\033[0m\n");
                    print_hint(msg);//打印系统提示信息
                    memset(msg, 0, sizeof(msg));
                    sleep(1);
                    Clear_hint();
                    break;
                }
                else
                {
                    sprintf(msg,"\033[0;31m密码修改失败,请重新输入!\033[0m\n");
                    print_hint(msg);//打印系统提示信息
                    memset(msg, 0, sizeof(msg));
                    sleep(1);
                }
            }
            else
            {
                sprintf(msg,"\033[0;31m;两次密码输入有误!请重新输入!\033[0m\n");
                print_hint(msg);//打印系统提示信息
                memset(msg, 0, sizeof(msg));
                sleep(1);
            }
        }
        else
        {
            int temp = 0;
            sprintf(msg,"\033[0;31m密码输入错误!是否继续输入\033[0;35m(任意键继续,放弃请按1)\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            scanf("%d", &temp);
            Clear_news(); //清除输入框内容
            if (temp == 1)
            {
                Chat_choose(head);
            }
        }
    }
}

void manage(struct client *head, int flag) //管理员权限
{
    Clear_news(); //清除输入框内容
    char msg[100];
    int temp = 0;
    // sprintf(msg,"\033[0;33m请输入禁言用户:\033[0m\n");
    //         print_hint(msg);//打印系统提示信息
    while (1)
    {
        if (1 == flag)
        {
            head->forbit = 1;
            sprintf(msg,"\033[0;33m请输入禁言用户:\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            scanf("%s", head->to_name);
            getchar();
            Clear_news(); //清除输入框内容
            send(clientfd2, head, sizeof(struct client), 0);
            usleep(100);
        }
        else if (2 == flag)
        {
            head->forbit = 2;
            sprintf(msg,"\033[0;33m请输入解禁用户:\033[0m\n");
            print_hint(msg); //打印系统提示信息
            memset(msg, 0, sizeof(msg));
            scanf("%s", head->to_name);
            getchar();
            Clear_news(); //清除输入框内容
            send(clientfd2, head, sizeof(struct client), 0);
            usleep(100);
        }
        else if (3 == flag)
        {
            head->forbit = 3;
            sprintf(msg,"\033[0;33m请输入被踢用户:\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            scanf("%s", head->to_name);
            getchar();
            Clear_news(); //清除输入框内容
            send(clientfd2, head, sizeof(struct client), 0);

        }
        memset(msg, 0, sizeof(msg));
        sprintf(msg,"\033[0;33m\033[1m是否继续:\033[0;33m(任意键继续,结束请按1)\033[0m \n");
        print_hint(msg);//打印系统提示信息
        memset(msg, 0, sizeof(msg));
        scanf("%d", &temp);
        getchar();
        Clear_news(); //清除输入框内容
        if(1 == temp)
        {
            Clear_hint();//清除系统提示信息
            break;
        }
        
    }
}

void Chat_choose(struct client *head) //聊天模式选择
{

    int count = 0;
    char msg[100];
    frame = 0;
    Function_frame(head);//打印功能选择框
    sprintf(msg,"\033[0;34m请输入功能选择项:\033[0m \n");
    print_hint(msg);//打印系统提示信息
    memset(msg, 0, sizeof(msg));
    while (1)
    {
        scanf("%d", &count);
        getchar();
        Clear_news(); //清除输入框内容
        printf("\n");
        switch (count)
        {
        case 1:
            Clear_hint();//清除系统提示信息
            head->flag = 1;
            group_chat(head); //私聊功能

        case 2:
            Clear_hint();//清除系统提示信息
            head->flag = 2;
            group_chat(head); //群聊功能
            break;
        case 3:
            Clear_hint();//清除系统提示信息
            head->flag = 4;
            alter(head); //修改密码
            break;
        case 0:
            printf(msg,"\033[0;33m退出成功!欢迎下次使用!\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            close(clientfd2);
            printf("\033[35,0H");
            exit(-1);
            break;
        default:
            printf("\033[0;31m选择有误!请重新输入!\033[0m\n");
            print_hint(msg);//打印系统提示信息
            memset(msg, 0, sizeof(msg));
            break;
        }
    }
}

void log_in(struct client *head) //登录&注册
{
    int select;
    system("clear");
    printf("\033[0;34m+================================================================+\033[0m\n");
    printf("\033[0;34m|                                                                |\033[0m\n");
    printf("\033[0;34m|***********************\033[0;33m欢迎来到飞飞聊天室\033[0;34m***********************|\033[0m\n");
    printf("\033[0;34m|                                                      版本:1.0 |\033[0m\n");
    printf("\033[0;34m|----------------------------------------------------------------|\033[0m\n");
    printf("\033[0;34m|                                                               |\033[0m\n");
    printf("\033[0;34m|                         \033[0;36m1.用户登录                            \033[0;34m|\033[0m\n");
    printf("\033[0;34m|                                                               |\033[0m\n");
    printf("\033[0;34m|                         \033[0;36m2.帐号注册                             \033[0;34m|\033[0m\n");
    printf("\033[0;34m|                                                               |\033[0m\n");
    printf("\033[0;34m|                         \033[0;33m3.管理员登录                           \033[0;34m|\033[0m\n");
    printf("\033[0;34m|                                                               |\033[0m\n");
    printf("\033[0;34m|                        \033[0;31m 0:退出聊天室                           \033[0;34m|\033[0m\n");
    printf("\033[0;34m|                                                               |\033[0m\n");
    printf("\033[0;34m+================================================================+\033[0m\n");
    printf("\n");
    while (1)
    {
        printf("\033[0;34m请选择:\033[0m\n");
        scanf("%d", &select);
        getchar();

        if (1 == select)
        {
            write(clientfd2, &select, sizeof(select));
            head->root = 0; //普通用户登录
            search(head);
            break;
        }
        else if (2 == select)
        {
            write(clientfd2, &select, sizeof(select));
            sign_in(head);
        }
        else if (3 == select)
        {
            select = 1;
            write(clientfd2, &select, sizeof(select));
            head->root = 1; //管理员登录
            search(head);
            break;
        }
        else if (0 == select)
        {
            printf("\033[0;33m退出成功!\033[0m\n");
            printf("\033[0;33m欢迎下次使用!\033[0m\n");
            exit(-1);
            break;
        }
        else
        {
            printf("\033[0;31m选择错误!请重新输入!\033[0m\n");
        }
    }
}

int main()
{
    struct client head;
    n_init();
    log_in(&head); //进入登录注册界面

    //创建一个线程用于数据的接收
    pthread_t id;
    void *recv_thread(void *);
    int ret1 = pthread_create(&id, 0, recv_thread, 0);
    if (ret1 != 0)
    {
        perror("pthread_create1:");
        exit(1);
    }

    //让服务器告诉所有在线用户,该用户进入聊天室
    if (head.root == 1)
    {
        sprintf(head.msg, "\033[0;33m%s\033[0;35m(管理员)\033[0;33m进入了聊天室!\033[0m\n", head.name);
    }
    else
    {
        sprintf(head.msg, "\033[0;33m%s进入了聊天室!\033[0m\n", head.name);
    }
    head.flag = 0;
    send(clientfd2, &head, sizeof(struct client), 0);
    memset(head.msg, 0, sizeof(head.msg));

    Chat_choose(&head); //进入聊天室功能界面

    close(clientfd2);
    return 0;
}

你可能感兴趣的:(数据库,网络通信,多线程,c语言,数据库,网络通信,链表,多线程)