用select实现基于C/S架构的聊天室

用select实现基于C/S架构的聊天室

1.项目要求

a) 项目需求总体描述
01. 采用Client/Server架构
02. Client A登录聊天服务器前,需要注册自己的ID和密码
03. 注册成功后,Client A就可以通过自己的ID和密码登录聊天服务器
04. 多个Client X同时登录聊天服务器之后,与其他用户进行通讯聊天
05. Client A成功登录后,可以查看当前聊天室内其他在线用户Client X
06. Client A可以选择发送消息给某个特定的Client X,即“悄悄话”功能
07. Client A可以选择发消息全部在线用户,即“群发消息”功能
08. Client A在退出前需要保存聊天记录

b) 项目选择实现功能
01. 添加会员功能;要求会员能够实现以下功能:
a. 会员可以禁言非会员;
b. 会员能够踢人(非会员);
02. 文件传输;
03. 常用语,表情;


2.项目思路

在浏览了以上要求后,我们首先要做的就是好好构思一下,整体的思路,首先我们确定用UDP,TCP,select三种方式中何种方式来实现,由此便牵扯出这三种方式的不同之处:

首先,UDP和TCP非常容易区分,即TCP是通过sockfd来连接的,有点像进程通信的管道通信,首先先需要服务器,客户端双方建立交换数据的专用“通道”进行通信,断开时也需要服务器和客户端同时断开才行。而UDP则不需要服务器和客户机之间相连接,它比较简单,即与TCP相比缺少了connectaccept环节,发送时只是将数据包发出即可;
select和TCP非常像,只是TCP能同时响应多个客户机,而select则是每次能处理一个响应,TCP是通过创建线程的方式处理多个响应,而select由于是通过筛选有变动的fd来响应客户机的,由于这个机制的存在,select便不能够处理多个响应。

这里由于网上通过TCP来实现聊天室的程序有很多,所以笔者选择用select来实现。其实无论是select还是UDP、TCP这些都只是服务器和客户机之间通信略有区别而已,只要能够理解的话,这三种方式都能够很好的实现。

言归正传,既然确定了用select实现的话,我们不妨用笔在纸上粗略的话一下整体思路。

用select实现基于C/S架构的聊天室_第1张图片

用select实现基于C/S架构的聊天室_第2张图片

如图所示,这便是服务器与客户机之间通信实现具体功能的大概步骤;
需要注意的是在进行服务器与客户机通信的时候需要设置好标志位,以及一些细节的处理。
在登录功能中建议用链表实现,主要是链表比较灵活,且大小不需要考虑。


3.具体子系统设计分析

01.注册子系统分析
这部分主要是需要与服务器建立连接,然后进入注册功能接口函数选项,将客户端发送来的消息录入保存到数据库中,然后需要向用户返回是否注册成功;如果失败,则返回注册/登录主菜单界面,重新选择注册选项(可以添加失败原因);

数据库需要提前创建,其实从注册开始,就有了客户机与服务器之间的通信了,所以有关通信部分也需要提前创建,绑定;这些主要可以有三种不同的方式实现,即UDP, TCP 和 select;其中UDP不需要绑定;

02.登录子系统系统分析
首先登录系统一定是已经注册过的用户才可以登录成功,所以先要与服务器建立连接,然后服务器接收客户
端发送过来的登录信息,取出数据库的信息进行匹配,相同登录成功,不同登录失败。登录成功后,进入主菜单选项界面。(可以添加“密码错误”,“忘记密码”进行密码修改等);

03.修改密码分析
是需要一同修改数据库里的值,所以服务器端需要用到update,而登录的话需要服务器端创建一个全局链表来维持在线用户的信息处理,即登录成功后,需要向链表中添加相应的信息;

04.查看聊天室其他用户系统分析
客户端登录成功后,选择私聊/群聊选项,进入私聊接口函数,进入此函数后,客户端需要向服务器发送一
请求附近用户的消息,然后服务器响应,返回已登录好友的信息显示在私聊/群聊的窗口界面;

这个地方主要是需要之前登录时的链表信息;由于所有在线用户的信息都在链表中了,所以只需要通过对链表的访问就可以读取到当前在在线用户的信息了;

05.刷新功能分析
这其实是一个小功能,因为是静态显示,所以需要通过刷新来更新显示的数据;
有2种比较简单的方法可以实现:1.写一个延迟接口delay( ),有一定单片机基础的人都可以非常轻松的写
出来,接下来如果不想要麻烦的话直接定时刷就行,如果想要花哨一点的,就可以通过信号来实现,每当有信号产生,则signal接受该信号,进入handel接口处理收到的信号,这里只需要alarm根据delay定时产生信号,handel中写上刷新函数就行;2.直接在你需要刷新内容前加上通信,即在显示这个信息之前都需要和服务器通信,以获得最新数据;

06.“悄悄话”子系统分析
如果前面的功能都实现了的话这个其实很好写;
这部分主要是逻辑需要清晰,首先主体部分是通信,即从命令行获取数据,发送给服务器,服务器收到信息后,与链表或者数据库进行核实部分数据,确定3件事发送者存在吗?数据合理吗?目标存在吗?这边有与需要向客户机返回服务器处理结果,所以设计大量判断,建议可以用switch使条理更清晰;

07.“群发消息“子系统分析
大致与悄悄话一样,需要改动的就是目标对象,改为服务器在链表中寻找,找到一个,发送一条;

08.保存消息记录分析
即对悄悄话内容和群发消息内容的保存,首先需要在悄悄话部分和群发消息部分调用该接口,获得信息存在
一个结构体中,然后在把这个结构体存入文件中,这里需要用到系统调用中的文件函数或者c库中的文件编程,所以需要选择合适自己的打开文件方式,一个是a+b,一个是r;

09.会员相关功能分析
会员说白了就是一个标志位,需要写入数据库中;
踢人,禁言:
这两个功能一起讲,是因为服务器在处理客户机发来与这两个功能相关的消息时,处理流程大致相同,首先
判断该人是否会员,只有会员才能进行这2项操作;其次,判断禁言踢人对象不能是自己,这一步可能会被忽略,
但是如果忽略的话,可能会导致bug;最后判断禁言踢人对象是否是会员,在线;
不同点:禁言即让目标不能使用悄悄话和群发消息功能;踢人即让目标回到登录界面;

10.文件传输功能分析
顾名思义,即让文件通过服务器,从一个客户机发送,再由另一个客户机接受;首先a客户机打开文件,读
取内容到结构体中,发给服务器,服务器接收文件,转发给b客户机。这是一个大概流程;
这里,需要思考一件事:你传输的文件是多大?如果很小的话一次就能传输结束了。如果比较大的话,就要分多次传输了。所以接受方打开文件方式就是a+b,那么问题来了,如果a连续传输了2个一样的文件给b的话,该文件是不是在b那边同名文件下写了2次;为了避免这个问题,我们需要在接受文件之前判断一下,先得到文件名,查找本地是否存在,不存在以a+b方式直接接收;存在则询问接收方是否覆盖?否,回到上一级菜单,是的话则以w方式接收;这样之前的问题就得到了很好的解决了。

11.删除聊天记录文件
调用remove就行;

12.退出
记得双方断开sockfd( UDP 无视),和pthread_t tid;


4.代码展示

头文件

#ifndef _CHAT_H_
#define _CHAT_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define PORT    8888

#define SUCCESS 10000
#define FAILURE 10001
#define ERROR   10002
#define FAULT   10003
#define YES     10004
#define NO      10005

#define LOGO    1                       //登录
#define SIGN    2                       //注册
#define FORGET  3                       //忘记密码
#define QUIT    4                       //退出

