IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> ChatRoom_LinuxC -> 正文阅读

[网络协议]ChatRoom_LinuxC

一、设计思路

在这里插入图片描述
聊天室主要基于socket网络编程来实现,所以第一步一定是使服务端和客户端连接通信,接下来就是发包和收包了。
在整个程序中,我将函数进行封装,其中一定要注意的是运算符的优先级,否则会出现Send:Socket operation on non-socket的错误。
对于服务器端,我使用了epoll实现服务器接收请求并处理请求
对于客户端,我将服务器返回的结果单独开线程进行(一定要用好锁和条件变量!),要尽可能减小锁的粒度,并且在send函数之后pthread_cond_wait()挂起等待。
在整个程序中,于我而言第一大难点是加好友和加群,因为不能让客户端发送完就一直等待,所以我创建了新的线程。第二是聊天segementation fault,第三是发送文件,经过向别人取经,我采用定长发包,多次循环,直到文件内容全部发送完成
在这其中,我还使用了数据库
server.c

#include "wrap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 8000

int main(void) {

    struct sockaddr_in serveraddr,clientaddr;
    int sockfd,addrlen,confd;
    char ipstr[128];

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&serveraddr,sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(SERV_PORT);
    Bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    Listen(sockfd,128);

    while(1) {
        addrlen = sizeof(clientaddr);
        confd = Accept(sockfd, &clientaddr, &addrlen);
        inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ipstr, sizeof(ipstr));
        printf("client IP %s\tport %d\n",
               inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ipstr, sizeof(ipstr)),
               ntohs(clientaddr.sin_addr.s_addr));//IP地址端口号
        //处理客户端请求
        Close(confd);
    }
    Close(sockfd);
    return 0;
}

client.c

#include "wrap.h"
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>



#define SERV_PORT 8000

int main(int argc, char *argv[]) {

    struct sockaddr_in serveraddr;
    char ipstr[ ]="192.168.30.134";
    int confd;

    confd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    inet_pton(AF_INET, ipstr, &serveraddr.sin_addr.s_addr);
    serveraddr.sin_port = htons(SERV_PORT);

    Connect(confd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    //请求服务器处理数据

    Close(confd);
    return 0;

}

二、问题

1.send recv包

在服务器和客户端连接上之后,主要就是通过send、recv包进行通信,所以PACK的结构体至关重要,需要足够明确且全面。但我因为开始没有什么思路,所以结构体的定义和封装的send()函数借鉴了别人的思路,我只做到了调用(就是会向里面传参)。。

#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>

#define BUFSIZE 1024
#define MAX_CHAR 100
#define FRI_MAX 100
#define MAX_FILE 10000

typedef struct _user
{
    char name[MAX_CHAR];
    char passwd[MAX_CHAR];
    int statu_s;
    int fd;
    char chat[MAX_CHAR];
    struct _user *next;
}User;

typedef struct _relation
{
    char name1[MAX_CHAR];
    char name2[MAX_CHAR];
    int statu_s;
    struct _relation *next;
}Relation;

typedef struct _recordinfo
{
    char name1[MAX_CHAR];
    char name2[MAX_CHAR];
    char message[BUFSIZE];
    struct _recordinfo *next;
}Recordinfo;

typedef struct _friends
{
    char friends[FRI_MAX][MAX_CHAR];
    int friends_status[FRI_MAX];
    int friends_num;
}FRI_INFO;

typedef struct _group
{
    char groups[FRI_MAX][MAX_CHAR];
    int grp_num;
}GROUP_INFO;

typedef struct _record
{
    char name1[MAX_CHAR];
    char name2[MAX_CHAR];
    char message[MAX_CHAR];
}RECORD_INFO;

typedef struct _data
{
    int send_fd;
    int recv_fd;
    char send_name[MAX_CHAR];
    char recv_name[MAX_CHAR];    
    char mes[MAX_CHAR * 3];
}DATA;

typedef struct file
{
    int size;
    char mes[MAX_FILE];
}FIle;

typedef struct _pack
{
    int type;
    DATA data;
    FIle file;
    FRI_INFO fri_info;
    GROUP_INFO grp_info;
    RECORD_INFO rec_info[55];
}PACK;

客户端

void send_pack(int type, char *send_name, char *recv_name, char *mes)
{
    PACK pack_send;
    memset(&pack_send, 0, sizeof(PACK));
    pack_send.type = type;
    pack_send.data.recv_fd = confd;
    strcpy(pack_send.data.send_name, send_name);
    strcpy(pack_send.data.recv_name, recv_name);
    strcpy(pack_send.data.mes, mes);
    if(send(confd, &pack_send, sizeof(PACK), 0) < 0)
        my_err("send",__LINE__);
}

服务端

void send_more(int fd, int type, PACK *recv_pack, char *mes)
{
    PACK pack_send;
    char temp[MAX_CHAR];
    memcpy(&pack_send, recv_pack, sizeof(PACK));
    strcpy(temp,pack_send.data.recv_name);
    
    pack_send.type = type;
    strcpy(pack_send.data.recv_name, pack_send.data.send_name);
    strcpy(pack_send.data.send_name, temp);
    strcpy(pack_send.data.mes, mes);
    pack_send.data.recv_fd = pack_send.data.send_fd;
    pack_send.data.send_fd = fd;

    if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
        my_err("send", __LINE__);
}

void send_pack(int fd, PACK *recv_pack, char *ch)
{
    PACK pack_send;
    memcpy(&pack_send, recv_pack, sizeof(PACK));
    printf("%s\t%s\n", pack_send.data.recv_name, pack_send.data.send_name);
    strcpy(pack_send.data.recv_name, pack_send.data.send_name);
    strcpy(pack_send.data.send_name, "server");
    strcpy(pack_send.data.mes, ch);
    pack_send.data.recv_fd = pack_send.data.send_fd;
    pack_send.data.send_fd = fd;

    if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
        my_err("send", __LINE__);
}

2.epoll(多路复用IO)

(1).epoll_create()

创建一个epoll句柄,参数size用来告诉内核监听的文件描述符个数,跟内存大小有关

#include <sys/epoll.h>

int epoll_create(int size) 
size:告诉内核监听的数目

(2).epoll_ctl()

控制某个epoll监控的文件描述符上的事件:注册、修改、删除。

#include <sys/epoll.h>

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 
epfd:为epoll_creat的句柄 
op:表示动作,用3个宏来表示: 
	EPOLL_CTL_ADD(注册新的fd到epfd)EPOLL_CTL_MOD(修改已经注册的fd的监听事件)EPOLL_CTL_DEL(从epfd删除一个fd); 
event:告诉内核需要监听的事件 struct 
epoll_event 
{ 
	__uint32_t events; /* Epoll events */ 
	epoll_data_t data; /* User data variable */ 
}; 
	EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭)
	EPOLLOUT:表示对应的文件描述符可以写

(3).epoll_wait()

等待所监控文件描述符上有事件的产生

#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 

events:用来从内核得到事件的集合, 
maxevents:告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size, 
timeout:是超时时间
   -1:阻塞
	0:立即返回,非阻塞
   >0:指定微秒 
返回值:成功返回有多少文件描述符就绪,时间到时返回0,出错返回-1

3.正则表达式

用于退出聊天。

4.pthread_cond_wait:

pthread _mutex_lock(&mutex)

while或if(线程执行的条件是否成立)

      pthread_cond_wait(&cond, &mutex);

线程执行

pthread_mutex_unlock(&mutex);

三、源码

1.服务器端


#include "wrap.h"
#include "chat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <mysql/mysql.h>
#include <sys/epoll.h>
#include <error.h>
#include <unistd.h>
#include <sys/stat.h>


#define SERV_PORT 8000
#define MAX_EVENTS 1000

#define OFFLINE 0
#define ONLINE 1
#define ONE_CHAT 2
#define MANY_CHAT 3

#define FRIEND 1
#define FRI_BLK 2
#define GRP 3
#define GRP_OWN 4
#define GRP_ADM 5

#define EXIT -1
#define REGISTE 1
#define LOGIN 2
#define CHECK_FRI 3
#define GET_FRI_STA 4
#define ADD_FRI 5
#define DEL_FRI 6
#define SHI_FRI 7
#define CRE_GRP 8
#define ADD_GRP 9
#define OUT_GRP 10
#define DEL_GRP 11
#define SET_GRP_ADM 12
#define KICK_GRP 13
#define CHECK_GRP 14
#define CHECK_MEM_GRP 15
#define CHAT_ONE 16
#define CHAT_MANY 17
#define CHECK_MES_FRI 18
#define CHECK_MES_GRP 19
#define RECV_FILE 20
#define SEND_FILE 21


User *U_read();                     //读取用户信息表
Relation *R_read();                 //读取关系表
Recordinfo *RC_read();              //读取消息记录
void Insert(User *pNew);            //注册
void Insert_R(Relation *pNew);      
void Insert_RC(Recordinfo *pNew);   
void Delete_R(Relation *pNew);      
void DeleteLink();                  	
void DeleteLink_R();                	
void DeleteLink_RC();               	
void *Menu(void *recv_pack_t);      
void Exit(PACK *recv_pack);        
void registe(PACK *recv_pack);      //注册
void login(PACK *recv_pack);        //登陆
void check_fri(PACK *recv_pack);    //查看好友列表
void get_fri_sta(PACK *recv_pack);  //获取好友状态
void add_fri(PACK *recv_pack);      //添加好友
void del_fri(PACK *recv_pack);      //删除好友
void shi_fri(PACK *recv_pack);      //屏蔽好友
void cre_grp(PACK *recv_pack);      
void add_grp(PACK *recv_pack);      
void out_grp(PACK *recv_pack);      
void del_grp(PACK *recv_pack);      
void set_grp_adm(PACK *recv_pack);  //设置管理员
void kick_grp(PACK *recv_pack);     //踢人
void check_grp(PACK *recv_pack);    //查看群列表       
void check_mem_grp(PACK *recv_pack);//查看群中成员
void chat_one(PACK *recv_pack);     //私聊
void chat_many(PACK *recv_pack);    //群聊
void recv_file(PACK *recv_pack);    //接收文件
void send_file(PACK *recv_pack);    //发送文件
void check_mes_fri(PACK *recv_pack);//查看与好友聊天记录
void check_mes_grp(PACK *recv_pack);//查看群组聊天记录
void send_more(int fd, int flag, PACK *recv_pack, char *mes);
void send_pack(int fd, PACK *recv_pack, char *ch);

MYSQL mysql;
User *pHead = NULL;
Relation *pStart = NULL;
Recordinfo *pRec = NULL;

PACK Mex_Box[100];
int sign;
int count;


int main(void) {

    struct sockaddr_in serveraddr,clientaddr;
    int sockfd,addrlen,confd;
    char ipstr[128];
    int epfd;
    struct epoll_event ev,events[MAX_EVENTS];
    int nready;
    int i=0;
    int ret;
    PACK recv_t;
    PACK *recv_pack;
    pthread_t pid;

    addrlen = sizeof(clientaddr);

    if(mysql_init(&mysql)==NULL){
        my_err("mysql_init",__LINE__);
        return -1;
    }

     if(mysql_real_connect(&mysql,"127.0.0.1","root","123456","chatroom",0,NULL,0)==NULL){
        my_err("mysql_real_connect",__LINE__);
        return -1;
    }
    printf("Loading...\n");

    sockfd = Socket(AF_INET,SOCK_STREAM,0);

    bzero(&serveraddr,sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(SERV_PORT);
    Bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    Listen(sockfd,128);

    epfd=epoll_create(MAX_EVENTS);
    ev.data.fd=sockfd;
    ev.events=EPOLLIN ;
    epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);
    sleep(1);
    printf("服务器启动成功!\n");

    //读数据
    pHead=U_read();
    pStart=R_read();
    pRec=RC_read();
    User *t=pHead;


    while(1){
        nready = epoll_wait(epfd, events, MAX_EVENTS, 1000);    //等待事件到来
        for(i = 0; i < nready; i++){
            if(events[i].data.fd == sockfd){
                confd = Accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen);
                printf("Connected client IP: %s, fd: %d\n",inet_ntoa(clientaddr.sin_addr), confd);
                ev.data.fd = confd;               //设置与要处理事件相关的文件描述符
                ev.events = EPOLLIN ;                //设置要处理的事件类型
                epoll_ctl(epfd, EPOLL_CTL_ADD, confd, &ev);   //注册epoll事件
                continue;
            }
            else if(events[i].events & EPOLLIN){      
                memset(&recv_t, 0, sizeof(PACK));
                ret=recv(events[i].data.fd, &recv_t, sizeof(PACK), MSG_WAITALL);
                recv_t.data.send_fd=events[i].data.fd;
 			    if (ret < 0) {
 				    Close(events[i].data.fd);
 				    perror("recv");
 				    continue;
 			    }
                else if(ret==0) {
                    ev.data.fd = events[i].data.fd;
                    while(t){
                        if(t->fd == ev.data.fd){
                            t->statu_s = OFFLINE;
                            break;
                        }
                        t = t->next;
                    }
                    printf("OFFLINE(fd): %d\n",ev.data.fd);
                    epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
                    Close(events[i].data.fd);
                    continue;
                }
                printf("------------------\n");
                printf("type      : %d\n", recv_t.type);
                printf("send_name : %s\n", recv_t.data.send_name);
                printf("recv_name : %s\n",recv_t.data.recv_name);
                printf("mes       : %s\n", recv_t.data.mes);
                printf("------------------\n\n");

                recv_t.data.recv_fd = events[i].data.fd;
 			    recv_pack = (PACK*)malloc(sizeof(PACK));
 			    memcpy(recv_pack, &recv_t, sizeof(PACK));
                Menu((void*)recv_pack);
            }
        }
    }

    Close(epfd);
    Close(sockfd);
    free(recv_pack);
    DeleteLink();
    DeleteLink_R();
    DeleteLink_RC();

    return 0;
}


//读取用户信息表
User *U_read()
{
    MYSQL_RES *res = NULL;
    MYSQL_ROW row;
    char query[1000];

    User *pEnd, *pNew;

    sprintf(query, "select * from user_data");
    mysql_real_query(&mysql, query, strlen(query));
    res = mysql_store_result(&mysql);

    while(row = mysql_fetch_row(res)){
        pNew = (User *)malloc(sizeof(User));
        strcpy(pNew->name, row[0]);
        strcpy(pNew->passwd, row[1]);
        pNew->statu_s = OFFLINE;
        pNew->next = NULL;
        if(pHead == NULL)
            pHead = pNew;
        else
            pEnd->next = pNew;
        pEnd = pNew;
    }
    return pHead;
}

//读取关系表
Relation *R_read()
{
    MYSQL_RES *res = NULL;
    MYSQL_ROW row;
    char query[1000];

    Relation *pEnd, *pNew;

    sprintf(query, "select * from friends");
    mysql_real_query(&mysql, query, strlen(query));
    res = mysql_store_result(&mysql);

    while(row = mysql_fetch_row(res)){
        pNew = (Relation *)malloc(sizeof(Relation));
        strcpy(pNew->name1, row[0]);
        strcpy(pNew->name2, row[1]);
        pNew->statu_s = row[2][0] - '0';
        pNew->next = NULL;
        if(pStart == NULL)
            pStart = pNew;
        else
            pEnd->next = pNew;
        pEnd = pNew;
    }
    return pStart;
}

//读取消息记录
Recordinfo *RC_read()
{
    MYSQL_RES *res = NULL;
    MYSQL_ROW row;
    char query[1000];
    Recordinfo *pEnd, *pNew;

    sprintf(query, "select * from records");
    mysql_real_query(&mysql, query, strlen(query));
    res = mysql_store_result(&mysql);

    while(row = mysql_fetch_row(res)){
        pNew = (Recordinfo *)malloc(sizeof(Recordinfo));
        strcpy(pNew->name1, row[0]);
        strcpy(pNew->name2, row[1]);
        strcpy(pNew->message, row[2]);
        pNew->next = NULL;
        if(pRec == NULL)
            pRec = pNew;
        else
            pEnd->next = pNew;
        pEnd = pNew;
    }
    return pRec;
}

//处理函数
void *Menu(void *recv_pack_t)
{
    PACK *recv_pack;
    recv_pack = (PACK *)recv_pack_t;
    switch(recv_pack->type)
    {
    case EXIT:
        Exit(recv_pack);
        break;
    case REGISTE:
        registe(recv_pack);            
        break;
    case LOGIN:
        login(recv_pack);
        break;
    case CHECK_FRI:
        check_fri(recv_pack);
        break;
    case GET_FRI_STA:
        get_fri_sta(recv_pack);
        break;
    case ADD_FRI:
        add_fri(recv_pack);
        break;
    case DEL_FRI:
        del_fri(recv_pack);
        break;
    case SHI_FRI:
        shi_fri(recv_pack);
        break;
    case CRE_GRP:
        cre_grp(recv_pack);
        break;
    case ADD_GRP:
        add_grp(recv_pack);
        break;
    case OUT_GRP:
        out_grp(recv_pack);
        break;
    case DEL_GRP:
        del_grp(recv_pack);
        break;
    case SET_GRP_ADM:
        set_grp_adm(recv_pack);
        break;
    case KICK_GRP:
        kick_grp(recv_pack);
        break;
    case CHECK_GRP:
        check_grp(recv_pack);
        break;
    case CHECK_MEM_GRP:
        check_mem_grp(recv_pack);
        break;
    case CHAT_ONE:
        chat_one(recv_pack);
        break;
    case CHAT_MANY:
        chat_many(recv_pack);
        break;
    case CHECK_MES_FRI:
        check_mes_fri(recv_pack);
        break;
    case CHECK_MES_GRP:
        check_mes_grp(recv_pack);
        break;
    case RECV_FILE:
        recv_file(recv_pack);
        break;
    case SEND_FILE:
        send_file(recv_pack);
        break;
    default:
        break;
    }
}

//退出
void Exit(PACK *recv_pack)
{
    User *t = pHead;
    while(t){
        if(strcmp(t->name, recv_pack->data.send_name) == 0){
            t->statu_s = OFFLINE;
            break;
        }
        t = t->next;
    }
    Close(recv_pack->data.send_fd);
}

//注册
void registe(PACK *recv_pack)
{
    char query[1000];
    int a;
    char ch[5];
    int fd;
    fd = recv_pack->data.send_fd;

    User *t = pHead;
    int flag = 0;
    User *pNew = (User *)malloc(sizeof(User));
    while(t){
        if(strcmp(t->name, recv_pack->data.send_name) == 0){
            flag = 1;
            break;
        }
        t = t->next;
    }

    //添加到数据库中并发送信息给客户端
    if(flag == 0){
        strcpy(pNew->name, recv_pack->data.send_name);
        strcpy(pNew->passwd, recv_pack->data.mes);
        pNew->statu_s = OFFLINE;
        Insert(pNew);
        memset(query, 0, strlen(query));
        sprintf(query, "insert into user_data values('%s', '%s')", recv_pack->data.send_name, recv_pack->data.mes);
        mysql_real_query(&mysql, query, strlen(query));
        ch[0] = '1';
    }
    else//重名
        ch[0] = '0';
    
    ch[1] = '\0';
    send_pack(fd, recv_pack, ch);
}

//注册——加入链表
void Insert(User *pNew)
{
    User *t = pHead;
    if(t==NULL){
        t=pNew;
        pNew->next = NULL;
    }
    else{
        while(t && t->next != NULL)
            t = t->next;
        t->next = pNew;
        pNew->next = NULL;
    }
}

//登陆
void login(PACK *recv_pack)
{
    char ch[5];
    int fd = recv_pack->data.send_fd;
    int i;

    User *t = pHead;
    int flag = 0;
    while(t)
    {
        if(strcmp(t->name, recv_pack->data.send_name) == 0 && strcmp(t->passwd, recv_pack->data.mes) == 0){
            flag = 1;
            break;
        }
        t = t->next;
    }

    if(flag == 0)//不存在
        ch[0] = '0';
    else{
        if(t->statu_s == OFFLINE){
            ch[0] = '1';
            t->statu_s = ONLINE;
            t->fd = recv_pack->data.send_fd;
        }
        else //在线
            ch[0] = '2';
    }
    ch[1] = '\0';
    send_pack(fd, recv_pack, ch);
    
    for(i = 0; i < sign; i++)
    {
        //私聊
        if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && (Mex_Box[i].type == CHAT_ONE)){
            send_more(fd, CHAT_ONE, &Mex_Box[i], "1");
            count++;
        }
        //群聊
        if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.send_name) == 0 && (Mex_Box[i].type == CHAT_MANY)){
            send_more(fd, CHAT_MANY, &Mex_Box[i], "2");
            count++;
        }
        //加好友
        if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && (Mex_Box[i].type == ADD_FRI)){
            Menu((void *)&Mex_Box[i]);
            count++;
        }
        //加群
        if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && (Mex_Box[i].type == ADD_GRP)){
            Menu((void *)&Mex_Box[i]);  
            count++;
        }
        //设置管理员/踢人
        if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.mes) == 0){
            send_more(fd, Mex_Box[i].type, &Mex_Box[i], "6");
            count++;
        }
        //发文件
        if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && strcmp(Mex_Box[i].data.mes, "success") == 0)
        {
            send_file(&Mex_Box[i]);
            count++;
        }
    }
    if(count == sign)
        sign = count = 0;
}

//查看好友列表
void check_fri(PACK *recv_pack)
{
    int flag = CHECK_FRI;
    MYSQL_RES *res = NULL;
    MYSQL_ROW row;
    char query[700];
    int rows;
    int i;

    int fd = recv_pack->data.send_fd;
    int statu_s;

    memset(query, 0, strlen(query));
    sprintf(query, "select * from friends where name1='%s' or name2='%s'", recv_pack->data.send_name, recv_pack->data.send_name);
    mysql_real_query(&mysql, query, strlen(query));
    
    res = mysql_store_result(&mysql);
    
    rows = mysql_num_rows(res); //行数

    if(rows == 0)
        recv_pack->fri_info.friends_num = 0;
    else{
        i = 0;
        while(row = mysql_fetch_row(res)){
            if(strcmp(row[0], recv_pack->data.send_name) == 0){
                strcpy(recv_pack->fri_info.friends[i], row[1]);
                statu_s = row[2][0] - '0';
                recv_pack->fri_info.friends_status[i] = statu_s;
                i++;
            }
            else if(strcmp(row[1], recv_pack->data.send_name) == 0){
                strcpy(recv_pack->fri_info.friends[i], row[0]);
                statu_s = row[2][0] - '0';
                recv_pack->fri_info.friends_status[i] = statu_s;
                i++;
            }   
        }
        recv_pack->fri_info.friends_num = i;
    }
    send_more(fd, flag, recv_pack, "");
}