#define SHOW    5                       //显示在线昵称
#define PCHAT   6                       //私聊
#define SHOWNUM 7                       //显示在线人数
#define GCHAT   8                       //群聊
#define BACK    9                       //注销
#define CHANGE  10                      //修改密码
#define GETNICK 11                      //获得当前昵称
#define MEMBER  12                      //会员
#define CLOSE   13                      //禁言
#define DOWN    14                      //踢人
#define GIVE    15                      //传输文件


struct data
{
    int  id;                            //帐号
    char pswd[20];                      //密码
    char nickname[20];                  //昵称
    char sex;                           //性别
    char phone[20];                     //手机号
    int flag;                           //判断标志位
    char message[200];                  //消息
    char fromname[20];                  //发送人
    char toname[20];                    //接受人
    int num;                            //在线人数
    int endflag;                        //结束标志位
    int time_year;                      //年
    int time_mon;                       //月
    int time_mday;                      //日
    int time_hour;                      //时
    int time_min;                       //分
    int time_sec;                       //秒
};
typedef struct data DATA;

struct trans
{
    char text[4096];                    //文件传送
    char filename[64];                  //文件名
    char fromname[20];                  //发送人
    char toname[20];                    //接收人
    int flag;                           //判断标志位
    int endflag;                        //文件结束标志
};
typedef struct trans TRAN;

struct status
{
    int id;                             //帐号
    int fd;                             //sockfd
    char nickname[20];                  //昵称
    int member_flag;                    //会员 0不是 1是会员
    int nospeak;                        //禁言 0   1禁
    struct status * next;
};
typedef struct status Status;
typedef Status *STATUS;

/*********************************************************服务器****************************************************/

void server_logo(int aim, DATA RecvBuf);
void server_sign(int aim, DATA RecvBuf);
int compare(void *para, int columnCount, char **columnValue, char **columnName);
void server_forget(int aim, DATA RecvBuf);
int getpswd(void *para, int columnCount, char **columnValue, char **columnName);
void server_quit(int aim);

void server_show(int aim);
void server_pchat(int aim, DATA RecvBuf);
void server_gchat(int aim, DATA RecvBuf);
void server_back(int aim);
void server_change(int aim, DATA RecvBuf);
int find(void *para, int columnCount, char **columnValue, char **columnName);
//void server_give(int aim, TRAN RecvBuf);

/*********************************************************客户端****************************************************/

void show_welcome();
void client_sign(int sockfd);
void show_sign();
int client_logo(int sockfd);
void show_logo();
void client_forget(int sockfd);
void show_forget();
void client_quit(int sockfd);
void show_quit();

void show_load();
void show_menu();
void *client_menu(void *arg);
void *Recv(void *arg);
void show_people(int sockfd);
void private_chat(int sockfd);
void group_chat(int sockfd);
void change_pswd(int sockfd);
void client_back(int sockfd);
void client_change(int sockfd);
void handel(int sig);
void delay();


void show_time();
void save_message(DATA *s);
void client_read();
void read_pchat();
void read_gchat();
void client_member(int sockfd);
void client_close(int sockfd);
void client_down(int sockfd);
//void clent_transform(int sockfd);
//void client_receive(TRAN RecvBuf);


#endif

服务器

#include "chat.c"

sqlite3 *ppdb;
STATUS sta;
char sql[200];

int main()
{
    int ret;
    int m, n,  temp;
/************************************************链表初始化******************************************/

    sta = (STATUS)malloc(sizeof(Status));
    sta->next = NULL;

/************************************************sqlite3**********************************************/

    ret = sqlite3_open("userdata.db", &ppdb);
    if(ret != SQLITE_OK)
    {
        perror("sqlite3_open");
        exit(1);
    }

    memset(&sql, 0, sizeof(sql));
    sprintf(sql, "create table if not exists userdata (id integer primary key, pswd text, nickname text, sex text, phone text, member integer);");
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if(ret != SQLITE_OK)
    {
        perror("sqlite3_open");
        exit(1);
    }

/***********************************************select************************************************/

    int sockfd, fd[100] = {0}, i = 0, length, j;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    fd_set ReadFd, TmpFd;
    int MaxFd;
    DATA RecvBuf = {0};

    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        perror("socket");
        exit(1);
    }

    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = PF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if(ret < 0)
    {
        perror("bind");
        exit(1);
    }

    printf("等待客户端连接...\n");
    ret = listen(sockfd, 1);
    if(ret < 0)
    {
        perror("listen");
        exit(1);
    }

    FD_ZERO(&ReadFd);
    FD_ZERO(&TmpFd);
    FD_SET(sockfd, &ReadFd);
    MaxFd = sockfd;

    while(1)
    {
        TmpFd = ReadFd;
        ret = select(MaxFd + 1, &TmpFd, NULL, NULL, NULL);
        if(-1 == ret)
        {
            perror("select");
            exit(1);
        }

        if(FD_ISSET(sockfd, &TmpFd))
        {
            length = sizeof(client_addr);
            fd[i] = accept(sockfd, (struct sockaddr *)&client_addr, &length);
            if(fd[i] < 0)
            {
                perror("accept");
                exit(1);
            }

            printf("fd:%d\t端口号:%d\n", fd[i], client_addr.sin_port);

            for(m = 0; m < i; m++)
            {
                for(n = 0; n < i - m; n++)
                {
                    if(fd[m] > fd[m+1])
                    {
                        temp = fd[m];
                        fd[m] = fd[m+1];
                        fd[m+1] = temp;
                    }
                }
            }

            FD_SET(fd[i], &ReadFd);
            MaxFd = fd[i];
            i++;
        }
        else
        {
            for(j = 0; j < i; j++)
            {
                if(FD_ISSET(fd[j], &TmpFd))
                {
                    memset(&RecvBuf, 0, sizeof(RecvBuf));
                    ret = recv(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
                    if(ret < 0)
                    {
                        perror("recv");
                        exit(1);
                    }

                    printf("flag:%d nickname:%s message:%s\n", RecvBuf.flag, RecvBuf.nickname, RecvBuf.message);
                    switch (RecvBuf.flag)
                    {
                        case LOGO:
                            server_logo(fd[j], RecvBuf);
                            break;
                        case SIGN:
                            server_sign(fd[j], RecvBuf);
                            break;
                        case FORGET:
                            server_forget(fd[j], RecvBuf);
                            break;
                        case QUIT:
                            close(fd[j]);
                            FD_CLR(fd[j], &ReadFd);
                            break;
                        case SHOW:
                            server_show(fd[j]);
                            break;
                        case PCHAT:
                            server_pchat(fd[j], RecvBuf);
                            break;
                        case GCHAT:
                            server_gchat(fd[j], RecvBuf);
                            break;
                        case BACK:
                            server_back(fd[j]);
                            break;
                        case CHANGE:
                            server_change(fd[j], RecvBuf);
                            break;
                        case MEMBER:
                            server_member(fd[j], RecvBuf);
                            break;
                        case CLOSE:
                            server_close(fd[j], RecvBuf);
                            break;
                        case DOWN:
                            server_down(fd[j], RecvBuf);
                            break;
/*                      case GIVE:
                            server_give(fd[j], RecvBuf);
                            break;*/
                        default:
                            break;
                    }
                    break;
                }
            }
        }
    }

    return 0;
}

客户机

#include "chat.c"

pthread_t tid[2] = {0};
int sign = 0;
int cfd;