//获取好友状态
void get_fri_sta(PACK *recv_pack)
{
    int flag = GET_FRI_STA;
    char ch[5];
    int fd = recv_pack->data.send_fd;

    User *t = pHead;
    int flag2 = 0;
    while(t){
        if(strcmp(t->name, recv_pack->data.send_name) == 0){
            flag2 = 1;
            break;
        }
        t = t->next;
    }

    if(t->statu_s == OFFLINE)
        ch[0] = '0';
    else 
        ch[0] = '1';
    ch[1] = '\0';

    send_more(fd, flag, recv_pack, ch);
}

//添加好友
void add_fri(PACK *recv_pack)
{
    char query[1700];
    int flag = ADD_FRI;
    int fd = recv_pack->data.send_fd;
    char ch[5];
    char temp[MAX_CHAR];

    User *t = pHead;
    int flag2 = 0;
    Relation *q = pStart;
    int flag3 = 0;
    Relation *pNew = (Relation *)malloc(sizeof(Relation));
    while(q){
        if((strcmp(q->name1, recv_pack->data.recv_name) == 0 && strcmp(q->name2, recv_pack->data.send_name) == 0) || (strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0)){
            flag3 = 1;
            break;
        }
        q = q->next;
    }

    if(flag3 == 1){//已经是好友
        ch[0] = '4';
        send_more(fd, flag, recv_pack, ch);
        free(pNew);
        pNew = NULL;
        return;
    }
    else{
        while(t){
            if(strcmp(t->name, recv_pack->data.recv_name) == 0){
                flag2 = 1;
                break;
            }
            t = t->next;
        }
        
        //该用户不存在
        if(flag2 == 0){
            ch[0] = '3';
            send_more(fd, flag, recv_pack, ch);
            free(pNew);
            pNew = NULL;
            return;
        }
        else{
            if(t->statu_s != OFFLINE){
                fd = t->fd;
                if(recv_pack->data.mes[0] == '0')
                    ch[0] = '0';
                else if(recv_pack->data.mes[0] == 'y'){
                    ch[0] = '1';
                    strcpy(pNew->name1, recv_pack->data.recv_name);
                    strcpy(pNew->name2, recv_pack->data.send_name);
                    pNew->statu_s = FRIEND;
                    printf("add----\n");
                    Insert_R(pNew);

                    memset(query, 0, strlen(query));
                    sprintf(query, "insert into friends values('%s', '%s', %d)", recv_pack->data.recv_name, recv_pack->data.send_name, FRIEND);
                    mysql_real_query(&mysql, query, strlen(query));
                }
                else if(recv_pack->data.mes[0] == 'n')
                    ch[0] = '2';
                
                strcpy(temp,recv_pack->data.recv_name);
                strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
                strcpy(recv_pack->data.send_name, temp);
                send_more(fd, flag, recv_pack, ch);
            }
            else if(t->statu_s == OFFLINE)
                memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));       //登陆

        }
    }
}

//加入关系表
void Insert_R(Relation *pNew)
{
    Relation *t = pStart;
    if(t==NULL){
        t=pNew;
        pNew->next = NULL;
    }
    else{
        while(t && t->next != NULL)
            t = t->next;
        t->next = pNew;
        pNew->next = NULL;
    }
}

//删除好友
void del_fri(PACK *recv_pack)
{
    char query[1700];
    int flag = DEL_FRI;
    char ch[5];
    int fd = recv_pack->data.send_fd;

    Relation *q = pStart;
    int flag3 = 0;
    while(q){
        if((strcmp(q->name1, recv_pack->data.mes) == 0 && strcmp(q->name2, recv_pack->data.send_name) == 0) || (strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0)){
            flag3 = 1;
            break;
        }
        q = q->next;
    }

    if(flag3 == 0)//不是好友
        ch[0] = '0';
    else{
        Delete_R(q);

        memset(query, 0, strlen(query));
        sprintf(query, "delete from friends where (name1='%s' and name2='%s') or (name1='%s' and name2='%s')", recv_pack->data.send_name, recv_pack->data.mes, recv_pack->data.mes, recv_pack->data.send_name);
        mysql_real_query(&mysql, query, strlen(query));
        ch[0] = '1';
    }
    send_more(fd, flag, recv_pack, ch);
}

//删除出关系表
void Delete_R(Relation *pNew)
{
    Relation *t = pStart;
    Relation *ptr;
    while(t){
        if((strcmp(t->name1, pNew->name1) == 0 && strcmp(t->name2, pNew->name2) == 0) || (strcmp(t->name1, pNew->name2) == 0 && strcmp(t->name2, pNew->name2) == 0)){
            if(pStart == t){
                pStart = t->next;
                free(t);
                return;
            }
            ptr->next = t->next;
            free(t);
            return;
        }
        ptr = t;
        t = t->next;
    }
}

//屏蔽好友
void shi_fri(PACK *recv_pack)
{
    char query[1700];
    int flag = SHI_FRI;
    char ch[5];
    int fd = recv_pack->data.send_fd;

    Relation *q = pStart;
    int flag3 = 0;
    while(q){
        if((strcmp(q->name1, recv_pack->data.mes) == 0 && strcmp(q->name2, recv_pack->data.send_name) == 0) || (strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0)){
            flag3 = 1;
            break;
        }
        q = q->next;
    }

    if(flag3 == 0)
        ch[0] = '0';
    else{
        q->statu_s = FRI_BLK;
        memset(query, 0, strlen(query));
        sprintf(query, "update friends set status=%d where (name1='%s' and name2='%s') or (name1='%s' and name2='%s')", FRI_BLK, recv_pack->data.send_name, recv_pack->data.mes, recv_pack->data.mes, recv_pack->data.send_name);
        mysql_real_query(&mysql, query, strlen(query));
        ch[0] = '1';
    }
    send_more(fd, flag, recv_pack, ch);

}

//创建群
void cre_grp(PACK *recv_pack)
{
    char query[1000];

    int flag = CRE_GRP;
    int fd = recv_pack->data.send_fd;
    char ch[5];

    Relation *q = pStart;
    int flag3 = 0;
    Relation *pNew = (Relation *)malloc(sizeof(Relation));
    while(q){
        if(strcmp(q->name2, recv_pack->data.mes) == 0){
            flag3 = 1;
            break;
        }
        q = q->next;
    }

    if(flag3 == 1)
        ch[0] = '0';
    else{
        ch[0] = '1';
        strcpy(pNew->name1, recv_pack->data.send_name);
        strcpy(pNew->name2, recv_pack->data.mes);
        pNew->statu_s = GRP_OWN;
        Insert_R(pNew);
        
        memset(query, 0, strlen(query));
        sprintf(query, "insert into friends values('%s', '%s', %d)", recv_pack->data.send_name, recv_pack->data.mes, GRP_OWN);
        mysql_real_query(&mysql, query, strlen(query));
    }
    send_more(fd, flag, recv_pack, ch);
}

//加群
void add_grp(PACK *recv_pack)
{
    char query[15000];

    int flag = ADD_GRP;
    int fd = recv_pack->data.send_fd;
    char ch[5];
    User *t = pHead;
    Relation *q = pStart;
    int flag2 = 0;
    Relation *pNew = (Relation *)malloc(sizeof(Relation));
    if(strcmp(recv_pack->data.mes, "y") == 0){   
        while(t){
            if(strcmp(t->name, recv_pack->data.recv_name) == 0){
                fd = t->fd;
                break;
            }
            t = t->next;
        }
        ch[0] = '2';
        printf("%s\n", recv_pack->file.mes);
        strcpy(pNew->name1, recv_pack->data.recv_name);
        strcpy(pNew->name2, recv_pack->data.send_name);
        pNew->statu_s = GRP;
        Insert_R(pNew);

        memset(query, 0, strlen(query));
        sprintf(query, "insert into friends values('%s', '%s', %d)", recv_pack->data.recv_name, recv_pack->data.send_name, GRP);
        mysql_real_query(&mysql, query, strlen(query));
        send_more(fd, flag, recv_pack, ch);
        return;
    }
    else if(strcmp(recv_pack->data.mes, "n") == 0){
        while(t){
            if(strcmp(t->name, recv_pack->data.recv_name) == 0){
                fd = t->fd;
                break;
            }
            t = t->next;
        }
        ch[0] = '3';
        send_more(fd, flag, recv_pack, ch);
        return;
    }
    while(q){
        if(strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s == GRP_OWN)){
            flag2 = 1;
            strcpy(recv_pack->data.recv_name, q->name1);
            break;
        }
        q = q->next;
    }

    if(flag2 == 0){//该群不存在
        ch[0] = '0';
        send_more(fd, flag, recv_pack, ch);
        return;
    }
    else if(flag2 == 1){
        t = pHead;
        while(t){
            if(strcmp(recv_pack->data.recv_name, t->name) == 0 && (t->statu_s != OFFLINE)){
                ch[0] = '1';
                fd = t->fd;
                strcpy(recv_pack->file.mes, recv_pack->data.mes);
                send_more(fd, flag, recv_pack, ch);
                return;
            }
            else if(strcmp(recv_pack->data.recv_name, t->name) == 0 && (t->statu_s == OFFLINE)){
                memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
                break;
            } 
            t = t->next;
        }
    }
}

//退群
void out_grp(PACK *recv_pack)
{
    char query[1000];
    int flag = OUT_GRP;
    char ch[5];
    int fd = recv_pack->data.send_fd;

    Relation *q = pStart;
    int flag_3 = 0;
    while(q){
        if(strcmp(q->name2, recv_pack->data.mes) == 0){
            flag_3 = 1;
            break;
        }
        q = q->next;
    }

    if(flag_3 == 0)
        ch[0] = '0';
    else{
        ch[0] = '1';
        Delete_R(q);

        memset(query, 0, strlen(query));
        sprintf(query, "delete from friends where name1='%s' and name2='%s'", recv_pack->data.send_name, recv_pack->data.mes);
        mysql_real_query(&mysql, query, strlen(query));
    }
    send_more(fd, flag, recv_pack, ch);
}

//解散群
void del_grp(PACK *recv_pack)
{
    char query[1000];
    int flag = DEL_GRP;
    char ch[5];
    int fd = recv_pack->data.send_fd;

    Relation *q = pStart;
    int flag3 = 0;
    int flag2 = 0;
    while(q){
        if(strcmp(q->name2, recv_pack->data.mes) == 0){
            flag2 = 1;
            break;
        }
        q = q->next;
    }

    q = pStart;
    while(q){
        if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s == GRP_OWN)){
            flag3 = 1;
            break;
        }
        q = q->next;
    }

    if(flag2 == 0)
        ch[0] = '0';
    else if(flag3 == 1 && flag2 == 1){
        ch[0] = '1';
        q = pStart;
        while(q){
            if(strcmp(q->name2, recv_pack->data.mes) == 0)
                Delete_R(q);
            q = q->next;
        }
        memset(query, 0, strlen(query));
        sprintf(query, "delete from friends where name2='%s'", recv_pack->data.mes);
        mysql_real_query(&mysql, query, strlen(query));
    }
    else if(flag3 == 0 && flag2 == 1)
        ch[0] = '2';
    send_more(fd, flag, recv_pack, ch);
}

//设置管理员
void set_grp_adm(PACK *recv_pack)
{
    char query[1000];

    int flag = SET_GRP_ADM;
    char ch[5];
    int fd = recv_pack->data.send_fd;
    int fd2;
    User *t = pHead;
    Relation *q = pStart;
    int flag3 = 0;
    int flag2 = 0;
    int flag1 = 0;
    while(q){
        if(strcmp(q->name2, recv_pack->data.recv_name) == 0){
            flag2 = 1;
            break;
        }
        q = q->next;
    }

    q = pStart;
    while(q){
        if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && strcmp(q->name1, recv_pack->data.mes) == 0){
            flag1 = 1;
            break;
        }
        q = q->next;
    }

    q = pStart;
    while(q){
        if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0 && q->statu_s == GRP_OWN){
            flag3 = 1;
            break;
        }
        q = q->next;
    }

    if(flag3 == 1 && flag2 == 1 && flag1 == 1){
        ch[0] = '1';
        q = pStart;
        while(q){
            if(strcmp(q->name1, recv_pack->data.mes) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0){
                q->statu_s = GRP_ADM;
                break;
            }
            q = q->next;
        }
        while(t){
            if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s != OFFLINE)){
                fd2 = t->fd;
                send_more(fd2, flag, recv_pack, "6");
            }
            else if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s == OFFLINE))
                memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
            t = t->next;
        }
        memset(query, 0, strlen(query));
        sprintf(query, "update friends set status=%d where name1='%s' and name2='%s'", GRP_ADM, recv_pack->data.mes, recv_pack->data.recv_name);
        mysql_real_query(&mysql, query, strlen(query));
    }
    else if(flag3 == 0 && flag2 == 1 && flag1 == 1)
        ch[0] = '2';
    else if(flag1 == 0)
        ch[0] = '3';
    else if(flag2 == 0)
        ch[0] = '0';
    send_more(fd, flag, recv_pack, ch);
}

//踢人
void kick_grp(PACK *recv_pack)
{
    char query[1000];

    int flag = KICK_GRP;
    char ch[5];
    int fd = recv_pack->data.send_fd;
    int fd2;
    User *t = pHead;
    Relation *q = pStart;
    int flag3 = 0;
    int flag1 = 0;
    int flag2 = 0;
    int flag4 = 0;
    while(q){
        if(strcmp(q->name2, recv_pack->data.recv_name) == 0){
            flag1 = 1;
            break;
        }
        q = q->next;
    }
    q = pStart;
    while(q){
        if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && strcmp(q->name1, recv_pack->data.mes) == 0){
            flag2 = 1;
            break;
        }
        q = q->next;
    }
    q = pStart;
    while(q){
        if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s == GRP_OWN || q->statu_s == GRP_ADM)){
            flag3 = 1;
            break;
        }
        q = q->next;
    }
    q = pStart;
    while(q){
        if(strcmp(q->name1, recv_pack->data.mes) == 0 && (q->statu_s == (GRP))){
            flag4 = 1;
            break;
        }
        q = q->next;
    }
    if(flag3 == 1 && flag1 == 1 && flag2 == 1 && flag4 == 1){
        ch[0] = '1';
        Delete_R(q);
        while(t){
            if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s != OFFLINE)){
                fd2 = t->fd;
                send_more(fd2, flag, recv_pack, "6");
            }
            else if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s == OFFLINE))
                memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
            t = t->next;
        }
        memset(query, 0, strlen(query));
        sprintf(query, "delete from friends where name1='%s' and name2='%s'", recv_pack->data.mes, recv_pack->data.recv_name);
        mysql_real_query(&mysql, query, strlen(query));
    }
    else if(flag3 == 0 && flag1 == 1 && flag2 == 1 && flag4 == 1)
        ch[0] = '2';
    else if(flag4 == 0)
        ch[0] = '4';
    else if(flag2 == 0)
        ch[0] = '3';
    else if(flag1 == 0)
        ch[0] = '0';
    send_more(fd, flag, recv_pack, ch);
}

//查看所加群
void check_grp(PACK *recv_pack)
{
    int flag = CHECK_GRP;
    int fd = recv_pack->data.send_fd;
    Relation *q = pStart;
    int i = 0;

    while(q){
        if(strcmp(q->name1, recv_pack->data.send_name) == 0 && (q->statu_s == GRP || q->statu_s == GRP_OWN || q->statu_s == GRP_ADM)){
            strcpy(recv_pack->grp_info.groups[i], q->name2);
            i++;
        }
        q = q->next;
    }
    recv_pack->grp_info.grp_num = i;

    send_more(fd, flag, recv_pack, "");
}

//查看群中成员
void check_mem_grp(PACK *recv_pack)
{
    int flag = CHECK_MEM_GRP;
    int fd = recv_pack->data.send_fd;
    Relation *q = pStart;
    int i = 0;

    while(q){
        if(strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s == GRP || q->statu_s == GRP_OWN || q->statu_s == GRP_ADM)){
            strcpy(recv_pack->fri_info.friends[i], q->name1);
            i++;
        }
        q = q->next;
    }
    recv_pack->fri_info.friends_num = i;

    send_more(fd, flag, recv_pack, "");
}

//私聊
void chat_one(PACK *recv_pack)
{
    int flag = CHAT_ONE;
    char ch[5];
    int fd = recv_pack->data.send_fd;
    char temp[MAX_CHAR];
    MYSQL_RES *res = NULL;
    MYSQL_ROW row;
    char query[1500];
    int rows;
    int i = 0;
    User *t = pHead;
    Relation *q = pStart;
    int flag2 = 0;
    int flag3 = 0;
    Recordinfo *pNew = (Recordinfo *)malloc(sizeof(Recordinfo));

    if(strcmp(recv_pack->data.mes, "q") == 0){
        while(t){
            if(strcmp(t->name, recv_pack->data.send_name) == 0){
                t->statu_s = ONLINE;
                t->chat[0] = '\0';
                free(pNew);
                pNew = NULL;
                return;
            }
            t = t->next;
        }
    }

    while(q){//不是好友
        if(((strcmp(q->name1,recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0) || (strcmp(q->name2,recv_pack->data.send_name) == 0 && strcmp(q->name1, recv_pack->data.recv_name) == 0)) && (q->statu_s == FRI_BLK)){
            ch[0] = '3';
            send_more(fd, flag, recv_pack, ch);
            free(pNew);
            pNew = NULL;
            return;
        }
        q = q->next;
    }
    t = pHead;
    while(t){
        if(strcmp(t->name, recv_pack->data.recv_name) == 0){
            flag2 = 1;
            break;
        }
        t = t->next;
    }
    if(flag2 == 0){//用户不存在
        ch[0] = '0';
        send_more(fd, flag, recv_pack, ch);
        free(pNew);
        pNew = NULL;
        return;
    }
    else
    {
        if(recv_pack->data.mes[0] == '1'){
            memset(query, 0, strlen(query));
            sprintf(query, "select * from off_records where name1='%s' and name2='%s'", recv_pack->data.recv_name, recv_pack->data.send_name);
            mysql_real_query(&mysql, query, strlen(query));
            res = mysql_store_result(&mysql);
            rows = mysql_num_rows(res);
            while(row = mysql_fetch_row(res)){
                strcpy(pNew->name1, row[0]);
                strcpy(pNew->name2, row[1]);
                strcpy(pNew->message, row[2]);
                Insert_RC(pNew);
                memset(query, 0, strlen(query));
                sprintf(query, "insert into records values('%s', '%s', '%s')", row[0], row[1], row[2]);
                mysql_real_query(&mysql, query, strlen(query));
                
                strcpy(recv_pack->rec_info[i].name1, row[0]);
                strcpy(recv_pack->rec_info[i].name2, row[1]);
                strcpy(recv_pack->rec_info[i].message, row[2]);
                i++;
                if(i > 50)
                    break;                          
            }
            recv_pack->rec_info[i].message[0] = '0';
            send_more(fd, flag, recv_pack, "6");

            memset(query, 0, strlen(query));
            sprintf(query, "delete from off_records where name1='%s' and name2='%s'", recv_pack->data.recv_name, recv_pack->data.send_name);
            mysql_real_query(&mysql, query, strlen(query));
            
            t = pHead;
            while(t){
                if(strcmp(t->name, recv_pack->data.send_name) == 0){
                    t->statu_s = ONE_CHAT;
                    strcpy(t->chat, recv_pack->data.recv_name);
                    break;
                }
                t = t->next;
            }
            t = pHead;
            while(t){
                if(strcmp(t->name, recv_pack->data.recv_name) == 0 && (t->statu_s != OFFLINE)){
                    flag3 = 1;
                    break;
                }
                t = t->next;
            }
            if(flag3 == 1){
                ch[0] = '1';
                fd = t->fd;
                strcpy(temp,recv_pack->data.recv_name);
                strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
                strcpy(recv_pack->data.send_name, temp);
                send_more(fd, flag, recv_pack, ch);
            }
            else{
                ch[0] = '2';
                send_more(fd, flag, recv_pack, ch);
                memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
            }
        }
        else{
            t = pHead;
            while(t){
                if(strcmp(t->name, recv_pack->data.recv_name) == 0 && strcmp(t->chat, recv_pack->data.send_name) == 0 && (t->statu_s == ONE_CHAT)){
                    fd = t->fd;
                    strcpy(pNew->name1, recv_pack->data.send_name);
                    strcpy(pNew->name2, recv_pack->data.recv_name);
                    strcpy(pNew->message, recv_pack->data.mes);
                    Insert_RC(pNew);

                    memset(query, 0, strlen(query));
                    sprintf(query, "insert into records values('%s', '%s', '%s')", recv_pack->data.send_name, recv_pack->data.recv_name, recv_pack->data.mes);
                    mysql_real_query(&mysql, query, strlen(query));
                    
                    memset(temp, 0, MAX_CHAR);
                    strcpy(temp,recv_pack->data.recv_name);
                    strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
                    send_more(fd, flag, recv_pack, recv_pack->data.mes);
                    return;
                }
                else if(strcmp(t->name, recv_pack->data.recv_name) == 0 && strcmp(t->chat, recv_pack->data.send_name) != 0){
                    memset(query, 0, strlen(query));
                    sprintf(query, "insert into off_records values('%s', '%s', '%s')", recv_pack->data.send_name, recv_pack->data.recv_name, recv_pack->data.mes);
                    mysql_real_query(&mysql, query, strlen(query));
                    free(pNew);
                    pNew = NULL;
                    return;
                }
                t = t->next;
            }
        }
    }
}

//加入聊天记录
void Insert_RC(Recordinfo *pNew)
{
    Recordinfo *p = pRec;
    if(p==NULL){
        p=pNew;
        pNew->next = NULL;
    }
    else{
        while(p && p->next != NULL)
            p = p->next;
        p->next = pNew;
        pNew->next = NULL;
    }
}

//群聊
void chat_many(PACK *recv_pack)
{
    int flag = CHAT_MANY;
    char ch[5];
    int fd = recv_pack->data.send_fd;
    char temp[MAX_CHAR];
    MYSQL_RES *res = NULL;
    MYSQL_ROW row;
    char query[1500];
    int rows;
    PACK recv_t;
    recv_t.type = flag;
    int i = 0,j = 0;
    User *t = pHead;
    Relation *q = pStart;
    int flag2 = 0;

    Recordinfo *pNew = (Recordinfo *)malloc(sizeof(Recordinfo));
    if(strcmp(recv_pack->data.mes, "q") == 0){
        while(t){
            if(strcmp(t->name, recv_pack->data.send_name) == 0){
                t->statu_s = ONLINE;
                free(pNew);
                pNew = NULL;
                return;
            }
            t = t->next;
        }
    }
    while(q){
        if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s >= GRP)){
            flag2 = 1;
            break;
        }
        q = q->next;
    }
    if(flag2 == 0){//不是群成员
        ch[0] = '0';
        send_more(fd, flag, recv_pack, ch);
        free(pNew);
        pNew = NULL;
        return;
    }
    else{
        if(strcmp(recv_pack->data.mes, "1") == 0){//加入群聊
            memset(query, 0, strlen(query));
            sprintf(query, "select * from records where name2='%s'", recv_pack->data.recv_name);
            mysql_real_query(&mysql, query, strlen(query));
            res = mysql_store_result(&mysql);
            rows = mysql_num_rows(res);
            if(rows != 0){
                while(row = mysql_fetch_row(res)){
                    if(rows <= 30){
                        strcpy(recv_pack->rec_info[i].name1, row[0]);
                        strcpy(recv_pack->rec_info[i].name2, row[1]);
                        strcpy(recv_pack->rec_info[i].message, row[2]);
                    }
                    else{
                        if(rows - i <= 30){
                            strcpy(recv_pack->rec_info[j].name1, row[0]);
                            strcpy(recv_pack->rec_info[j].name2, row[1]);
                            strcpy(recv_pack->rec_info[j].message, row[2]);
                            j++;
                        }
                    }
                    i++;
                }
            }
            if(rows <= 30)
                recv_pack->rec_info[i].message[0] = '0';
            else
                recv_pack->rec_info[j].message[0] = '0';

            send_more(fd, flag, recv_pack, "6");
            free(pNew);
            pNew = NULL;

            t = pHead;
            while(t){
                if(strcmp(t->name, recv_pack->data.send_name) == 0){
                    t->statu_s = MANY_CHAT;
                    strcpy(t->chat, recv_pack->data.recv_name);
                    break;
                }
                t = t->next;
            }
            q = pStart;
            while(q){
                if(strcmp(q->name1, recv_pack->data.send_name) != 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s >= GRP)){
                    t = pHead;
                    while(t){
                        if(strcmp(q->name1, t->name) == 0 && (t->statu_s != OFFLINE)){
                            ch[0] = '1';
                            fd = t->fd;
                            send_more(fd, flag, recv_pack, ch);
                            break;
                        }
                        else if(strcmp(q->name1, t->name) == 0 && (t->statu_s == OFFLINE)){
                            strcpy(recv_t.data.send_name, t->name);
                            strcpy(recv_t.data.recv_name, recv_pack->data.recv_name);
                            memcpy(&Mex_Box[sign++], &recv_t, sizeof(PACK));      
                            break;
                        }
                        t = t->next;
                    }
                }
                q = q->next;
            }
        }
        else{
            strcpy(pNew->name1, recv_pack->data.send_name);
            strcpy(pNew->name2, recv_pack->data.recv_name);
            strcpy(pNew->message, recv_pack->data.mes);
            Insert_RC(pNew);
            memset(query, 0, strlen(query));
            sprintf(query, "insert into records values('%s', '%s', '%s')", recv_pack->data.send_name, recv_pack->data.recv_name, recv_pack->data.mes);
            mysql_real_query(&mysql, query, strlen(query));

            q = pStart;
            while(q){
                if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s >= GRP)){
                    t = pHead;
                    while(t){
                        if(strcmp(q->name1, t->name) == 0 && strcmp(t->chat, recv_pack->data.recv_name) == 0 && (t->statu_s == MANY_CHAT)){
                            fd = t->fd;
                            bzero(temp, MAX_CHAR);
                            strcpy(temp,recv_pack->data.recv_name);
                            strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
                            send_more(fd, flag, recv_pack, recv_pack->data.mes);
                            strcpy(recv_pack->data.send_name, temp);
                            bzero(temp, MAX_CHAR);
                            strcpy(temp,recv_pack->data.recv_name);
                            strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
                            strcpy(recv_pack->data.send_name, temp);
                            break;
                        }
                        t = t->next;
                    }
                }
                q = q->next;
            }
        }
    }
}