int main()
{
/***********************************************屏蔽kill sign*****************************************/

    signal(SIGINT, handel);

/***********************************************连接服务器*******************************************/

    int sockfd, ret;
    struct sockaddr_in server_addr;

    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = PF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    printf("正在连接服务器....\n");
    ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if(-1 == ret)
    {
        perror("connect");
        exit(1);
    }

    cfd = sockfd;
/*************************************************登录界面********************************************/

    char choice[10];

    while(1)
    {
        sign = 0;
        memset(&choice, 0, sizeof(choice));
        system("clear");
        show_welcome();
        scanf("%s", choice);

        switch(atoi(&choice[0]))
        {
            case 1:
                ret = 0;
                ret = client_logo(sockfd);
                if(ret  == SUCCESS)
                {
                    system("clear");
                    show_load();
                    sleep(1);

                    ret = pthread_create(&tid[0], NULL, client_menu, (void *)&sockfd);
                    if(0 != ret)
                    {
                        perror("pthread_create1");
                        exit(1);
                    }

                    ret = pthread_create(&tid[1], NULL, Recv, (void *)&sockfd);
                    if(0 != ret)
                    {
                        perror("pthread_create2");
                        exit(1);
                    }

                    pthread_join(tid[0], NULL);
                    pthread_join(tid[1], NULL);
                }
                break;
            case 2:
                client_sign(sockfd);
                break;
            case 3:
                client_forget(sockfd);
                break;
            case 4:
                client_quit(sockfd);
                close(sockfd);
                show_quit();
                exit(1);
            default:
                printf("请重输:\n");
                break;
        }
        if(sign == 2)
        {
            client_quit(sockfd);
            close(sockfd);
            show_quit();
            exit(1);
        }
    }

    return 0;
}

服务器接口

#include "chat.c"

extern char sql[200];
extern sqlite3 *ppdb;
extern STATUS sta;

int count;  
char nname[20];                 //登录时保存昵称,修改密码保存昵称
char psnum[20];                 //忘记密码保存密码
int aim_a;                      //记录目标fd
int member_flag;                //会员标志

/****************************************************注册***********************************************/

void server_sign(int aim, DATA RecvBuf)
{
    int ret;
    memset(&sql,0, sizeof(sql));
    sprintf(sql, "insert into userdata (id, pswd, nickname, sex, phone, member) values (%d, '%s', '%s', '%c', '%s', 0);", RecvBuf.id, RecvBuf.pswd, RecvBuf.nickname, RecvBuf.sex, RecvBuf.phone);

    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if(ret != SQLITE_OK)
    {
        DATA SendBuf;
        memset(&SendBuf, 0, sizeof(SendBuf));
        SendBuf.flag = FAILURE;
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
    else
    {
        DATA SendBuf;
        memset(&SendBuf, 0, sizeof(SendBuf));
        SendBuf.flag = SUCCESS;
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
}

/****************************************************登录**********************************************/

void server_logo(int aim, DATA RecvBuf)
{
    member_flag = 0;
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    count = 0;
    int ret;
    memset(&sql, 0, sizeof(sql));
    sprintf(sql, "select * from userdata;");
    ret = sqlite3_exec(ppdb, sql, compare, (void *)&RecvBuf, NULL);
    if(ret != SQLITE_OK)
    {
        perror("sqlite3_exec");
        exit(1);
    }

    if(count == 1)
    {
        STATUS tmp = sta;
        STATUS p = sta->next;
        while(p)
        {
            if(p->id == RecvBuf.id)
            {
                SendBuf.flag = FAILURE;                                 //用户已在线
                ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
                if(-1 == ret)
                {
                    perror("send");
                    exit(1);
                }

                return;
            }
            tmp = p;
            p = p->next;
        }

        SendBuf.flag = SUCCESS;                                         //登录成功
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }

        STATUS n = (STATUS)malloc(sizeof(Status));
        if(NULL == n)
        {
            perror("malloc");
            exit(1);
        }
        n->id = RecvBuf.id;
        n->fd = aim;
        n->member_flag = member_flag;
        strcpy(n->nickname, nname);
        tmp->next = n;
        n->next = NULL;

        return;
    }
    else if(count == 2)
    {
        SendBuf.flag = ERROR;                                           //密码错误
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }

        return;
    }
    else
    {
        SendBuf.flag = FAULT;                                           //用户未注册
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }

        return;
    }
}

int compare(void *para, int columnCount, char **columnValue, char **columnName)
{
    int ret, j;
    if((*(((int **)columnValue)[0]) - 48) == ((*(DATA *)para).id))
    {
        if(!strcmp(columnValue[1], ((*(DATA *)para).pswd)))
        {
            memset(&nname, 0, sizeof(nname));
            strcpy(nname, columnValue[2]);
            member_flag = ((*(((int **)columnValue)[5])) - 48);
            count = 1;                              //密码帐号正确,但需要印证是否在线
            return 0;
        }
        else
        {
            count = 2;                              //密码错误
            return 0;
        }
    }
    return 0;
}

/**************************************************忘记密码*************************************************/

void server_forget(int aim, DATA RecvBuf)
{
    count = 0;
    int ret;
    memset(&sql, 0, sizeof(sql));
    sprintf(sql, "select * from userdata;");
    ret = sqlite3_exec(ppdb, sql, getpswd, (void *)&RecvBuf, NULL);
    if(ret != SQLITE_OK)
    {
        perror("sqlite3_exec");
        exit(1);
    }

    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    if(1 == count)
    {
        SendBuf.flag = FAILURE;                             //用户已上线
    }
    else if(2 == count)
    {
        SendBuf.flag = SUCCESS;                             //查找成功
        strcpy(SendBuf.pswd, psnum);
    }
    else
    {
        SendBuf.flag = ERROR;                               //用户未注册
    }

    ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
    return;
}

int getpswd(void *para, int columnCount, char **columnValue, char **columnName)
{
    printf("in\n");
    int ret, j;
    if(((*(columnValue[0]) - 48) == (*(DATA *)para).id) && (!strcmp(columnValue[2], ((*(DATA *)para).nickname))) && (*(columnValue[3]) == (*(DATA *)para).sex) && (!strcmp(columnValue[4], ((*(DATA *)para).phone))))
    {
        STATUS p;
        p = sta->next;
        while(p)
        {
            if(p->id == (*(DATA *)para).id)
            {
                count = 1;
                return 0;
            }
            p = p->next;
        }

        memset(&psnum, 0, sizeof(psnum));
        strcpy(psnum, columnValue[1]);
        count = 2;
        return 0;
    }
    return 0;
}

/***********************************************显示在线人昵称************************************************/