//查看与好友聊天记录
void check_mes_fri(PACK *recv_pack)
{
    int i = 0;
    int flag = CHECK_MES_FRI;
    char ch[5];
    int fd = recv_pack->data.send_fd;
    Relation *q = pStart;
    Recordinfo *p = pRec;
    int flag2 = 0;
    while(q){
        if(((strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0) || (strcmp(q->name2, recv_pack->data.send_name) == 0 && strcmp(q->name1, recv_pack->data.mes) == 0)) && (q->statu_s == FRIEND)) {
            flag2 = 1;
            break;
        }
        q = q->next;
    }
    if(flag2 == 0)
        ch[0] = '0';
    else{
        ch[0] = '1';
        while(p){
            if((strcmp(p->name1, recv_pack->data.send_name) == 0 && strcmp(p->name2, recv_pack->data.mes) == 0) || (strcmp(p->name2, recv_pack->data.send_name) == 0 && strcmp(p->name1, recv_pack->data.mes) == 0)){
                strcpy(recv_pack->rec_info[i].name1, p->name1);
                strcpy(recv_pack->rec_info[i].name2, p->name2);
                strcpy(recv_pack->rec_info[i].message, p->message);
                i++;
                if(i > 50)
                    break;
            }
            p = p->next;
        }
    }
    recv_pack->rec_info[i].message[0] = '0';
                            
    send_more(fd, flag, recv_pack, ch);
}

//查看群组聊天记录
void check_mes_grp(PACK *recv_pack)
{
    int i = 0;
    int flag = CHECK_MES_GRP;
    char ch[5];
    int fd = recv_pack->data.send_fd;
    Relation *q = pStart;
    Recordinfo *p = pRec;
    int flag2 = 0;
    while(q){
        if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s >= GRP)){
            flag2 = 1;
            break;
        }
        q = q->next;
    }
    if(flag2 == 0)
        ch[0] = '0';
    else{
        ch[0] = '1';
        while(p){
            if((strcmp(p->name2, recv_pack->data.mes) == 0)) {
                strcpy(recv_pack->rec_info[i].name1, p->name1);
                strcpy(recv_pack->rec_info[i].name2, p->name2);
                strcpy(recv_pack->rec_info[i].message, p->message);
                i++;
                if(i > 50)
                    break;
            }
            p = p->next;
        }
    }
    recv_pack->rec_info[i].message[0] = '0';
    
    send_more(fd, flag, recv_pack, ch);
}


//接收文件
void recv_file(PACK *recv_pack)
{
    int flag = RECV_FILE;
    int fd = recv_pack->data.send_fd;
    int length = 0;
    int i = 0;
    char mes[MAX_CHAR * 3 + 1];
    char *name;
    bzero(mes, MAX_CHAR * 3 + 1);
    int fp;
    User *t = pHead;
    int flag2 = 0;
    if(strcmp(recv_pack->data.mes,"send") == 0){
        while(t){
            if(strcmp(t->name, recv_pack->data.recv_name) == 0){
                flag2 = 1;
                break;
            }
            t = t->next;
        }
        if(flag2 == 1){
            file.file_name[file.sign_file][0] = '_';
            for(i = 0; i < strlen(recv_pack->data.send_name); i++){
                if(recv_pack->data.send_name[i] == '/'){
                    name = strrchr(recv_pack->data.send_name, '/');
                    name++;
                    strcat(file.file_name[file.sign_file],name);
                    break;
                }
            }
            if(i == strlen(recv_pack->data.send_name))
                strcat(file.file_name[file.sign_file],recv_pack->data.send_name);

            strcpy(file.file_send_name[file.sign_file], recv_pack->data.recv_name);
            fp = creat(file.file_name[file.sign_file], S_IRWXU);
            file.sign_file++;
            close(fp);
            send_more(fd, flag, recv_pack, "1");
        }
        else 
            send_more(fd, flag, recv_pack, "0");
    }
    else if(strcmp(recv_pack->data.mes, "success") == 0){
        while(t){
            if(strcmp(t->name, recv_pack->data.recv_name) == 0 && (t->statu_s != OFFLINE)){
                flag2 = 1;
                break;
            }
            t = t->next;
        }
        if(flag2 == 1)
            send_file(recv_pack);
        else if(flag2 == 0)
            memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));    
    }
    else{
        for(i = 0; i < file.sign_file; i++){
            if(strcmp(recv_pack->data.recv_name, file.file_send_name[i]) == 0){
                fp = open(file.file_name[i], O_WRONLY | O_APPEND);
                break;
            }
        }
        if(write(fp, recv_pack->file.mes, recv_pack->file.size) < 0)
            my_err("write", __LINE__);
        close(fp);
        //send_more(fd, flag, recv_pack, "");
    }
}


//发送文件
void send_file(PACK *recv_pack)
{
    int flag = SEND_FILE;
    int fd = recv_pack->data.send_fd;
    int fd2;
    int fp;
    int length = 0;
    PACK send_file;
    send_file.type = flag;

    char temp[MAX_CHAR];
    User *t = pHead;
    int flag_2 = 0;
    int i = 0;
    while(t)
    {
        if(strcmp(t->name, recv_pack->data.recv_name) == 0)
        {
            fd2 = t->fd;
            break;
        }
        t = t->next;
    }

    if(strcmp(recv_pack->data.mes, "success") == 0)
    {
        strcpy(temp,recv_pack->data.recv_name);
        strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
        strcpy(recv_pack->data.send_name, temp);
        send_more(fd2, flag, recv_pack, "5");
    }
    else if(recv_pack->data.mes[0] == 'y')
    {
        for(i = 0; i < file.sign_file; i++)
            if(strcmp(file.file_send_name[i], recv_pack->data.send_name) == 0)
                break;
        send_more(fd2, flag, recv_pack, "1");
        strcpy(recv_pack->data.recv_name, file.file_name[i]);
        send_more(fd, flag, recv_pack, "4");

        strcpy(send_file.data.send_name, recv_pack->data.recv_name);
        strcpy(send_file.data.recv_name, recv_pack->data.send_name);
        fp = open(file.file_name[i], O_RDONLY);
        if(fp == -1)
            printf("未找到文件%s!\n", file.file_name[i]);
        while((length = read(fp, send_file.file.mes, MAX_FILE - 1)) > 0)
        {
            send_file.file.size = length;
            if(send(fd, &send_file, sizeof(PACK), 0) < 0)
                my_err("send",__LINE__);
            bzero(send_file.file.mes, MAX_FILE);
        }
        printf("发送成功!\n");
        send_more(fd, flag, recv_pack, "3");
        send_more(fd2, flag, recv_pack, "2");
        remove(file.file_name[i]);
        file.file_send_name[i][0] = '\0';
        close(fp);
    }
    else if(recv_pack->data.mes[0] == 'n')
    {
        send_more(fd2, flag, recv_pack, "0");
        for(i = 0; i < file.sign_file; i++)
            if(strcmp(file.file_send_name[i], recv_pack->data.send_name) == 0)
                break;
        remove(file.file_name[i]);
        file.file_send_name[i][0] = '\0';
    }
}


void send_more(int fd, int type, PACK *recv_pack, char *mes)
{
    PACK pack_send;
    char temp[MAX_CHAR];
    memcpy(&pack_send, recv_pack, sizeof(PACK));
    strcpy(temp,pack_send.data.recv_name);
    pack_send.type = type;
    strcpy(pack_send.data.recv_name, pack_send.data.send_name);
    strcpy(pack_send.data.send_name, temp);
    strcpy(pack_send.data.mes, mes);
    pack_send.data.recv_fd = pack_send.data.send_fd;
    pack_send.data.send_fd = fd;

    if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
        my_err("send", __LINE__);
}

//发送信息
void send_pack(int fd, PACK *recv_pack, char *ch)
{
    PACK pack_send;
    memcpy(&pack_send, recv_pack, sizeof(PACK));
    strcpy(pack_send.data.recv_name, pack_send.data.send_name);
    strcpy(pack_send.data.send_name, "server");
    strcpy(pack_send.data.mes, ch);
    pack_send.data.recv_fd = pack_send.data.send_fd;
    pack_send.data.send_fd = fd;

    if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
        my_err("send", __LINE__);
}