void server_show(int aim)
{
    int ret, num = 0;

    STATUS p = sta->next;
    while(p)
    {
        num++;
        p = p->next;
    }

    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    SendBuf.flag = SHOWNUM;
    SendBuf.num = num;
    ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }

    p = sta->next;
    while(p)
    {
        if(p->next == NULL)
        {
            memset(&SendBuf, 0, sizeof(SendBuf));
            SendBuf.flag = SHOW;
            SendBuf.endflag = YES;
            strcpy(SendBuf.nickname, p->nickname);
            ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
            if(-1 == ret)
            {
                perror("send");
                exit(1);    
            }

        }
        else
        {
            memset(&SendBuf, 0, sizeof(SendBuf));
            SendBuf.flag = SHOW;
            SendBuf.endflag = NO;
            strcpy(SendBuf.nickname, p->nickname);
            ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
            if(-1 == ret)
            {
                perror("send");
                exit(1);    
            }
        }

        p = p->next;
    }

    DATA RecvBuf;
    p = sta->next;
    while(p)
    {
        if(aim == p->fd)
        {
            strcpy(RecvBuf.fromname, p->nickname);
            break;
        }
        p = p->next;
    }

    RecvBuf.flag = GETNICK;
    ret = send(aim, &RecvBuf, sizeof(RecvBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
    return;
}

/***************************************************私聊*****************************************************/

void server_pchat(int aim, DATA RecvBuf)
{
    int ret;
    aim_a = 0;
    char fromname[20] = {0};
    STATUS p = sta->next;
    while(p)
    {
        if(p->fd == aim && p->nospeak == 1)
        {
            DATA SendBuf;
            memset(&SendBuf, 0, sizeof(SendBuf));
            SendBuf.flag = PCHAT;
            SendBuf.endflag = FAILURE;
            ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
            if(-1 == ret)
            {
                perror("send");
                exit(1);
            }
            return;
        }
        p = p->next;
    }
    p = sta->next;
    while(p)
    {
        if(!strcmp(p->nickname, RecvBuf.nickname))
        {
            aim_a = p->fd;
            break;
        }
        p = p->next;
    }
    if(0 == aim_a)
    {
        RecvBuf.flag = PCHAT;
        RecvBuf.endflag = NO;
        ret = send(aim, &RecvBuf, sizeof(RecvBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
        return;
    }
    else if(aim == aim_a)
    {
        RecvBuf.flag = PCHAT;
        RecvBuf.endflag = FAULT;
        ret = send(aim, &RecvBuf, sizeof(RecvBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
        return;
    }
    else
    {
        p = sta->next;
        while(p)
        {
            if(aim == p->fd)
            {
                strcpy(RecvBuf.fromname, p->nickname);
                RecvBuf.flag = PCHAT;
                RecvBuf.endflag = YES;
                printf("name:%s, endflag:%d,  message:%s\n", RecvBuf.nickname, RecvBuf.endflag, RecvBuf.message);
                ret = send(aim_a, &RecvBuf, sizeof(RecvBuf), 0);
                if(-1 == ret)
                {
                    perror("send");
                    exit(1);
                }
                return;
            }
            p = p->next;
        }
        return;
    }
}

/****************************************************群聊****************************************************/

void server_gchat(int aim, DATA RecvBuf)
{
    int ret;
    char fromname[20] = {0};
    aim_a = 0;
    STATUS p = sta->next;
    while(p)
    {
        if(p->fd == aim && p->nospeak == 1)
        {
            DATA SendBuf;
            memset(&SendBuf, 0, sizeof(SendBuf));
            SendBuf.flag = GCHAT;
            SendBuf.endflag = FAILURE;
            ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
            if(-1 == ret)
            {
                perror("send");
                exit(1);
            }
            return;
        }
        p = p->next;
    }

    p = sta->next;
    while(p)
    {
        if(p->fd == aim)
        {
            strcpy(fromname, p->nickname);
        }
        p = p->next;
    }

    p = sta->next;
    while(p)
    {
        if(aim != p->fd)
        {
            aim_a = p->fd;
            RecvBuf.flag = GCHAT;
            strcpy(RecvBuf.fromname, fromname);
            ret = send(aim_a, &RecvBuf, sizeof(RecvBuf), 0);
            if(-1 == ret)
            {
                perror("send");
                exit(1);
            }
        }
        p = p->next;
    }
    if(aim_a == 0)
    {
        RecvBuf.flag = ERROR;
        ret = send(aim, &RecvBuf, sizeof(RecvBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }

    return;
}

/*************************************************注销**********************************************/

void server_back(int aim)
{
    STATUS p = sta->next;
    STATUS tmp = sta;

    while(p)
    {
        if(p->fd == aim)
        {
            if(p->next == NULL)
            {
                tmp->next = NULL;
                free(p);
                return;
            }
            else
            {
                tmp->next = p->next;
                free(p);
                p->next = NULL;
                return;
            }
        }
        tmp = p;
        p = p->next;
    }
}

/**************************************************修改密码**********************************************/

void server_change(int aim, DATA RecvBuf)
{
    int ret;
    count = 0;
    memset(&nname, 0, sizeof(nname));
    STATUS p = sta->next;
    while(p)
    {
        if(p->fd == aim)
        {
            memset(&nname, 0, sizeof(nname));
            strcpy(nname, p->nickname);
        }
        p= p->next;
    }

    memset(&sql, 0, sizeof(sql));
    sprintf(sql, "select * from userdata;");
    ret = sqlite3_exec(ppdb, sql, find, (void *)&RecvBuf, NULL);
    if(ret != SQLITE_OK)
    {
        perror("sqlite3_exec");
        exit(1);
    }

    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    SendBuf.flag = CHANGE;

    if(0 == count)
    {
        SendBuf.endflag = FAILURE;                          //旧密码错误
    }
    else if(1 == count)
    {
        memset(&sql, 0, sizeof(sql));
        sprintf(sql, "update userdata set pswd = '%s' where nickname = '%s';", RecvBuf.message, nname);
        ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
        if(ret != SQLITE_OK)
        {
            perror("sqlite3_exec");
            exit(1);
        }

        SendBuf.endflag = SUCCESS;                          //修改密码成功
    }
    ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }

    return;
}

int find(void *para, int columnCount, char **columnValue, char **columnName)
{
    int ret;
    if((!strcmp(columnValue[1], (*(DATA *)para).pswd)) && ((!strcmp(columnValue[2], nname))))
    {
        count = 1;
        return 0;
    }

    return 0;
}

/*******************************************会员************************************/

void server_member(int aim, DATA RecvBuf)
{

    int ret;
    count = 0;

    memset(&nname, 0, sizeof(nname));
    STATUS p = sta->next;
    while(p)
    {
        if(p->fd == aim)
        {
            if(p->member_flag == 0)
            {
                p->member_flag = 1;
                memset(&nname, 0, sizeof(nname));
                strcpy(nname, p->nickname);
                count = 1;
                break;
            }
            else
            {
                count = 2;
                break;
            }
        }
        p= p->next;
    }

    printf("name:%s\n", nname);

    DATA SendBuf;
    bzero(&SendBuf, sizeof(SendBuf));
    if(1 == count)
    {
        memset(&sql, 0, sizeof(sql));
        sprintf(sql, "update userdata set member = 1 where nickname = '%s';", nname);
        ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
        if(ret != SQLITE_OK)
        {
            perror("sqlite3_exec");
            exit(1);
        }

        SendBuf.flag = MEMBER;
        SendBuf.endflag = SUCCESS;
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
    else if(2 == count)
    {
        SendBuf.flag = MEMBER;
        SendBuf.endflag = YES;
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
    else if(0 == count)
    {
        SendBuf.flag = MEMBER;
        SendBuf.endflag = FAILURE;
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
    return;
}


/******************************************禁言*****************************************/

void server_close(int aim, DATA RecvBuf)
{
    aim_a = 0;
    int ret;
    count = 0;
    STATUS p = sta->next;
    while(p)
    {
        if(p->fd == aim && p->member_flag == 0)
        {
            DATA SendBuf;
            memset(&SendBuf, 0, sizeof(SendBuf));
            SendBuf.flag = CLOSE;
            SendBuf.endflag = ERROR;
            ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
            if(-1 == ret)
            {
                perror("send");
                exit(1);
            }
            return;
        }
        p = p->next;
    }

    p = sta->next;
    while(p)
    {
        if(!strcmp(p->nickname, RecvBuf.nickname))
        {
            if(p->fd == aim)
            {
                count = 3;
                break;
            }
            else
            {
                if(p->member_flag != 1)
                {
                    p->nospeak = 1;
                    aim_a = p->fd;
                    count = 1;
                    break;
                }
                else
                {
                    count = 2;
                    break;
                }
            }       
        }
        p= p->next;
    }

    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    if(0 == count)
    {
        SendBuf.flag = CLOSE;
        SendBuf.endflag= FAILURE;
    }
    else if(1 == count)
    {
        SendBuf.flag = CLOSE;
        SendBuf.endflag  = SUCCESS;

        DATA ToBuf;
        ToBuf.flag = CLOSE;
        ToBuf.endflag = YES;
        ret = send(aim_a, &ToBuf, sizeof(ToBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
    else if(2 == count)
    {
        SendBuf.flag = CLOSE;
        SendBuf.endflag = FAULT;
    }
    else if(3 == count)
    {
        SendBuf.flag = CLOSE;
        SendBuf.endflag = NO;
    }
    ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
    if(ret == -1)
    {
        perror("send");
        exit(1);
    }
}

/**************************************************踢人***************************************/

void server_down(int aim, DATA RecvBuf)
{
    count = 0;
    aim_a = 0;
    DATA SendBuf;
    bzero(&SendBuf, sizeof(SendBuf));
    int ret;
    STATUS p = sta->next;
    while(p)
    {
        if(p->fd == aim)
        {
            if(p->member_flag != 1)
            {
                count = 1;
            }
            break;
        }
        p = p->next;
    }

    p = sta->next;
    while(p)
    {
        if(!strcmp(p->nickname, RecvBuf.nickname))
        {
            if(p->fd == aim)
            {
                count = 3;
                break;
            }
            else
            {
                if(p->member_flag == 1)
                {
                    count = 2;
                    break;
                }
                else
                {
                    aim_a = p->fd;
                    count = 4;
                    break;
                }

            }
        }
        p = p->next;
    }

    if(1 == count)
    {
        SendBuf.flag = DOWN;
        SendBuf.endflag = FAILURE;
    }
    else if(2 == count)
    {
        SendBuf.flag = DOWN;
        SendBuf.endflag = ERROR;
    }
    else if(3 == count)
    {
        SendBuf.flag = DOWN;
        SendBuf.endflag = NO;
    }
    else if(4 == count)
    {
        SendBuf.flag = DOWN;
        SendBuf.endflag = SUCCESS;

        DATA ToBuf;
        bzero(&ToBuf, sizeof(ToBuf));
        ToBuf.flag = DOWN;
        ToBuf.endflag = YES;
        ret = send(aim_a, &ToBuf, sizeof(ToBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }

    ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
    return;
}

/*************************************************文件传输****************************************/

void server_give(int aim, DATA RecvBuf)
{
    int ret;
    aim_a = 0;
    STATUS p = sta->next;
    while(p)
    {
        if(!strcmp(RecvBuf.toname, p->nickname))
        {
            aim_a = p->fd;
            break;
        }
        p = p->next;
    }

    DATA SendBuf;
    bzero(&SendBuf, sizeof(SendBuf));
    if(0 == aim_a)
    {
        SendBuf.flag = GIVE;
        SendBuf.endflag = FAILURE;
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }

    }
    else if(aim == aim_a)
    {
        SendBuf.flag = GIVE;
        SendBuf.endflag = ERROR;
        ret = send(aim, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
    else
    {
        RecvBuf.flag = GIVE;
        RecvBuf.endflag = YES;
        ret = send(aim_a, &RecvBuf, sizeof(RecvBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }

        bzero(&SendBuf, sizeof(SendBuf));
        RecvBuf.flag = GIVE;
        RecvBuf.endflag = OK;
        ret = send(aim, &RecvBuf, sizeof(RecvBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
}

客户机接口

#include "chat.c"

extern pthread_t tid[2];
extern int sign;
extern int cfd;

char my_nickname[20];


void show_welcome()
{
    printf("\n\n\n\n\n\t\t\t\t\t欢迎来到聊天室!\n");
    printf("\t\t\t\t      WELCOME TO CHAT ROOM\n");
    printf("\n\n\t\t1. 登录\n");
    printf("\n\t\t2. 注册\n");
    printf("\n\t\t3. 忘记密码\n");
    printf("\n\t\t4. 退出\n");
    printf("\n\n\n\t请输入您的选择:\n");
}



/*****************************************注册****************************************/

void show_sign()
{
    printf("\n\n\n\n\n\t\t\t\t\t注册帐号\n\n\n");
    printf("\t\t请输入您的帐号:\n\n");
    printf("\t\t请输入您的密码:\n\n");
    printf("\t\t请输入您的昵称:\n\n");
    printf("\t\t请输入您的性别(帅哥m,美女f):\n\n");
    printf("\t\t请输入您的手机号码:\n\n");
}

void client_sign(int sockfd)
{
    int ret;
    system("clear");
    show_sign();
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    scanf("%d %s %s %c %s", &SendBuf.id, SendBuf.pswd, SendBuf.nickname, &SendBuf.sex, SendBuf.phone);
    SendBuf.flag = SIGN;

    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }

    DATA RecvBuf;
    memset(&RecvBuf, 0, sizeof(RecvBuf));
    ret = recv(sockfd, &RecvBuf, sizeof(RecvBuf), 0);
    if(-1 == ret)
    {
        perror("recv");
        exit(1);
    }

    if(RecvBuf.flag == FAILURE)
    {
        printf("\n\t\t\t注册失败,该用户已存在!\n\n");
        sleep(1);
    }
    else if(RecvBuf.flag == SUCCESS)
    {
        system("clear");
        printf("\n\n\n\n\t注册中...\n");
        system("clear");
        printf("\n\n\n\n\t注册成功!\n\n");
    }
}

/***********************************************登录******************************************/

void show_logo()
{
    printf("\n\n\n\n\n\t\t\t\t\t登录帐号\n\n\n");
    printf("\t\t请输入您的帐号:\n\n");
    printf("\t\t请输入您的密码:\n\n");
}

int client_logo(int sockfd)
{
    int ret;
    system("clear");
    show_logo();
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    scanf("%d %s", &SendBuf.id, SendBuf.pswd);
    SendBuf.flag = LOGO;

    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }

    DATA RecvBuf;
    memset(&RecvBuf, 0, sizeof(RecvBuf));
    ret = recv(sockfd, &RecvBuf, sizeof(RecvBuf), 0);
    if(-1 == ret)
    {
        perror("recv");
        exit(1);
    }

    if(RecvBuf.flag == SUCCESS)
    {
        system("clear");
        printf("\n\n\n\n\t登录中...\n");
        sleep(1);
        return SUCCESS;
    }
    else if(RecvBuf.flag == FAILURE)
    {
        printf("登录失败,该用户已上线!\n");
        sleep(1);
    }
    else if(RecvBuf.flag == ERROR)
    {
        printf("登录失败,密码不正确!\n");
        sleep(1);
    }
    else if(RecvBuf.flag == FAULT)
    {
        printf("登录失败,用户未注册!\n");
        sleep(1);
    }
    return FAILURE;
}

/*********************************************忘记密码********************************************/

void show_forget()
{
    printf("\n\n\n\n\n\t\t\t\t\t忘记密码\n\n\n");
    printf("\t\t请输入您的帐号:\n\n");
    printf("\t\t请输入您的昵称:\n\n");
    printf("\t\t请输入您的性别(帅哥m,美女f):\n\n");
    printf("\t\t请输入您的手机号码:\n\n");
}

void client_forget(int sockfd)
{
    char choice[20];
    int ret;
    system("clear");
    show_forget();
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    scanf("%d %s %c %s", &SendBuf.id, SendBuf.nickname, &SendBuf.sex, SendBuf.phone);
    SendBuf.flag = FORGET;

    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }

    DATA RecvBuf;
    memset(&RecvBuf, 0, sizeof(RecvBuf));
    ret = recv(sockfd, &RecvBuf, sizeof(RecvBuf), 0);
    if(-1 == ret)
    {
        perror("recv");
        exit(1);
    }

    if(RecvBuf.flag == SUCCESS)
    {
        system("clear");
        printf("\n\n\n\n\n密码找回中:\n\n");
        sleep(1);
        printf("该用户的密码是: %s\n", RecvBuf.pswd);
        while(1)
        {
            printf("请输入yes,进行下一步:\n");
            scanf("%s", choice);
            if(!strcmp(choice, "yes"))
            {
                break;
            }
        }
    }
    else if(RecvBuf.flag == FAILURE)
    {
        printf("该用户已上线!\n");
        sleep(1);
    }
    else if(RecvBuf.flag == ERROR)
    {
        printf("该用户未注册!\n");
        sleep(1);
    }
    return;
}

/***************************************************退出*************************************************/

void client_quit(int sockfd)
{
    int ret;
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    SendBuf.flag = QUIT;
    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }

    return;
}

void show_quit()
{
    system("clear");
    printf("\n\n\n\n\n\n\n\n");
    printf("                                                                                     =============================================\n");
    printf("                                                                                                  执剑天涯,有缘再见!\n");
    printf("                                                                                     =============================================\n");
    sleep(1);
    system("clear");
}

/**************************************************LOADING**************************************************/

void show_load()
{
    printf("\n\n\n\n\t登录成功!\n\n\n\n\n\n\n");
    sleep(1);
    printf("                                                                                     =============================================\n");
    printf("                                                                                                       载入中...\n");
    printf("                                                                                     =============================================\n");
}

/************************************************客户端菜单*************************************************/

void show_menu()
{
    show_time();
    printf("\n\n\t\t\t\t\t\t主菜单MAIN MENU\n");
    printf("\n\n\t\t1. 私聊\t\t\t2. 群聊\n\n");
    printf("\t\t3. 修改密码\t\t4. 刷新\n\n");
    printf("\t\t5. 查询消息记录\t\t6. 会员充值\n\n");
    printf("\t\t7. 禁言\t\t\t8. 踢人\n\n");
    printf("\t\t9. 注销\t\t\t10 .退出\n\n");
    printf("\t\t11. 文件传输\n\n");
}

void *client_menu(void *arg)
{
    bzero(&my_nickname, sizeof(my_nickname));
    sign = 5;
    char choice[10] = {0};

    system("clear");
    while(1)
    {
        system("clear");
        memset(&choice, 0, sizeof(choice));
        show_menu();
        show_people(*(int *)arg);
        printf("\n\n请输入您的选择:\n");

        scanf("%s", choice);
        switch(atoi(&choice[0]))
        {
            case 1:
                private_chat(*(int *)arg);
                break;
            case 2:
                group_chat(*(int *)arg);
                break;
            case 3:
                change_pswd(*(int *)arg);
                break;
            case 4:
                break;
            case 5:
                client_read();
                break;
            case 6:
                client_member(*(int *)arg);
                break;
            case 7:
                client_close(*(int *)arg);
                break;
            case 8:
                client_down(*(int *)arg);
                break;
            case 9:
                client_back(*(int *)arg);
                sign = 1;
                break;
            case 10:
                client_back(*(int *)arg);
                sign = 2;
                break;
            case 11:
                client_transform(*(int *)arg);
                break;
            default:
                printf("请重输:\n");
                break;
        }

        if(1 == sign || 2 == sign)
        {
            pthread_cancel(tid[1]);
            return;
        }
    }
}



/************************************************接受消息**************************************************/

void *Recv(void *arg)
{
    static recv_count;
    int ret, oldtype;
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);

    DATA RecvBuf;
    while(1)
    {
        memset(&RecvBuf, 0, sizeof(RecvBuf));
        ret = recv(*(int *)arg, &RecvBuf, sizeof(RecvBuf), 0);
        if(-1 == ret)
        {
            perror("recv");
            exit(1);
        }

    //  printf("flag:%d, endflag:%d, nickname:%s, message:%s\n", RecvBuf.flag, RecvBuf.endflag, RecvBuf.nickname, RecvBuf.message);
        if(RecvBuf.flag == PCHAT)
        {
            if(RecvBuf.endflag == FAILURE)
            {
                delay();
                printf("消息发送失败,您已被禁言!\n");
            }
            else if(RecvBuf.endflag == NO)
            {
                delay();
                printf("\n\t消息发送失败,目标用户不在线!\n");
            }
            else if(RecvBuf.endflag == FAULT)
            {
                delay();
                printf("\n\t消息发送失败,用户不能发消息给自己!\n");
            }
            else if(RecvBuf.endflag == YES)
            {
                printf("\n\n\n\t您有新消息!\n");
                printf("\t\t%s对您说%s\n\n\n", RecvBuf.fromname, RecvBuf.message);
                strcpy(RecvBuf.nickname, my_nickname);
                save_message(&RecvBuf);
            }
        }
        else if(RecvBuf.flag == GCHAT)
        {
            if(RecvBuf.endflag == FAILURE)
            {
                delay();
                printf("消息发送失败,您已被禁言!\n");
            }
            else
            {
                printf("\n\n\n\t您有新的群消息!\n");
                printf("\t\t%s对您说:%s\n\n\n", RecvBuf.fromname, RecvBuf.message);
                strcpy(RecvBuf.toname, RecvBuf.fromname);
                strcpy(RecvBuf.fromname, "all");
                strcpy(RecvBuf.nickname, my_nickname);
                save_message(&RecvBuf);
            }
        }
        else if(RecvBuf.flag == ERROR)
        {
            delay();
            printf("\n\t消息发送失败,当前只有您一人在线!\n");
        }
        else if(RecvBuf.flag == SHOWNUM)
        {
            printf("\n\t当前有%d个用户在线:\n\n", RecvBuf.num);
        }
        else if(RecvBuf.flag == SHOW)
        {
            if(RecvBuf.endflag == NO)
            {
                printf("\t\t%d. %s\n", recv_count + 1, RecvBuf.nickname);
                recv_count++;
            }
            else if(RecvBuf.endflag == YES)
            {
                printf("\t\t%d. %s\n", recv_count + 1, RecvBuf.nickname);
                recv_count = 0;
            }
        }
        else if(RecvBuf.flag == CHANGE)
        {
            if(RecvBuf.endflag == FAILURE)
            {
                delay();
                printf("\n\n\t修改失败,旧密码输入不正确!\n");
            }
            else if(RecvBuf.endflag == SUCCESS)
            {
                delay();
                printf("\n\n\t修改密码成功!\n");
            }
        }
        else if(RecvBuf.flag == GETNICK)
        {
            strcpy(my_nickname, RecvBuf.fromname);
            printf("\n\n\n\t当前用户:%s\n", my_nickname);
        }
        else if(RecvBuf.flag == MEMBER)
        {
            if(RecvBuf.endflag == SUCCESS)
            {
                delay();
                printf("\n\n\t会员充值成功!\n");
            }
            else if(RecvBuf.endflag == YES)
            {
                delay();
                printf("\n\n\t您已经是会员了!\n");
            }
            else if(RecvBuf.endflag == FAILURE)
            {
                delay();
                printf("\n\n\t会员充值失败!\n");
            }
        }
        else if(RecvBuf.flag == CLOSE)
        {
            if(RecvBuf.endflag == SUCCESS)
            {
                delay();
                printf("\n\n\t禁言成功,该用户已经不能发言了!\n");
            }
            else if(RecvBuf.endflag == FAILURE)
            {
                delay();
                printf("\n\n\t禁言失败,该用户不在线!\n");
            }
            else if(RecvBuf.endflag == ERROR)
            {
                delay();
                printf("\n\n\t禁言失败,您不是会员!\n");
            }
            else if(RecvBuf.endflag == FAULT)
            {
                delay();
                printf("\n\n\t禁言失败,对方也是会员!\n");
            }
            else if(RecvBuf.endflag == NO)
            {
                delay();
                printf("\n\n\t禁言失败,您不能禁言您自己!\n");
            }
            else if(RecvBuf.endflag == YES)
            {
                delay();
                printf("\n\n\t您被禁言了!\n");
            }
        }
        else if(RecvBuf.flag == DOWN)
        {
            if(RecvBuf.endflag == FAILURE)
            {
                delay();
                printf("\n\n\t踢人失败,您不是会员!\n");
            }
            else if(RecvBuf.endflag == ERROR)
            {
                delay();
                printf("\n\n\t踢人失败,您不能踢会员!\n");
            }
            else if(RecvBuf.endflag == SUCCESS)
            {
                delay();
                printf("\n\n\t踢人成功!\n");
            }
            else if(RecvBuf.endflag == NO)
            {
                delay();
                printf("\n\n\t踢人失败,您不能踢你自己!\n");
            }
            else if(RecvBuf.endflag == YES)
            {
                printf("\n\n\t您被踢了!\n");
                sleep(1);
                DATA SendBuf;
                memset(&SendBuf, 0, sizeof(SendBuf));
                SendBuf.flag = BACK;
                ret = send(cfd, &SendBuf, sizeof(SendBuf), 0);
                if(-1 == ret)
                {
                    perror("send");
                    exit(1);
                }
                pthread_cancel(tid[0]);
                return;
            }
        }
        else if(RecvBuf.flag == GIVE)
        {
            if(RecvBuf.endflag == FAILURE)
            {
                delay();
                printf("\n\n\t文件传输失败,目标用户不在线!\n");
            }
            else if(RecvBuf.endflag == ERROR)
            {
                delay();
                printf("\n\n\t文件传输失败,不能将文件传给自己!\n");
            }
            else if(RecvBuf.endflag == OK)
            {
                delay();
                printf("\n\n\t文件发送成功!\n");
            }
            else if(RecvBuf.endflag == YES || RecvBuf.endflag == NO)
            {
                client_receive(RecvBuf);
            }
        }
    }
}

/************************************************显示在线人数,昵称****************************************/

void show_people(int sockfd)
{
    int ret;
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    SendBuf.flag = SHOW;
    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
}


/*************************************************私聊****************************************************/

void private_chat(int sockfd)
{
    system("clear");
    int ret;
    DATA SendBuf;

    while(1)
    {
        memset(&SendBuf, 0, sizeof(SendBuf));
        printf("\n\n\t请输入您聊天对象的昵称(输入end退出聊天):\n");
        scanf("%s", SendBuf.nickname);
        if(!strcmp(SendBuf.nickname, "end"))
        {
            break;
        }
        printf("\t请输入您聊天的内容:\n");
        scanf("%s", SendBuf.message);
        SendBuf.flag = PCHAT;

        ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }

        strcpy(SendBuf.fromname, my_nickname);
        save_message(&SendBuf);
    }
    return;
}

/************************************************群聊***************************************************/

void group_chat(int sockfd)
{
    int ret;
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));

    printf("\n\n\t请输入您的聊天内容:\n");
    scanf("%s", SendBuf.message);
    SendBuf.flag = GCHAT;

    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
    strcpy(SendBuf.fromname, my_nickname);
    strcpy(SendBuf.nickname, "all");
    save_message(&SendBuf);
    delay();
}

/**************************************************修改密码**********************************************/

void change_pswd(int sockfd)
{
    char npswd1[20], npswd2[20];
    memset(&npswd1, 0, sizeof(npswd1));
    memset(&npswd2, 0, sizeof(npswd2));

    int ret;
    DATA SendBuf;
    printf("\n\n\t请输入您的旧密码:\n");
    printf("\n\t请输入您的新密码:\n");
    printf("\n\t请核实您的新密码:\n");
    scanf("%s %s %s", SendBuf.pswd, npswd1, npswd2);
    while(strcmp(npswd1, npswd2) || (!strcmp(SendBuf.pswd, npswd1)) || (!strcmp(SendBuf.pswd, npswd2)))
    {
        printf("\n\n\t您输入的两次密码不一致,新密码不能和旧密码一样!\n");
        memset(&npswd1, 0, sizeof(npswd1));
        memset(&npswd2, 0, sizeof(npswd2)); 
        printf("\n\n\t请重新输入您的新密码:\n");
        printf("\n\t请重新核实您的新密码:\n");
        scanf("%s %s", npswd1, npswd2);
    }

    SendBuf.flag = CHANGE;
    strcpy(SendBuf.message, npswd1);
    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
}

/***************************************************注销**************************************************/

void client_back(int sockfd)
{
    int ret;
    DATA SendBuf;
    memset(&SendBuf, 0, sizeof(SendBuf));
    SendBuf.flag = BACK;
    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
}   

/****************************************************屏蔽kill**********************************************/

void handel(int aig)
{
    int ret;
    DATA SendBuf;
    if(5 == sign)
    {
        memset(&SendBuf, 0, sizeof(SendBuf));
        SendBuf.flag = BACK;
        ret = send(cfd, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }

        pthread_cancel(tid[1]);
    }

    memset(&SendBuf, 0, sizeof(SendBuf));
    SendBuf.flag = QUIT;
    ret = send(cfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }

    close(cfd);
    show_quit();
    exit(1);
}

///
/*********************************************show time*******************************************************/

void show_time()
{
    time_t now;
    now = time(NULL);
    struct tm * tm_now;
    tm_now = localtime(&now);

    printf("当前时间:%d年 %d月 %d日 %d时 %d分 %d秒\n", tm_now->tm_year+1990, tm_now->tm_mon+1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
}

/************************************************保存记录***************************************************/

void save_message(DATA *s)
{
    char filename[64];
    FILE *fp;
    time_t now;
    now = time(NULL);
    struct tm * tm_now;
    tm_now = localtime(&now);

    s->time_year = tm_now->tm_year+1990;
    s->time_mon = tm_now->tm_mon+1;
    s->time_mday = tm_now->tm_mday;
    s->time_hour = tm_now->tm_hour;
    s->time_min = tm_now->tm_min;
    s->time_sec = tm_now->tm_sec;


    if(s->flag == PCHAT)
    {
        sprintf(filename, "%s发给%s_pchat", s->fromname, s->nickname);
        fp = fopen(filename, "a+b");
        if(NULL == fp)
        {
            perror("fopen");
            exit(1);
        }
        fwrite(s, 1, sizeof(DATA), fp);
        fclose(fp);
    }
    else if(s->flag == GCHAT)
    {
        sprintf(filename, "%s发给%s_gchat", s->fromname, s->nickname);
        fp = fopen(filename, "a+b");
        if(NULL == fp)
        {
            perror("fopen");
            exit(1);
        }
        fwrite(s, 1, sizeof(DATA), fp);
        fclose(fp);
    }
    return;
}

/******************************************************读取消息******************************************/

void client_read()
{
    int mark = 0;
//  system("clear");
    printf("\n\n\n");
    char choice[10];

    while(1)
    {
        printf("\n\n\t\t\t\t聊天记录查询!\n");
        printf("\n\n\n\t1. 私聊\n\n");
        printf("\t2. 群聊\n\n");
        printf("\t3. 退出\n\n");
        printf("\t请输入您的选项:\n");
        scanf("%s", choice);
        switch(atoi(&choice[0]))
        {
            case 1:
                read_pchat();
                break;
            case 2:
                read_gchat();
                break;
            case 3:
                return;
            default:
                printf("请重新输入:\n");
                break;
        }
    }
}

void read_pchat()
{
    system("clear");
    printf("\n\n\n\t\t\t私聊记录:\n\n");
    FILE *fp;
    int ret;
    DATA tmp;
    char name[20];
    printf("请依次输入您想要查询和谁的聊天记录:\n");
    scanf("%s", name);
    char filename[64];


    sprintf(filename, "%s发给%s_pchat", my_nickname, name);
    printf("发送记录:\n\n");
    fp = fopen(filename, "r");
    if(fp == NULL)
    {
        printf("\t您没有发送记录!\n\n");
    }
    else
    {
        while(1)
        {
            bzero(&tmp, sizeof(tmp));
            ret = fread(&tmp, 1, sizeof(DATA), fp);
            if(0 == ret)
            {
                break;
            }
            printf("\t时间:%d-%d-%d-%d-%d-%d\n", tmp.time_year, tmp.time_mon, tmp.time_mday, tmp.time_hour, tmp.time_min, tmp.time_sec);
            printf("\t%s对%s说:\t%s\n\n", tmp.fromname, tmp.nickname, tmp.message);
        }
        fclose(fp);
    }


    sprintf(filename, "%s发给%s_pchat", name, my_nickname);
    printf("接受记录:\n\n");
    fp = fopen(filename, "r");
    if(fp == NULL)
    {
        printf("\t您没有接受记录!\n\n");
    }
    else
    {
        while(1)
        {
            bzero(&tmp, sizeof(tmp));
            ret = fread(&tmp, 1, sizeof(DATA), fp);
            if(0 == ret)
            {
                break;
            }
            printf("\t时间:%d-%d-%d-%d-%d-%d\n", tmp.time_year, tmp.time_mon, tmp.time_mday, tmp.time_hour, tmp.time_min, tmp.time_sec);
            printf("\t%s对%s说:\t%s\n\n", tmp.fromname, tmp.nickname, tmp.message);
        }
        fclose(fp);
    }
}

void read_gchat()
{
    system("clear");
    printf("\n\n\n\t\t\t群聊记录\n\n");
    DATA tmp;
    int ret;
    FILE *fp;
    char filename[64];
    sprintf(filename, "%s发给all_gchat", my_nickname);
    fp = fopen(filename, "r");
    if(NULL == fp)
    {
        printf("\t您没有发送群消息记录!\n\n");
    }
    else
    {
        while(1)
        {
            bzero(&tmp, sizeof(tmp));
            ret = fread(&tmp, 1, sizeof(DATA), fp);
            if(0 == ret)
            {
                break;
            }
            printf("\t时间:%d-%d-%d-%d-%d-%d\n", tmp.time_year, tmp.time_mon, tmp.time_mday, tmp.time_hour, tmp.time_min, tmp.time_sec);
            printf("\t%s对%s说:\t%s\n\n", tmp.fromname, tmp.nickname, tmp.message);   
        }
        fclose(fp);
    }

    sprintf(filename, "all发给%s_gchat", my_nickname);
    fp = fopen(filename, "r");
    if(NULL == fp)
    {
        printf("\t您没有接受群消息的记录\n\n");
    }
    else
    {   
        while(1)
        {
            bzero(&tmp, sizeof(tmp));
            ret = fread(&tmp, 1, sizeof(tmp), fp);
            if(0 == ret)
            {
                break;
            }
            printf("\t时间:%d-%d-%d-%d-%d-%d\n", tmp.time_year, tmp.time_mon, tmp.time_mday, tmp.time_hour, tmp.time_min, tmp.time_sec);
            printf("\t%s对%s说:\t%s\n\n", tmp.toname, tmp.nickname, tmp.message); 
        }
        fclose(fp);
    }
}

/*********************************************会员****************************************************/

void client_member(int sockfd)
{
    int choice, ret;
    printf("确定支付30rmb,充值会员吗?(是1,否0)\n\n");
    scanf("%d", &choice);
    if(choice == 1)
    {
        DATA SendBuf;
        SendBuf.flag = MEMBER;
        ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
    return;
}

/********************************************禁言***************************************************/

void client_close(int sockfd)
{
    int ret;
    DATA SendBuf;
    printf("请输入您禁言对象的昵称:\n");
    scanf("%s", SendBuf.nickname);
    SendBuf.flag = CLOSE;
    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
}


/********************************************踢人******************************************/

void client_down(int sockfd)
{
    system("clear");
    int ret;
    DATA SendBuf;
    printf("\n\n\n\n\n\t请输入您想踢人的昵称:\n");
    scanf("%s", SendBuf.nickname);
    SendBuf.flag = DOWN;
    ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
    if(-1 == ret)
    {
        perror("send");
        exit(1);
    }
}


/*************************************************delay****************************************/

void delay()
{
    int i, j;
    for(i = 0; i < 1000; i++)
    {
        for(j = 0; j < 800; j++)
        {

        }
    }
}

/*******************************************文件传输*****************************************/

void client_transform(int sockfd)
{
    char tmpbuf[4096];
    system("clear");
    int ret;
    FILE *fp;
    char filename[64];
    DATA SendBuf;
    bzero(&SendBuf, sizeof(SendBuf));
    printf("\n\n\n\n\n\t请输入您想要传送的文件名:\n");
    scanf("%s", filename);
    printf("\n\t请输入您想要发送文件的对象:\n");
    scanf("%s", SendBuf.toname);
    SendBuf.flag = GIVE;
    SendBuf.endflag = YES;
    strcpy(SendBuf.fromname, my_nickname);
    strcpy(SendBuf.filename, filename);

    fp = fopen(filename, "r");
    if(NULL == fp)
    {
        printf("\n\n\t该文件不存在!\n");
        sleep(1);
        return;
    }
    while(1)
    {
        bzero(&tmpbuf, sizeof(tmpbuf));
        ret = fread(&tmpbuf, 1, sizeof(tmpbuf), fp);
        if(0 == ret)
        {
            bzero(&SendBuf.text, sizeof(SendBuf.text));
            SendBuf.flag = GIVE;
            SendBuf.endflag = NO;

            ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
            if(-1 == ret)
            {
                perror("send");
                exit(1);
            }
            break;
        }

        strcpy(SendBuf.text, tmpbuf);
        ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
        if(-1 == ret)
        {
            perror("send");
            exit(1);
        }
    }
}

/***********************************************接受文件**************************************/

void client_receive(DATA RecvBuf)
{
    FILE *fp;
    char filename[60];
    bzero(&filename, sizeof(filename));
    strcpy(filename, RecvBuf.filename);

    if(RecvBuf.endflag == YES)
    {
        fp = fopen(RecvBuf.filename, "a+b");
        if(NULL == fp)
        {
            perror("fopen");
            exit(1);
        }

        fwrite(&RecvBuf.text, 1, sizeof(RecvBuf.text), fp);
        fclose(fp);
    }
    else if(RecvBuf.endflag == NO)
    {
        printf("\n\n\t您接受到了来自%s用户的新文件!\n", RecvBuf.fromname);
        sleep(1);
        printf("\n\t接受完成!\n");
        sleep(1);
    }
}

你可能感兴趣的:(Linux)