//销毁链表
void DeleteLink()		
{
    User *q = pHead;
    if(pHead == NULL)
        return;
    while(pHead){
        q = pHead->next;
        free(pHead);
        pHead = q;
    }
	pHead = NULL;
}

void DeleteLink_R()		
{
    Relation *q = pStart;
    if(pStart == NULL)
        return;
    while(pStart){
        q = pStart->next;
        free(pStart);
        pStart = q;
    }
	pStart = NULL;
}

void DeleteLink_RC()
{
    Recordinfo *q = pRec;
    if(pRec == NULL)
        return;
    while(pRec){
        q = pRec->next;
        free(pRec);
        pRec = q;
    }
	pRec = NULL;
}

2.客户端

#include "wrap.h"
#include "chat.h"
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
    

#define SERV_PORT 8000
#define MAX_LINE 20

#define EXIT -1
#define REGISTE 1
#define LOGIN 2
#define CHECK_FRI 3
#define GET_FRI_STA 4
#define ADD_FRI 5
#define DEL_FRI 6
#define SHI_FRI 7
#define CRE_GRP 8
#define ADD_GRP 9
#define OUT_GRP 10
#define DEL_GRP 11
#define SET_GRP_ADM 12
#define KICK_GRP 13
#define CHECK_GRP 14
#define CHECK_MEM_GRP 15
#define CHAT_ONE 16
#define CHAT_MANY 17
#define CHECK_MES_FRI 18
#define CHECK_MES_GRP 19
#define SEND_FILE 20
#define RECV_FILE 21

#define PASSIVE 0
#define ACTIVE 1


void *get_back(); //服务器返回结果
void Menu();            //主菜单
void Menu_friends();    //好友管理
void Menu_groups();     //群管理
void Menu_message();    //聊天记录
void Menu_mes_box();    //消息盒子
int login_menu();       //登陆菜单
int login();            //登陆
void registe();         //注册
void check_fri();       //查看好友列表
void add_fri();         //添加好友
void del_fri();         //删除好友
void shi_fri();         //屏蔽好友
void cre_grp();         //创建群
void add_grp();         //加群
void out_grp();         //退群
void power_grp_menu();  //群管理权限
void del_grp();         //解散群
void set_grp_adm();     //设置管理员
void kick_grp();        //踢人
void check_grp_menu();  //查看群
void check_grp();       //查看所加群
void check_mem_grp();   //查看群中成员
void Menu_chat();       //聊天+聊天记录
void chat_one();        //私聊
void chat_many();       //群聊
void check_mes_fri();   //查看与好友聊天记录
void check_mes_grp();   //查看群组聊天记录
void send_pack(int type, char *send_name, char *recv_name, char *mes);
void send_file();       //发送文件
void recv_file(PACK *recv_pack);       //接收文件
int get_file_size(char *send_file_name); //得到文件大小




int confd;
char user[MAX_CHAR];    //当前登陆的账号名称
char grp_name[MAX_CHAR];
FRI_INFO fri_info;      //好友列表信息
GROUP_INFO grp_info;    //群列表信息
RECORD_INFO rec_info[55];  //聊天记录

int signal;

//来自外部的请求——消息盒子
char name[100][MAX_CHAR];    //发给的人
char mes_box[100][MAX_CHAR];//消息记录
int mes_box_inc[100];//加群/好友
int sign;
int sign_ive[100];//消息状态
char mes_file[MAX_CHAR * 3];

pthread_mutex_t mutex;
pthread_cond_t cond;


int main(int argc, char *argv[]) {

    struct sockaddr_in serveraddr;
    char ipstr[ ]="127.0.0.1";
    pthread_t tid;

    confd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    inet_pton(AF_INET, ipstr, &serveraddr.sin_addr.s_addr);
    serveraddr.sin_port = htons(SERV_PORT);

    Connect(confd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    
    if(login_menu() == 0){   //判断是否登陆成功
        Close(confd);
        return 0;
    }

    pthread_create(&tid, NULL, get_back, NULL);
    Menu();
    Close(confd);
    return 0;
}

//服务器返回结果
void *get_back()
{
    pthread_mutex_t mutex_g;
    pthread_mutex_init(&mutex_g, NULL);
    while(1)
    {
        int flag;
        int i = 0;
        int fd;
        PACK recv_pack;
        int ret = recv(confd, &recv_pack, sizeof(PACK), MSG_WAITALL);
        if(ret < 0)
            my_err("recv", __LINE__);
        switch(recv_pack.type)
        {
            case CHECK_FRI:
                memcpy(&fri_info, &recv_pack.fri_info, sizeof(FRI_INFO));
                pthread_cond_signal(&cond);           
                break;
            case GET_FRI_STA:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("%s---离线\n",recv_pack.data.recv_name);
                else if(flag == 1)
                    printf("%s---在线\n",recv_pack.data.recv_name);            
                pthread_cond_signal(&cond);
                break;
            case ADD_FRI:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0){
                    sign_ive[sign] = PASSIVE;
                    sprintf(name[sign], "%s", recv_pack.data.send_name);
                    mes_box_inc[sign] = ADD_FRI;
                    sprintf(mes_box[sign], "%s请求加你为好友(y/n): ", recv_pack.data.send_name);
                    sign++;
                }
                else if(flag == 1){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "%s已同意请求", recv_pack.data.send_name);
                    sign++;
                }
                else if(flag == 2){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "%s拒绝了你的请求", recv_pack.data.send_name);
                    sign++;
                }
                else if(flag == 3){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "%s账号不存在", recv_pack.data.send_name);
                    sign++;
                }
                else if(flag == 4){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "%s已是你的好友", recv_pack.data.send_name);
                    sign++;
                }
                break;
            case DEL_FRI:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n他不是你的好友!\n");
                else if(flag == 1)
                    printf("\n删除成功!\n");                
                pthread_cond_signal(&cond);
                break;
            case SHI_FRI:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n他不是你的好友!\n");
                else if(flag == 1)
                    printf("\n屏蔽成功!\n");               
                pthread_cond_signal(&cond);
                break;
            case CRE_GRP:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n该群名已被注册!\n");
                else if(flag == 1)
                    printf("\n创建成功!\n");
                pthread_cond_signal(&cond);
                break;           
            case ADD_GRP:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n该群不存在!\n");
                else if(flag == 1){
                    memset(grp_name, 0, MAX_CHAR);
                    strcpy(grp_name, recv_pack.file.mes);
                    sign_ive[sign] = PASSIVE;
                    sprintf(name[sign], "%s", recv_pack.data.recv_name);
                    mes_box_inc[sign] = ADD_GRP;
                    sprintf(mes_box[sign], "%s请求加入群聊%s(y/n): ", recv_pack.data.recv_name, recv_pack.file.mes);
                    sign++;
                }
                else if(flag == 2){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "你已加入群聊%s", recv_pack.data.recv_name);
                    sign++;
                }
                else if(flag == 3){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "加入群聊%s请求被拒绝", recv_pack.data.recv_name);
                    sign++;
                }
                break;
            case OUT_GRP:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n该群不存在!\n");
                else if(flag == 1)
                    printf("\n退群成功!\n");
                pthread_cond_signal(&cond);
                break;
            case DEL_GRP:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n该群不存在!\n");
                else if(flag == 1)
                    printf("\n解散群成功!\n");
                else if(flag == 2)
                    printf("\n仅群主有权解散群!\n");
                pthread_cond_signal(&cond);
                break;
            case SET_GRP_ADM:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n该群不存在!\n");
                else if(flag == 1)
                    printf("\n设置管理员成功!\n");
                else if(flag == 2)
                    printf("\n只有群主可以设置管理员!\n");
                else if(flag == 3)
                    printf("\n此用户不在群中!\n");
                else if(flag == 6){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "你被设置为群%s的管理员!", recv_pack.data.send_name);
                    sign++;
                    break;
                }
                if(flag != 6)
                    pthread_cond_signal(&cond);
                break;
            case KICK_GRP:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("\n该群不存在!\n");
                else if(flag == 1)
                    printf("\n踢人成功!\n");
                else if(flag == 2)
                    printf("\n只有群主/管理员可以踢人!\n");
                else if(flag == 3)
                    printf("\n此用户不在群中!\n");
                else if(flag == 4)
                    printf("\n踢人失败!\n");
                else if(flag == 6){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "你被踢出群聊%s", recv_pack.data.send_name);
                    sign++;
                    break;
                }
                if(flag != 6)
                    pthread_cond_signal(&cond);
                break;
            case CHECK_GRP:
                memcpy(&grp_info, &recv_pack.grp_info, sizeof(GROUP_INFO));
                pthread_cond_signal(&cond);           
                break;
            case CHECK_MEM_GRP:
                memcpy(&fri_info, &recv_pack.fri_info, sizeof(FRI_INFO));
                pthread_cond_signal(&cond);           
                break;
            case CHAT_ONE:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0){
                    printf("\n该用户不存在!\n");
                    signal = 1;
                    pthread_cond_signal(&cond);           
                }
                else if(flag == 1){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "%s邀你私聊", recv_pack.data.send_name);
                    sign++;
                }
                else if(flag == 2){
                    printf("\n该用户不在线!\n");
                    pthread_cond_signal(&cond);           
                }
                else if(flag == 3){
                    printf("\n该好友已被屏蔽!\n");
                    signal = 1;
                    pthread_cond_signal(&cond);           
                }
                else if(flag == 6){
                    memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
                    pthread_cond_signal(&cond);           
                }
                else
                    printf("\n%s: %s\n", recv_pack.data.send_name, recv_pack.data.mes);
                break;
            case CHAT_MANY:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0){
                    printf("\n该群不存在!\n");
                    signal = 1;
                    pthread_cond_signal(&cond);           
                }
                else if(flag == 1){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign], "\n群%s有人进入群聊\n", recv_pack.data.send_name);
                    sign++;
                }
                else if(flag == 2){
                    sign_ive[sign] = ACTIVE;
                    sprintf(mes_box[sign],"\n群%s有新消息\n",recv_pack.data.send_name);
                    sign++;
                }
                else if(flag == 6){
                    memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
                    pthread_cond_signal(&cond);           
                }
                else
                    printf("%s: %s\n", recv_pack.data.send_name, recv_pack.data.mes);
                break;
            case CHECK_MES_FRI:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("该用户不是你的好友!\n");
                else if(flag == 1){
                    memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
                    printf("\n-----------聊天记录-----------\n");
                    if(rec_info[0].message[0] == '0')
                        printf("暂无历史记录\n");
                    else{
                        while(rec_info[i].message[0] != '0'){
                            printf("%s-->%s: %s\n",rec_info[i].name1, rec_info[i].name2, rec_info[i].message);
                            i++;
                        }
                    }
                }
                pthread_cond_signal(&cond);
                break;
            case CHECK_MES_GRP:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0)
                    printf("你不是该群成员!\n");
                else if(flag == 1){
                    memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
                    printf("-----------聊天记录-----------\n");
                    if(rec_info[0].message[0] == '0')
                    printf("暂无历史记录\n");
                    else{
                        while(rec_info[i].message[0] != '0'){
                            printf("%s: %s\n",rec_info[i].name1, rec_info[i].message);
                            i++;
                        }
                    }
                }
                pthread_cond_signal(&cond);
                break;
            case SEND_FILE:
                flag = recv_pack.data.mes[0] - '0';
                if(flag == 0){
                    printf("该用户不是你的好友!\n");
                    signal = 1;
                    pthread_cond_signal(&cond);
                }
                if(flag == 1)
                    pthread_cond_signal(&cond);
                break;
            case RECV_FILE:
                if(strcmp(recv_pack.data.mes, "5") == 0)
                {
                    sign_ive[sign] = PASSIVE;
                    sprintf(name[sign], "%s", recv_pack.data.send_name);
                    mes_box_inc[sign] = RECV_FILE;
                    sprintf(mes_box[sign], "%s给你发来了一个文件,是否接收(y/n): ", recv_pack.data.send_name);
                    sign++;
                }
                else if(strcmp(recv_pack.data.mes, "4") == 0)
                {
                    memset(mes_file, 0, sizeof(mes_file));
                    mes_file[0] = '_';
                    strcat(mes_file, recv_pack.data.send_name);
                    fd = creat(mes_file, S_IRWXU);
                    close(fd);
                }
                else if(strcmp(recv_pack.data.mes, "0") == 0)
                    printf("\n%s拒绝接收文件!\n", recv_pack.data.recv_name);
                else if(strcmp(recv_pack.data.mes, "1") == 0)
                    printf("\n%s确认接收文件!\n", recv_pack.data.recv_name);
                else if(strcmp(recv_pack.data.mes, "2") == 0)
                    printf("%s接收完毕\n", recv_pack.data.recv_name);
                else if(strcmp(recv_pack.data.mes, "3") == 0)
                    printf("接收完毕!\n");
                else 
                {
                    recv_file(&recv_pack);
                }
                break;

            default:
                break;
        }
        if(ret == 0){
            printf("\n无法连接服务器!\n");
            exit(1);
        }
    }
}

//登陆菜单
int login_menu()
{
    int flag;
    int choice;
    do
    {
        printf("------------------------\n");
        printf("|\t1.登陆\t\t|\n");
        printf("------------------------\n");
        printf("|\t2.注册\t\t|\n");
        printf("------------------------\n");
        printf("|\t0.退出\t\t|\n");
        printf("------------------------\n");
        printf("请选择: ");
        scanf("%d",&choice);
        
        switch(choice)
        {
        case 1:
            if(login() == 1)
                return 1;
            break;
        case 2:
            registe();
            break;
        default:
            break;
        }
    }while(choice != 0);
    flag = EXIT;
    send_pack(flag, user, "server", " ");
    return 0;
}


//注册
void registe()
{
    int flag = REGISTE;
    char registe_name[MAX_CHAR];
    char registe_passwd[MAX_CHAR];
    PACK recv_registe;
    int registe_flag;

    printf("请输入用户名:");
    scanf("%s",registe_name);
    printf("请输入用户密码:");
    scanf("%s",registe_passwd);

    
    send_pack(flag, registe_name, "server", registe_passwd);
    printf("请稍等...\n");
    sleep(1);
    if(recv(confd, &recv_registe, sizeof(PACK), MSG_WAITALL) < 0)
        my_err("recv", __LINE__);
    registe_flag = recv_registe.data.mes[0] - '0';

    if(registe_flag == 1)
        printf("注册成功!\n");
    else if(registe_flag == 0)
        printf("该用户名已存在,请重新选择!\n");
}

//登陆
int login()
{
    int flag = LOGIN;
    char login_name[MAX_CHAR];
    char login_passwd[MAX_CHAR];
    PACK recv_login;
    int login_flag;
    int i = 0;

    printf("请输入用户名称:");
    scanf("%s",login_name);
    getchar();                      
    printf("请输入用户密码:");
    do{
        login_passwd[i]=getch();
        if(login_passwd[i]=='\r'){
            printf("\n");
            break;
        }
        if(login_passwd[i]=='\b'){//为什么不行????
            if(i==0){
                printf("\a");
                continue;
            }
            i--;
            printf("'\b' '\b'");
        }
        else{
            i++;
            printf("*");
        }
    }while(login_passwd[i]!='\n' && i<18);
    login_passwd[i]='\0';
	
    system("clear");
    send_pack(flag, login_name, "server", login_passwd);
    if(recv(confd, &recv_login, sizeof(PACK), MSG_WAITALL) < 0)
        my_err("recv", __LINE__);
    
    login_flag = recv_login.data.mes[0] - '0';
    if(login_flag == 1)
    {
        printf("登陆成功!\n");
        strncpy(user, login_name, strlen(login_name));
        return 1;
    }
    else if(login_flag == 0)
        printf("登陆失败!\n");
    else if(login_flag == 2)
        printf("该用户已在线!\n");
    return 0;
}

//主菜单
void Menu()
{
    int choice;
    int flag;
    do
    {
        printf("---------------------------------\n");
        printf("|\t   1.好友管理   \t|\n");
        printf("---------------------------------\n");
        printf("|\t   2.群管理      \t|\n");
        printf("---------------------------------\n");
        printf("|\t   3.发送文件   \t|\n");
        printf("---------------------------------\n");
        printf("|\t   4.聊天通讯   \t|\n");
        printf("---------------------------------\n");
        printf("|\t   5.通知中心   \t|\n");
        printf("---------------------------------\n");
        printf("|\t   0.退出         \t|\n");
        printf("---------------------------------\n");
        printf("请选择:");
        scanf("%d",&choice);

        switch(choice)
        {
        case 1:
            Menu_friends();
            break;
        case 2:
            Menu_groups();
            break;          
        case 3:
            send_file();
            break;
        case 4:
            Menu_chat();
            break;
        case 5:
            Menu_mes_box();
            break;        
        default:
            break;
        }
    }while(choice != 0);
    flag = EXIT;
    send_pack(flag, user, "server", " ");
}

//好友管理
void Menu_friends()
{
    int choice;
    do
    {
        printf("---------------------------\n");
        printf("|\t1.查看好友列表    |\n");
        printf("---------------------------\n");
        printf("|\t2.添加好友\t  |\n");
        printf("---------------------------\n");
        printf("|\t3.删除好友\t  |\n");
        printf("---------------------------\n");
        printf("|\t4.屏蔽好友\t  |\n");
        printf("---------------------------\n");
        printf("|\t0.返回     \t  |\n");
        printf("---------------------------\n");
        printf("请选择:");
        scanf("%d",&choice);

        switch(choice)
        {
        case 1:
            check_fri();
            break;
        case 2:
            add_fri();
            break;           
        case 3:
            del_fri();
            break;
        case 4:
            shi_fri();
            break;
        default:
            break;
        }
    }while(choice != 0);
}

//查看好友列表
void check_fri()
{
    int flag = CHECK_FRI;
    char mes[MAX_CHAR];
    bzero(mes, MAX_CHAR);
    memset(&fri_info, 0, sizeof(fri_info));
    int i;

    pthread_mutex_lock(&mutex);
    send_pack(flag, user, "server", "1");
    pthread_cond_wait(&cond, &mutex);
    printf("\n-----------好友列表-----------\n");
    if(fri_info.friends_num == 0)
        printf("暂无好友!\n");
    else{
        for(i = 0; i < fri_info.friends_num; i++){
            if(fri_info.friends_status[i] == 1){
                flag = GET_FRI_STA;
                send_pack(flag, fri_info.friends[i], "server", mes);
                pthread_cond_wait(&cond, &mutex);
            }
            else if(fri_info.friends_status[i] == 2)
                printf("%s---黑名单\n",fri_info.friends[i]);
        }
    }
    pthread_mutex_unlock(&mutex);
}

//添加好友
void add_fri()
{
    int i;
    int flag = ADD_FRI;
    pthread_mutex_lock(&mutex);
    char friend_add[MAX_CHAR];
    printf("你想要添加的用户名:");
    scanf("%s",friend_add);
    send_pack(flag, user, friend_add, "0");
    pthread_mutex_unlock(&mutex);
}

//删除好友
void del_fri()
{
    int flag = DEL_FRI;
    char friend_del[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要删除的用户名:");
    scanf("%s",friend_del);
    send_pack(flag, user, "server", friend_del);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}

//屏蔽好友
void shi_fri()
{
    int flag = SHI_FRI;
    char friend_shi[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要屏蔽的用户名:");
    scanf("%s",friend_shi);
    send_pack(flag, user, "server", friend_shi);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}


//群管理
void Menu_groups()
{
    int choice;
    do
    {
        printf("-----------------------------\n");
        printf("|         1.查看群          |\n");
        printf("-----------------------------\n");
        printf("|         2.创建群          |\n");
        printf("-----------------------------\n");
        printf("|         3.加入群          |\n");
        printf("-----------------------------\n");
        printf("|         4.退出群          |\n");
        printf("-----------------------------\n");
        printf("|         5.管理群          |\n");
        printf("-----------------------------\n");
        printf("|         0.返回            |\n");
        printf("-----------------------------\n");
        printf("请选择:");
        scanf("%d",&choice);

        switch(choice)
        {
        case 1:
            check_grp_menu();           
            break;
        case 2:
            cre_grp();
            break;          
        case 3:
            add_grp();
            break;
        case 4:
            out_grp();
            break;
        case 5:
            power_grp_menu();
            break;
        default:
            break;
        }
    }while(choice != 0);
}

//查看群
void check_grp_menu()
{
    int choice;
    do
    {
        printf("-----------------------------\n");
        printf("|       1.查看所加群        |\n");
        printf("-----------------------------\n");
        printf("|       2.查看群中成员      |\n");
        printf("-----------------------------\n");
        printf("|       0.返回              |\n");
        printf("-----------------------------\n");
        printf("请选择:");
        scanf("%d",&choice);

        switch(choice)
        {
        case 1:
            check_grp();
            break;
        case 2:
            check_mem_grp();
            break;
        default:
            break;
        }
    }while(choice != 0);
}

//查看所加群
void check_grp()
{
    int flag = CHECK_GRP;
    char mes[MAX_CHAR];
    memset(mes, 0, sizeof(mes));
    memset(&grp_info, 0, sizeof(grp_info));
    int i;

    pthread_mutex_lock(&mutex);
    send_pack(flag, user, "server", mes);
    pthread_cond_wait(&cond, &mutex);
    printf("\n-----------群聊列表-----------\n");
    if(grp_info.grp_num == 0)
        printf("暂无加入群聊!\n");
    else{
        for(i = 0; i < grp_info.grp_num; i++){
            printf("%s\n",grp_info.groups[i]);
        }
    }
    pthread_mutex_unlock(&mutex);
}

//查看群中成员
void check_mem_grp()
{
    int flag = CHECK_MEM_GRP;
    char mes[MAX_CHAR];
    int i;

    pthread_mutex_lock(&mutex);
    printf("\n你想要查看那个群中的成员信息:");
    scanf("%s",mes);
    for(i = 0; i < grp_info.grp_num; i++){
        if(strcmp(grp_info.groups[i], mes) == 0)
            break;
    }
    if(i > grp_info.grp_num)
        printf("你没有加入此群!\n");
    else{
        memset(&fri_info, 0, sizeof(fri_info));
        send_pack(flag, user, "server", mes);
        pthread_cond_wait(&cond, &mutex);
        printf("\n-----------%s-----------\n",mes);
        if(fri_info.friends_num == 0)
            printf("该群中暂无成员!\n");
        else
        {
            for(i = 0; i < fri_info.friends_num; i++)
                printf("%s\n", fri_info.friends[i]);
        }
    }
    pthread_mutex_unlock(&mutex);
}

//创建群
void cre_grp()
{
    int flag = CRE_GRP;
    char grp_cre[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要创建的群名称:");
    scanf("%s",grp_cre);
    send_pack(flag, user, "server", grp_cre);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}

//加群
void add_grp()
{
    int flag = ADD_GRP;
    char grp_add[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要加入的群名称:");
    scanf("%s",grp_add);
    send_pack(flag, user, "server", grp_add);
    pthread_mutex_unlock(&mutex);
}

//退群
void out_grp()
{
    int flag = OUT_GRP;
    char grp_out[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要退出的群名称:");
    scanf("%s",grp_out);
    send_pack(flag, user, "server", grp_out);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}

//群管理权限
void power_grp_menu()
{
    int choice;
    do
    {
        printf("-----------------------------\n");
        printf("|         1.解散群          |\n");
        printf("-----------------------------\n");
        printf("|         2.设置管理员      |\n");
        printf("-----------------------------\n");
        printf("|         3.踢人(管)        |\n");
        printf("-----------------------------\n");
        printf("|         0.返回            |\n");
        printf("-----------------------------\n");
        printf("请选择:");
        scanf("%d",&choice);
        
        switch(choice)
        {
        case 1:
            del_grp();
            break;
        case 2:
            set_grp_adm();
            break;           
        case 3:
            kick_grp();
            break;
        default:
            break;
        }
    }while(choice != 0);
}

//解散群
void del_grp()
{
    int flag = DEL_GRP;
    char grp_del[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要解散的群名称:");
    scanf("%s",grp_del);
    send_pack(flag, user, "server", grp_del);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}

//设置管理员
void set_grp_adm()
{
    int flag = SET_GRP_ADM;
    char grp_set_1[MAX_CHAR];
    char grp_set_2[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要在那个群中设置谁为管理员:");
    scanf("%s",grp_set_1);
    scanf("%s",grp_set_2);
    send_pack(flag, user, grp_set_1, grp_set_2);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}

//踢人
void kick_grp()
{
    int flag = KICK_GRP;
    char grp_set_1[MAX_CHAR];
    char grp_set_2[MAX_CHAR];
    pthread_mutex_lock(&mutex);
    printf("你想要在那个群将谁踢出:");
    scanf("%s",grp_set_1);
    scanf("%s",grp_set_2);
    send_pack(flag, user, grp_set_1, grp_set_2);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}


void Menu_chat()
{

    int choice;
    do
    {
        printf("----------------------------\n");
        printf("|         1.私聊            |\n");
        printf("----------------------------\n");
        printf("|         2.群聊            |\n");
        printf("----------------------------\n");
        printf("|         3.聊天记录        |\n");
        printf("----------------------------\n");
        printf("|         0.返回            |\n");
        printf("----------------------------\n");
        printf("请选择:");
        scanf("%d",&choice);

        switch(choice)
        {
        case 1: 
            chat_one(); 
            break;
        case 2:
            chat_many();
            break;
        case 3:
            Menu_message();
            break;
        default:
            break;
        }
    }while(choice != 0);
}

//私聊
void chat_one()
{
    int flag = CHAT_ONE;
    char chat_name[MAX_CHAR];
    char mes[MAX_CHAR];
    int i = 0;
    memset(mes, 0, sizeof(mes));
    memset(&rec_info, 0, sizeof(rec_info));
    rec_info[0].message[0] = '0';
    pthread_mutex_lock(&mutex);
    printf("\n你想要和谁聊天呢? ");
    scanf("%s",chat_name);
    mes[0] = '1';
    send_pack(flag, user, chat_name, mes);
    
    pthread_cond_wait(&cond, &mutex);
    if(signal == 1){
        signal = 0;
        pthread_mutex_unlock(&mutex);
        return;
    }
    printf("\n-----------%s-----------\n",rec_info[i].name2);
    while(rec_info[i].message[0] != '0'){
        printf("%s: %s\n",rec_info[i].name1,rec_info[i].message);
        i++;
    }
    
    printf("\n按q退出聊天\n");
    getchar();
    do
    {
        memset(mes, 0, sizeof(mes));
        printf("%s: ", user);
        scanf("%[^\n]", mes);
        getchar();
        send_pack(flag, user, chat_name, mes);
    }while(strcmp(mes, "q") != 0);

    pthread_mutex_unlock(&mutex);
}


//群聊
void chat_many()
{
    int flag = CHAT_MANY;
    char chat_name[MAX_CHAR];
    char mes[MAX_CHAR];
    int i = 0;
    memset(mes, 0, sizeof(mes));
    memset(&rec_info, 0, sizeof(rec_info));
    rec_info[0].message[0] = '0';
    pthread_mutex_lock(&mutex);
    printf("\n你想要在那个群中聊天呢? ");
    scanf("%s",chat_name);
    mes[0] = '1';
    send_pack(flag, user, chat_name, mes);
    
    pthread_cond_wait(&cond, &mutex);
    if(signal == 1)//群不存在
    {
        signal = 0;
        pthread_mutex_unlock(&mutex);
        return;
    }
    printf("\n-----------%s-----------\n",rec_info[i].name2);
    while(rec_info[i].message[0] != '0')
    {
        printf("%s: %s\n",rec_info[i].name1, rec_info[i].message);
        i++;
    }
    printf("\n按q退出群聊\n");
    getchar();
    do
    {
        memset(mes, 0, sizeof(mes));
        //scanf("%s", mes);
        scanf("%[^\n]", mes);
        getchar();
        send_pack(flag, user, chat_name, mes);
    }while(strcmp(mes, "q") != 0);

    pthread_mutex_unlock(&mutex);
}


 //得到文件大小
int get_file_size(char *send_file_name)
{
    FILE *fd;
    int len;
    if((fd = fopen(send_file_name,"rb")) == NULL){
        printf("\n该文件不存在!\n");
        return -1;
    }
    fseek(fd, 0, SEEK_END);
    len=ftell(fd);
    fclose(fd);
    return len;
}


//发文件
void send_file()
{
    int flag = SEND_FILE;
    int fd;
    int length = 0;
    int sum, n, m = 0;
    char file_name[MAX_CHAR];
    char send_file_name[MAX_CHAR];
    PACK send_file;
    send_file.type = flag;
    printf("你想要给谁发送文件: ");
    scanf("%s", file_name);
    printf("你想要发送的文件名称:");
    scanf("%s",send_file_name);
    sum = get_file_size(send_file_name);
    if(sum == -1){
        pthread_mutex_unlock(&mutex);
        return;
    } 
    printf("总大小:%d\n", sum);
    send_pack(flag, send_file_name, file_name, "send");
    pthread_cond_wait(&cond, &mutex);
    if(signal == 1){
        signal = 0;
        pthread_mutex_unlock(&mutex);
        return;
    }

    strcpy(send_file.data.send_name, user);
    strcpy(send_file.data.recv_name, file_name);
    //printf("总大小:%d\n", sum);
    fd = open(send_file_name, O_RDONLY);
    if(fd == -1)
        printf("没有找到文件:%s\n", send_file_name);
    else{
        while((length = read(fd, send_file.file.mes, MAX_FILE - 1)) > 0){
            send_file.file.size = length;    
            if(send(confd, &send_file, sizeof(PACK), 0) < 0)
                my_err("send",__LINE__);
            
            bzero(send_file.file.mes, MAX_FILE);
            printf("发送中...\n");
        }
    }
    printf("发送成功!\n");
    send_pack(flag, user, file_name, "success");
    close(fd);
}


//接收文件
void recv_file(PACK *recv_pack)
{
    int fd;
    int length;
    char mes[MAX_CHAR * 3 + 1];
    bzero(mes, MAX_CHAR * 3 + 1);
    fd = open(mes_file, O_WRONLY | O_APPEND);
    if(fd == -1)
        printf("未找到文件%s!\n", mes_file);
    if(write(fd, recv_pack->file.mes, recv_pack->file.size) < 0)
        my_err("write", __LINE__);
    printf("\n接收中...\n");
    close(fd);
}


//聊天记录
void Menu_message()
{
    int choice;
    do
    {
        printf("-----------------------------\n");
        printf("|       1.好友聊天记录      |\n");
        printf("-----------------------------\n");
        printf("|       2.群聊记录          |\n");
        printf("-----------------------------\n");
        printf("|       0.返回              |\n");
        printf("-----------------------------\n");
        printf("请选择:");
        scanf("%d",&choice);

        switch(choice)
        {
        case 1:
            check_mes_fri();
            break;
        case 2:
            check_mes_grp();
            break;
        default:
            break;
        }
    }while(choice != 0);
}

//与好友聊天记录
void check_mes_fri()
{
    int i = 0;
    int flag = CHECK_MES_FRI;
    char mes_fri[MAX_CHAR];
    memset(&rec_info, 0, sizeof(rec_info));
    rec_info[0].message[0] = '0';
    pthread_mutex_lock(&mutex);
    printf("\n你想要查看与谁的聊天记录? ");
    scanf("%s",mes_fri);
    send_pack(flag, user, "server", mes_fri);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}

//群组聊天记录
void check_mes_grp()
{
    int i = 0;
    int flag = CHECK_MES_GRP;
    char mes_grp[MAX_CHAR];
    memset(&rec_info, 0, sizeof(rec_info));
    rec_info[0].message[0] = '0';
    pthread_mutex_lock(&mutex);
    printf("\n你想要查看那个群的聊天记录? ");
    scanf("%s",mes_grp);
    send_pack(flag, user, "server", mes_grp);
    pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);
}

// //接收文件


//消息盒子
void Menu_mes_box()
{
    int i;
    char ch[5];
    pthread_mutex_lock(&mutex);
    printf("\n您有%d条消息未读\n", sign);
    for(i = 0; i < sign; i++){
        if(sign_ive[i] == PASSIVE){
            printf("NO.%d: %s", i + 1, mes_box[i]);
            scanf("%s", ch);
            if(mes_box_inc[i] == ADD_GRP)
                send_pack(mes_box_inc[i], grp_name, name[i], ch);
            else
                send_pack(mes_box_inc[i], user, name[i], ch);
        }
        else if(sign_ive[i] == ACTIVE)
            printf("NO.%d: %s\n", i + 1, mes_box[i]);
    }
    sign = 0;
    pthread_mutex_unlock(&mutex);
}

//发包
void send_pack(int type, char *send_name, char *recv_name, char *mes)
{
    PACK pack_send;
    memset(&pack_send, 0, sizeof(PACK));
    pack_send.type = type;
    pack_send.data.recv_fd = confd;
    strcpy(pack_send.data.send_name, send_name);
    strcpy(pack_send.data.recv_name, recv_name);
    strcpy(pack_send.data.mes, mes);
    if(send(confd, &pack_send, sizeof(PACK), 0) < 0)
        my_err("send",__LINE__);
}

四、总结

在写聊天室之前,我只是简单了解了网络与MYSQL的一些API,所以在最开始并没有整体的思路和架构。所以我又在网上看了一些视频加深理解,并且借鉴和学习了其他人的思路和具体实现。随着写的越来越多,我发现一个大的项目,整体思路远比具体细节重要的多,在写好友管理时,我将每个任务分开写,而后发现有很多可以优化的地方,从而重新进行了改进。还有很重要的一点是,写完一个函数一定就要开始测试,而不能等到写了好多再开始,各种各样不同的错误让我根部无法精确定位,浪费了很多时间。在快要写完的现在,我并没有想象中的如释重负,而是发现了很多自己还存在的问题,并且那些额外要求功能都没有实现(但是对于这方面实在没有什么兴趣,以后应该不会完善了吧…)。
最后 。我还是好好学JavaWeb吧!

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 11:23:21  更:2021-09-05 11:24:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 22:53:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码