目录

1.概述

1.1聊天室设计内容

2.系统设计

2.1系统功能设计

2.1.1用户管理

2.1.2聊天室管理

2.1.3聊天管理

2.2系统数据结构设计

2.3系统主要函数设计

3.系统实现

3.2功能模块的程序流程图及运行界面

3.2.1功能模块流程图

3.2.2运行界面

4.源代码

4.1客户端

4.2服务器

注:存在问题



1.概述

1.1聊天室设计内容

1.用户管理

实现用户注册,登录,找回密码

2.聊天室管理

用户登录,本地添加删除好友,修改备注,注册vip,vip可以实现禁言,解除禁言,强制好友下线

3.聊天管理

用户可以私发,群发消息,表情包或者文件,好友上线提醒

2.系统设计

2.1系统功能设计

网络聊天室系统分为服务器和客户端,客户端主要进行命令的发送,以及接受服务器发送过来的信息。服务器主要进行指令的解析并执行相关的函数,将执行的结果反馈给客户端。

2.1.1用户管理

用户管理要完成用户注册、登录、和找回密码。注册的信息存储在服务器的数据库中。数据库保存用户的昵称,账号,密码,权限,套接字,以及在线状态。当用户登录时,查询服务器数据库中的账号密码是否匹配,若是成功匹配,则登陆成功,否则登录失败。反馈客户端用户账号或者密码错误。

用户注册时,引导用户输入用户名,密码,密保以及答案,将注册信息存储到数据库中,若成功执行,则反馈给用户一个六位数的账号。

当用户湾及密码是,需要输入正确的账号,发送给服务器,服务器从数据中查找,找到对应账号则反馈给客户端密保问题,用户回答正确后反馈相应的密码。

当客户端退出程序时,向服务器发送下线数据,服务器更新相应的套接字以及在线状态。

2.1.2聊天室管理

用户登录聊天室需要输入正确的账号密码。登陆成功后服务器会发送给其好友,提醒好友已上线。用户可以选择私发,群发,注册会员,以及退出聊天。

2.1.3聊天管理

用户发送消息的情况有两种,分别是1、发送给私人。2、发送给多人。用户发送信息采用write命令,可以根据菜单选项确定用户发送的时那种模式。

1、私聊

发送给指定用户消息,提示用户输入私聊的对象的昵称或者备注,客户端检查用户是否有该对象好友,若没有,靠苏用户没有该好友,若有则发送消息,当用户发送私聊信息时,服务器检查发送方权限(是否被禁言),然后检查对方是否在线,若用户被禁言,则提示用户“您以被禁言”,若被发送方不在线,则提醒用户。

2、群聊

发送给指定的多个用户,原理同上。

2.2系统数据结构设计

1.注册登录选项结构体

选项结构体包option选项用来判断用户即将进行的操作,共用体存放的是对应操作需要的信息。

2.发送的消息结构体

struct file结构体用来存放文件大小,文件名字,需要发送的次数以及发送文件的buff。

2.3系统主要函数设计

2.3.1客户端

1.int main()

客户端主程序主要完成设置服务器地址,创建客户端流式套接字,创建好友数据库,表情包数据库。

2.user_options()

用户操作函数,根据用户对应的选项执行相应的操作

3.chat_start_c()

用户登陆成功后,创建读写线程,进行聊天,读线程根据用户的选项决定是消息,表情包还是文件的发送,读线程,对接受到的消息进行相应的处理。

2.3.2服务器

1.int main()

服务器主程序主要完成服务器地址的设置,创建服务器流式套接字,将地址结构和套接字绑定,设置侦听接口。每接收到一个客户端登录成功,就创建一个线程。

2.do_use_fd()

服务器根据客户端发送的消息进行相应的处理。

3.creat_sqlite()

创建数据库,建立注册信息表,以及聊天记录表,分别用于存放用户的账户信息以及聊天记录。

3.系统实现

系统环境:Ubuntu 18.04

gcc版本:7.50

编辑器:visual studio code version

3.2功能模块的程序流程图及运行界面

3.2.1功能模块流程图

1.客户端

2.写线程流程图

3.读线程流程图

4.服务器流程图

3.2.2运行界面

注册信息数据库:

图片太多就不全放了,这里只展示一部分功能。

4.源代码

4.1客户端

#ifndef _CHAT_C_H_#define _CHAT_C_H_#define _DEBUG_#ifndef _DEBUG_#define debug_msg(fmt, args...)#else#define debug_msg(fmt, args...) printf(fmt, ##args)#endif#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IPADDR "127.0.0.1"#define TCP_PORT 8000#define MAX_EVENTS 20#define MSG_BUFFSIZE 100#define PASSWORD_SIZE 10#define NICKNAME_SIZE 10#define SC_PRO 10#define ANSWER 10#define EXP_SIZE 10#define FILE_S 1024#define FILE_N 20#define SQL_SIZE 300#define MAX_GROUP 20#define MUSHIN -1#define ACCOUNT_ERROR -1#define ANSWER_ERROR -2#define CTRL1 30#define CTRL2 30#define CTRL3 18#define SEARCH_ERROR "查找失败!!"#define PED_ERROR "回答错误!!"#define NO_FRIEND "查无此人!!"#define PAY "支付"#define PAY_SUCCED "支付成功"#define PAY_FAILED "支付失败"#define ERO_VIP "注册会员成功"#define NOT_ONLINE -3#define ONLINE -4#define OFFLINE -5enum option{EXIT,ERO,LOG,FGPD};enum chatmode{STOO = 1,STOA,ADD,DEL,VIP,MUS,CANCLE,OUT};enum chatoption{MSG = 1,EXP,FS,GAME,};// 注册信息struct enrollinfo{char nickname[NICKNAME_SIZE];char password[PASSWORD_SIZE];char sc_protect[SC_PRO];char answer[ANSWER];int account;};// 登录信息struct logininfo{int account;char password[PASSWORD_SIZE];};// 注册登录选项包struct options{int option;union{struct enrollinfo eninfo;struct logininfo loginfo;int fgpwd_account;} info;};struct file{int times;unsigned int file_size;char file_name[FILE_N];char file_buff[FILE_S];};// 聊天消息包struct msg_buff{int chat_mode;int my_account;//自己账号int account[MAX_GROUP];// 对方账号char op_nickname[NICKNAME_SIZE]; // 自己昵称int num; // 聊天人数int mushin_flag; //禁言踢人标志位int option;union{struct file fileinfo;char chat_msg[MSG_BUFFSIZE];} chat_opt;};// 回调函数参数(套接口和数据库文件描述符)struct cp{int confd;int account;FILE *fp;sqlite3 *pdb;};// 创建数据库(好友信息(设置备注),账号)int creat_sqlite(sqlite3 **pdb);int creat_table_chat(sqlite3 *pdb);int creat_table(sqlite3 *pdb, char *sql);// 创建tcp/udp套接口void create_tcp_client(int *sockfd, struct sockaddr_in *s_addr);void create_udp_client(int *sockfd, struct sockaddr_in *s_addr);// 菜单选项void options_menu();void enroll_menu();void log_menu();void chat_interface();void mode();void mode1();void mode2();void mode3();void mode4();void modevip();void loging();// 用户选择void user_options(const int confd, sqlite3 *pdb);// 查询权限int sure_my_permision(int confd, int account);// 操作void insert_enroll_infomation(struct options *option);void ero_account_c(int confd, struct options *option);void select_friends(sqlite3 *pdb);int display(void *para, int colcount, char **colvalue, char **colname);// 登录void log_opreation_c(int confd, struct options *option, sqlite3 *pdb);void log_infomation(struct options *option);void chat_start_c(int confd, struct options *option, sqlite3 *pdb);// 找回密码void get_password(int confd, struct options *option);// 读写分离void *read_thread(void *arg);void *write_thread(void *arg);void say_to_all(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp);void say_to_one(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp);void send_msg_c(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp);void send_exp_c(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp);void send_file_c(int confd, struct msg_buff *msg, sqlite3 *pdb);int file_size(char *name);int search_account(struct msg_buff *msg, char *name, sqlite3 *pdb);void add_friends(int confd, struct msg_buff *msg, sqlite3 *pdb);int insert_into_chat_friend(sqlite3 *pdb, int account, char *remarkname, char *nickname);int delete_friend(sqlite3 *pdb);int ero_vip(int confd, struct msg_buff *msg);void mush_friend_cancle(int confd, struct msg_buff *msg, sqlite3 *pdb);#endif
#include "chat_c.h"void user_options(const int confd, sqlite3 *pdb){int flag = 0;struct options option;do{memset(&option, 0, sizeof(option));if (flag == 0){system("clear");flag = 1;}options_menu();printf("\033[%dC请选择:> ", CTRL1 + 4);printf("\033[2D");scanf("%d", &option.option);getchar();switch (option.option){case ERO:ero_account_c(confd, &option);break;case LOG:log_opreation_c(confd, &option, pdb);break;case FGPD:get_password(confd, &option);break;case EXIT:system("clear");option.option = EXIT;write(confd, &option, sizeof(option));break;default:printf("input error:\n");break;}} while (option.option);return;}void insert_enroll_infomation(struct options *option){char pswd_buff[10];enroll_menu();scanf("%s", option->info.eninfo.nickname);do{printf("\033[%dC\033[1B", CTRL1 + 15);scanf("%s", pswd_buff);printf("\033[%dC\033[1B", CTRL1 + 15);scanf("%s", option->info.eninfo.password);if (0 != strcmp(pswd_buff, option->info.eninfo.password)){printf("\033[4A");}} while (0 != strcmp(pswd_buff, option->info.eninfo.password));printf("\033[%dC\033[1B", CTRL1 + 15);scanf("%s", option->info.eninfo.sc_protect);printf("\033[%dC\033[1B", CTRL1 + 15);scanf("%s", option->info.eninfo.answer);return;}void ero_account_c(const int confd, struct options *option){int account;insert_enroll_infomation(option);write(confd, option, sizeof(struct options));read(confd, &account, sizeof(int));system("clear");printf("\033[4B\033[%dC你的账号是 :%d\033[4A\n", CTRL1 + 2, account);return;}void log_infomation(struct options *option){int i = 0;char a[20];log_menu();scanf("%d", &option->info.loginfo.account);getchar();printf("\033[1B\033[%dC", CTRL2 + 15);while (1){system("stty -echo");a[i] = getchar();if (a[i] == '\n'){break;}fflush(stdin);system("stty echo");printf("*");fflush(stdout);i++;}system("stty echo");a[i] = '\0';strcpy(option->info.loginfo.password, a);}void log_opreation_c(int confd, struct options *option, sqlite3 *pdb){char buff[10];memset(buff, 0, sizeof(buff));log_infomation(option);write(confd, option, sizeof(struct options));read(confd, buff, sizeof(buff));if (0 == strcmp(buff, "failed")){loging();printf("\033[2B\033[%dC登录失败!!\n", CTRL2 + 6);sleep(2);return;}if (0 == strcmp(buff, "success")){loging();chat_start_c(confd, option, pdb);}return;}void get_password(int confd, struct options *option){char buff[100];memset(buff, 0, sizeof(buff));int account;printf("\033[%dC请输入账号:> \033[K", CTRL1 + 4);scanf("%d", &option->info.fgpwd_account);write(confd, option, sizeof(struct options));read(confd, buff, sizeof(buff));if (0 == strcmp(buff, SEARCH_ERROR)){printf("账号输入错误:\n");return;}printf("\033[%dC密保问题是:> %s\n", CTRL1 + 4, buff);printf("\033[%dC请输入答案:> \033[K", CTRL1 + 4);memset(buff, 0, sizeof(buff));scanf("%s", buff);write(confd, buff, sizeof(buff));memset(buff, 0, sizeof(buff));read(confd, buff, sizeof(buff));if (0 == strcmp(buff, PED_ERROR)){printf("答案错误!!!\n");printf("\033[%dC答案错误!!!\n", CTRL1 + 4);}elseprintf("\033[%dC你的密码是:> %s\n", CTRL1 + 4, buff);printf("\033[u");}

#include "chat_c.h"int creat_sqlite(sqlite3 **pdb){int ret;if ((ret = sqlite3_open("chat_room_c.db", pdb)) != SQLITE_OK){perror("creat sqlite error");exit(1);}return SQLITE_OK;}int creat_table_chat(sqlite3 *pdb){char *sql = "create table if not exists chat_friend (Account integer primary key, \Nickname text NOT NULL,\Remarkname text );";char *sql1 = "create table if not exists expression (id integer primary key,exp text);";if (creat_table(pdb, sql) != SQLITE_OK){debug_msg("creat table account error\n");return -1;}if (creat_table(pdb, sql1) != SQLITE_OK){debug_msg("creat table expression error\n");return -1;}return SQLITE_OK;}int creat_table(sqlite3 *pdb, char *sql){int ret;char *errmsg = NULL;if ((ret = sqlite3_exec(pdb, sql, NULL, NULL, &errmsg)) != SQLITE_OK){perror("creat table error:");return -1;}return SQLITE_OK;}int insert_into_chat_friend(sqlite3 *pdb, int account, char *remarkname, char *nickname){char sql[SQL_SIZE];char *errmsg = NULL;sprintf(sql, "insert OR IGNORE intochat_friend (Account,Nickname,Remarkname) values (%d,'%s','%s');",account, nickname, remarkname);if (SQLITE_OK != sqlite3_exec(pdb, sql, NULL, NULL, &errmsg)){printf("insert friend error:%s\n", errmsg);sqlite3_free(errmsg);return -1;}return 0;}

#include "chat_c.h"void *write_thread(void *arg){int flag = 0;int bytes_send;int confd;int account;FILE *fp;sqlite3 *pdb;struct cp args;memset(&args, 0, sizeof(args));args = *((struct cp *)arg);confd = args.confd;pdb = args.pdb;fp = args.fp;struct msg_buff msg;system("clear");// 查看自己是否是vipchat_interface();if (sure_my_permision(confd, args.account) > 1){flag = 1;}mode4();do{if (1 == flag){modevip();}memset(&msg, 0, sizeof(msg));msg.my_account = args.account;select_friends(pdb);printf("\033[u");scanf("%d", &msg.chat_mode);getchar();switch (msg.chat_mode){case STOO:mode1();say_to_one(confd, &msg, pdb, fp);break;case STOA:mode1();say_to_all(confd, &msg, pdb, fp);break;case ADD:add_friends(confd, &msg, pdb);break;case DEL:if (delete_friend(pdb) != 0){printf("删除好友失败\n");}break;case VIP:if (0 == ero_vip(confd, &msg)){modevip();}break;case MUS:mush_friend_cancle(confd, &msg, pdb);break;case CANCLE:mush_friend_cancle(confd, &msg, pdb);break;case OUT:mush_friend_cancle(confd, &msg, pdb);break;case EXIT:system("clear");msg.chat_mode = EXIT;write(confd, &msg, sizeof(msg));fclose(fp);exit(0);default:break;};} while (msg.chat_mode);return NULL;}void say_to_all(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp){do{mode();printf("\033[u");scanf("%d", &msg->option);switch (msg->option){case MSG:send_msg_c(confd, msg, pdb, fp);break;case EXP:send_exp_c(confd, msg, pdb, fp);break;case FS:send_file_c(confd, msg, pdb);break;case EXIT:system("clear");chat_interface();mode2();mode4();break;default:break;}} while (msg->option);return;}void say_to_one(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp){char buff[100];do{mode();printf("\033[u");scanf("%d", &msg->option);switch (msg->option){case MSG:send_msg_c(confd, msg, pdb, fp);break;case EXP:send_exp_c(confd, msg, pdb, fp);break;case FS:send_file_c(confd, msg, pdb);break;case EXIT:system("clear");chat_interface();mode2();mode4();break;default:break;}} while (msg->option);return;}// 客户端发送消息void send_msg_c(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp){int ret;char name[NICKNAME_SIZE];char record[200];char buff[100];memset(buff, 0, sizeof(buff));memset(record, 0, sizeof(record));msg->num = 1;if (msg->chat_mode == STOO){mode3();printf("\033[2B\033[10D请输入聊天好友:>\033[K");memset(name, 0, sizeof(name));scanf("%s", name);ret = search_account(msg, name, pdb);if (ret account[0] = ret;printf("\033[u");scanf("%s", msg->chat_opt.chat_msg);write(confd, msg, sizeof(struct msg_buff));sprintf(record, "%s %s 我-->%s:%s\n", __DATE__, __TIME__, name, msg->chat_opt.chat_msg);fputs(record, fp);}else if (msg->chat_mode == STOA){mode3();int num;printf("\033[2B\033[10D请输入群聊人数:>\033[K");scanf("%d", &num);msg->num = num;for (int i = 0; i \033[K", CTRL3 + 2);scanf("%s", name);ret = search_account(msg, name, pdb);if (ret account[i] = ret;}printf("\033[u");scanf("%s", msg->chat_opt.chat_msg);write(confd, msg, sizeof(struct msg_buff));sprintf(record, "%s %s 我-->群发:%s\n", __DATE__, __TIME__, msg->chat_opt.chat_msg);fputs(record, fp);}mode4();return;}// 显示表情库void show_explib(sqlite3 *pdb){char *sql = "select * from expression;";char *errmsg = NULL;char **result = NULL;int row, col;if (sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);sqlite3_free(errmsg);return;}printf("\033[u\033[10A\033[12D");for (int i = 2; i chat_opt.chat_msg, presult[1]);sqlite3_free_table(presult);return 0;}}// 发送表情void send_exp_c(int confd, struct msg_buff *msg, sqlite3 *pdb, FILE *fp){int ret;char name[NICKNAME_SIZE];char buff[100];char record[200];int id;memset(buff, 0, sizeof(buff));memset(record, 0, sizeof(record));msg->num = 1;if (msg->chat_mode == STOO){mode3();printf("\033[2B\033[10D请输入聊天好友:>\033[K");memset(name, 0, sizeof(name));scanf("%s", name);ret = search_account(msg, name, pdb);if (ret account[0] = ret;show_explib(pdb);mode4();scanf("%d", &id);find_exp(msg, id, pdb);write(confd, msg, sizeof(struct msg_buff));sprintf(record, "%s %s 我-->%s:%s\n", __DATE__, __TIME__, name, msg->chat_opt.chat_msg);fputs(record, fp);}else if (msg->chat_mode == STOA){mode3();int num;printf("\033[2B\033[10D请输入群聊人数:>\033[K");scanf("%d", &num);msg->num = num;for (int i = 0; i \033[K", CTRL3 + 2);scanf("%s", name);ret = search_account(msg, name, pdb);if (ret account[i] = ret;}show_explib(pdb);mode4();scanf("%d", &id);find_exp(msg, id, pdb);write(confd, msg, sizeof(struct msg_buff));sprintf(record, "%s %s 我-->群发:%s\n", __DATE__, __TIME__, msg->chat_opt.chat_msg);fputs(record, fp);}mode4();return;}// 查找联系人列表的账号通过备注int search_account(struct msg_buff *msg, char *name, sqlite3 *pdb){int row, col;int account;char *errmsg = NULL;char sql[SQL_SIZE];char **presult = NULL;sprintf(sql, "select Account from chat_friend where Remarkname = '%s' OR Nickname = '%s';", name, name);if (sqlite3_get_table(pdb, sql, &presult, &row, &col, &errmsg) != SQLITE_OK){debug_msg("write thread %d %s\n", __LINE__, errmsg);printf("查找失败:\n");sqlite3_free(errmsg);return -1;}if (0 == row){sqlite3_free_table(presult);printf("名字输入错误:\n");return -1;}else{account = atoi(presult[1]); // presult[0] 是字段名sqlite3_free_table(presult);return account;}}// 添加好友,单方面添加void add_friends(int confd, struct msg_buff *msg, sqlite3 *pdb){printf("\033[u");char buff[100];char remarkname[NICKNAME_SIZE];memset(buff, 0, sizeof(buff));printf("\033[2B\033[10D请输入好友账号:>\033[K");scanf("%d", &msg->account[0]);write(confd, msg, sizeof(struct msg_buff));read(confd, buff, sizeof(buff));if (0 == strcmp(buff, NO_FRIEND)){printf(NO_FRIEND);printf("\n");return;}printf("\033[%dC您添加的好友昵称为%s\n", CTRL3 + 6, buff);printf("\033[%dC设置备注:>\033[K", CTRL3 + 6);scanf("%s", remarkname);if (insert_into_chat_friend(pdb, msg->account[0], remarkname, buff) \033[K");scanf("%s", name);sprintf(sql, "delete fromchat_friendwhere Remarkname = '%s';", name);if (SQLITE_OK != sqlite3_exec(pdb, sql, NULL, NULL, &errmsg)){printf("delete friend error:%s\n", errmsg);sqlite3_free(errmsg);return -1;}return 0;}// 注册vipint ero_vip(int confd, struct msg_buff *msg){char buff[100];int money;memset(buff, 0, sizeof(buff));printf("\033[u");msg->mushin_flag = VIP;write(confd, msg, sizeof(struct msg_buff));read(confd, buff, sizeof(buff));if (0 != strcmp(buff, PAY)){printf("注册失败\n");return -1;}printf("\033[2B\033[10DC请支付15元:>\033[K");scanf("%d", &money);if (money == 15){write(confd, PAY_SUCCED, sizeof(PAY_SUCCED));read(confd, buff, sizeof(buff));printf("\033[%dC%s\n", CTRL3 + 2, buff);printf("\033[u");}else{write(confd, PAY_FAILED, sizeof(PAY_FAILED));printf("\033[%dC注册会员失败!!\n", CTRL3 + 2);printf("\033[u");return -1;}return 0;}// 显示好友列表void select_friends(sqlite3 *pdb){char *sql = "select Remarkname,account from chat_friend;";char *errmsg = NULL;char **result = NULL;int row, col;if (sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);sqlite3_free(errmsg);return;}printf("\033[s");printf("\033[17A");printf("\033[%dC", CTRL3 + 18);for (int i = 2; i \033[K");scanf("%s", name);if ((ret = search_account(msg, name, pdb)) account[0] = ret;write(confd, msg, sizeof(struct msg_buff));read(confd, buff, sizeof(buff));printf("\033[%dC%s!!", CTRL3 + 6, buff);printf("\033[u");}void send_file_c(int confd, struct msg_buff *msg, sqlite3 *pdb){int ret;int bytes_read;char name[NICKNAME_SIZE];struct stat info;msg->num = 1;if (msg->chat_mode == STOO){mode3();printf("\033[2B\033[10D请输入聊天好友:>\033[K");memset(name, 0, sizeof(name));scanf("%s", name);ret = search_account(msg, name, pdb);if (ret account[0] = ret;printf("\033[u");printf("\033[2B\033[10D请输入文件名:>\033[K");scanf("%s", msg->chat_opt.fileinfo.file_name);if ((ret = file_size(msg->chat_opt.fileinfo.file_name)) chat_opt.fileinfo.file_size = ret;FILE *fp = fopen(msg->chat_opt.fileinfo.file_name, "r");if (ret % FILE_S == 0)msg->chat_opt.fileinfo.times = ret / FILE_S;elsemsg->chat_opt.fileinfo.times = ret / FILE_S + 1;while (msg->chat_opt.fileinfo.times){msg->chat_opt.fileinfo.times--;bytes_read = fread(msg->chat_opt.fileinfo.file_buff, FILE_S, 1, fp);write(confd, msg, sizeof(struct msg_buff));}fclose(fp);}else if (msg->chat_mode == STOA){mode3();int num;printf("\033[2B\033[10D请输入群聊人数:>\033[K");scanf("%d", &num);msg->num = num;for (int i = 0; i \033[K", CTRL3 + 2);scanf("%s", name);ret = search_account(msg, name, pdb);if (ret account[i] = ret;}printf("\033[2B\033[10D请输入文件名:>\033[K");scanf("%s", msg->chat_opt.fileinfo.file_name);if ((ret = file_size(msg->chat_opt.fileinfo.file_name)) chat_opt.fileinfo.file_size = ret;FILE *fp = fopen(msg->chat_opt.fileinfo.file_name, "r");if (ret % FILE_S == 0)msg->chat_opt.fileinfo.times = ret / FILE_S;elsemsg->chat_opt.fileinfo.times = ret / FILE_S + 1;while (msg->chat_opt.fileinfo.times){bytes_read = fread(msg->chat_opt.fileinfo.file_buff, FILE_S, 1, fp);write(confd, msg, sizeof(struct msg_buff));msg->chat_opt.fileinfo.times--;}fclose(fp);}mode4();}int file_size(char *name){struct stat info;// 查看文件大小int ret = stat(name, &info);if (ret < 0){perror("stat error:");return -1;}return info.st_size;}

#include "chat_c.h"// 查找是否是好友上线int search_friend_name(char *name, int account, sqlite3 *pdb){int row, col;char *errmsg = NULL;char sql[SQL_SIZE];char **presult = NULL;sprintf(sql, "select Remarkname from chat_friend where Account = %d;", account);if (sqlite3_get_table(pdb, sql, &presult, &row, &col, &errmsg) != SQLITE_OK){debug_msg("write thread %d %s\n", __LINE__, errmsg);printf("查找失败:\n");sqlite3_free(errmsg);return -1;}if (0 == row){return -1;}else{strcpy(name, presult[1]);sqlite3_free_table(presult);return 0;}}// 查找是谁发的消息int search_who_send(char *name, int account, sqlite3 *pdb){char sql[SQL_SIZE];char **result = NULL;char *errmsg = NULL;int row, col;sprintf(sql, "select Remarkname from chat_friend where Account = %d;", account);if (SQLITE_OK != sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg)){printf("error :%s\n", errmsg);sqlite3_free(errmsg);return -1;}if (0 == row){strcpy(name, "someone");}else if (1 == row){strcpy(name, result[1]);}sqlite3_free_table(result);return SQLITE_OK;}// 接收文件void accept_file(struct msg_buff *msg, sqlite3 *pdb){int bytes_write;int ret;char name[NICKNAME_SIZE];// 查找是谁发的消息if (search_who_send(name, msg->my_account, pdb) chat_opt.fileinfo.file_name, msg->chat_opt.fileinfo.file_size);FILE *fp = fopen("accept.text", "w+");bytes_write = fwrite(msg->chat_opt.fileinfo.file_buff, FILE_S, 1, fp);if (msg->chat_opt.fileinfo.times == 0){printf("\033[u\033[2B\033[13D接收完毕!!\n");}fclose(fp);printf("\033[3A\033[%dC", CTRL3 + 16);}void read_msg(struct msg_buff *msg, sqlite3 *pdb, FILE *fp){char record[200];memset(record, 0, sizeof(record));char name[NICKNAME_SIZE];// 查找是谁发的消息if (search_who_send(name, msg->my_account, pdb) chat_opt.chat_msg);sprintf(record, "%s %s %s-->我:%s\n", __DATE__, __TIME__, name, msg->chat_opt.chat_msg);fputs(record, fp);printf("\033[15B\033[%dC", CTRL3 + 16);}void read_choice(struct msg_buff *msg, sqlite3 *pdb, FILE *fp){switch (msg->option){case MSG:read_msg(msg, pdb, fp);break;case EXP:read_msg(msg, pdb, fp);break;case FS:accept_file(msg, pdb);break;default:break;}}void *read_thread(void *arg){int bytes_recv;int confd;int choice;int account;struct sockaddr_in s_addr;socklen_t s_len = sizeof(s_addr);sqlite3 *pdb;FILE *fp;struct cp args = *((struct cp *)arg);confd = args.confd;pdb = args.pdb;fp = args.fp;struct msg_buff msg;while (1){if ((bytes_recv = read(confd, &msg, sizeof(msg))) != sizeof(msg)){continue;}if (msg.mushin_flag == MUSHIN){printf("\033[16A\033[11D您已经被禁言!!!\n");printf("\033[u");continue;}else if (msg.mushin_flag == -2){fclose(fp);system("clear");exit(0);}else if (msg.mushin_flag == NOT_ONLINE){printf("\033[16A\033[11D对方不在线!!!\n");printf("\033[u");}else if (msg.mushin_flag == ONLINE){char name[NICKNAME_SIZE];search_friend_name(name, msg.my_account, pdb);printf("\033[4A\033[36C%s上线了\n", name);printf("\033[u");}else if (msg.mushin_flag == OFFLINE){char name[NICKNAME_SIZE];search_friend_name(name, msg.my_account, pdb);printf("\033[4A\033[36C%s下线了\n", name);printf("\033[u");}else{read_choice(&msg, pdb, fp);}}}
#include "chat_c.h"void options_menu(){printf("\033[s");printf("\n\n\n\n");printf("\033[%dC______________________\n", CTRL1);printf("\033[%dC||\n", CTRL1);printf("\033[%dC||\n", CTRL1);printf("\033[%dC| 1.注册 |\n", CTRL1);printf("\033[%dC||\n", CTRL1);printf("\033[%dC| 2.登录 |\n", CTRL1);printf("\033[%dC||\n", CTRL1);printf("\033[%dC| 3.忘记密码 |\n", CTRL1);printf("\033[%dC||\n", CTRL1);printf("\033[%dC| 0.退出 |\n", CTRL1);printf("\033[%dC||\n", CTRL1);printf("\033[%dC||\n", CTRL1);printf("\033[%dC|____________________|\n", CTRL1);printf("\n");}void enroll_menu(){system("clear");printf("\n\n\n");printf("\033[%dC___________________________\n", CTRL1);printf("\033[%dC| |\n", CTRL1);printf("\033[%dC| |\n", CTRL1);printf("\033[%dC|请输入昵称: |\n", CTRL1);printf("\033[%dC| |\n", CTRL1);printf("\033[%dC|请输入密码: |\n", CTRL1);printf("\033[%dC| |\n", CTRL1);printf("\033[%dC|请确认密码: |\n", CTRL1);printf("\033[%dC| |\n", CTRL1);printf("\033[%dC|密保问题:|\n", CTRL1);printf("\033[%dC| |\n", CTRL1);printf("\033[%dC|密保答案:|\n", CTRL1);printf("\033[%dC| |\n", CTRL1);printf("\033[%dC|_________________________|\n", CTRL1);printf("\033[11A\033[%dC", CTRL1 + 15);}void log_menu(){system("clear");printf("\n\n\n\n\n");printf("\033[%dC_______________________________\n", CTRL2);printf("\033[%dC| |\n", CTRL2);printf("\033[%dC| |\n", CTRL2);printf("\033[%dC|聊天室 |\n", CTRL2);printf("\033[%dC| |\n", CTRL2);printf("\033[%dC|请输入账号: |\n", CTRL2);printf("\033[%dC| |\n", CTRL2);printf("\033[%dC|请输入密码: |\n", CTRL2);printf("\033[%dC| |\n", CTRL2);printf("\033[%dC| |\n", CTRL2);printf("\033[%dC|_____________________________|\n", CTRL2);printf("\033[6A\033[%dC", CTRL2 + 15);}void chat_interface(){printf("\n\n\n\n\n");printf("\033[%dC%s%s\n", CTRL3, __DATE__, __TIME__);printf("\033[%dC—————————————————————————————————————————————————————————————————————\n", CTRL3);printf("\033[%dC|| | 好友列表 |\n", CTRL3);printf("\033[%dC||\033[31m会员大放送\33[37m ||\n", CTRL3);printf("\033[%dC|| ||\n", CTRL3);printf("\033[%dC|| 超值会员||\n", CTRL3);printf("\033[%dC|| ||\n", CTRL3);printf("\033[%dC|| 让你拥有||\n", CTRL3);printf("\033[%dC||帝王般 ||\n", CTRL3);printf("\033[%dC||的权利 ||\n", CTRL3);printf("\033[%dC|| ||\n", CTRL3);printf("\033[%dC||禁言 ||\n", CTRL3);printf("\033[%dC||踢人 ||\n", CTRL3);printf("\033[%dC|| ||\n", CTRL3);printf("\033[%dC|----------------------------|你值得拥有 ||\n", CTRL3);printf("\033[%dC|1.私聊2.群聊| 还在等什么呢||\n", CTRL3);printf("\033[%dC|3.加好友4.删好友|赶快行动吧 ||\n", CTRL3);printf("\033[%dC|5.注册会员0.退出| ||\n", CTRL3);printf("\033[%dC---------------------------------------------------------------------\n", CTRL3);printf("\033[%dC| |\n", CTRL3);printf("\033[%dC| |\n", CTRL3);printf("\033[%dC—————————————————————————————————————————————————————————————————————\n", CTRL3);printf("\033[2A\033[%dC", CTRL3 + 16);printf("\033[s");return;}void modevip(){printf("\033[u");printf("\033[1A\033[11D\033[31m6.禁言7.解除禁言 8.踢人\033[37m\n");printf("\033[u");}void mode(){printf("\033[u");printf("\033[1A\033[11D \n");printf("\033[u");}void mode1(){printf("\033[u");printf("\033[5A\033[12D1.发消息 2.发表情\n");printf("\033[%dC\n", CTRL3 + 4);printf("\033[%dC3.发文件 0.退出 \n", CTRL3 + 4);printf("\033[u");}void mode2(){printf("\033[u");printf("\033[5A\033[12D1.私聊 2.群聊\n");printf("\033[%dC3.加好友 4.删好友 \n", CTRL3 + 4);printf("\033[%dC5.注册会员 0.退出 \n", CTRL3 + 4);printf("\033[u");}void mode3(){printf("\033[u\033[11D");printf("消息内容:[]\n");printf("\033[u");}void mode4(){printf("\033[u\033[11D");printf("请选择:> \n");printf("\033[u");}void loging(){int i;printf("\033[" />

4.2服务器

#ifndef _CHAT_S_H_#define _CHAT_S_H_#define _DEBUG_#ifndef _DEBUG_#define debug_msg(fmt, args...)#else#define debug_msg(fmt, args...) printf(fmt, ##args)#endif#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TCP_PORT 8000#define MAX_EVENTS 20#define MSG_BUFFSIZE 100#define PASSWORD_SIZE 10#define NICKNAME_SIZE 10#define SC_PRO 10#define ANSWER 10#define EXP_SIZE 10#define LOG_SUCCESS 1#define FILE_S 1024#define FILE_N 20#define SQL_SIZE 300#define MAX_GROUP 20#define MUSHIN -1#define ACCOUNT_ERROR -1#define ANSWER_ERROR -2#define SEARCH_ERROR "查找失败!!"#define PED_ERROR "回答错误!!"#define NO_FRIEND "查无此人!!"#define PAY "支付"#define PAY_SUCCED "支付成功"#define PAY_FAILED "支付失败"#define ERO_VIP "注册会员成功"#define NOT_ONLINE-3#define ONLINE -4#define OFFLINE -5enum option{EXIT,ERO,LOG,FGPD};enum chatmode{STOO = 1,STOA,ADD,DEL,VIP,MUS,CANCLE,OUT};enum chatoption{MSG = 1,EXP,FS,GAME,};// 注册信息struct enrollinfo{char nickname[NICKNAME_SIZE];char password[PASSWORD_SIZE];char sc_protect[SC_PRO];char answer[ANSWER];int account;};// 登录信息struct logininfo{int account;char password[PASSWORD_SIZE];};// 选项结构体struct options{int option;union{struct enrollinfo eninfo;struct logininfo loginfo;int fgpwd_account;//找回密码标志位} info;};struct file{int times;//发送次数unsigned int file_size; //文件大小char file_name[FILE_N]; //文件名字char file_buff[FILE_S]; //缓冲区};// 聊天数据结构体struct msg_buff{int chat_mode; //聊天模式(私聊、群聊)int my_account;//自己账号int account[MAX_GROUP];// 对方账号char op_nickname[NICKNAME_SIZE]; // 自己昵称int num; // 聊天人数int mushin_flag; //标志位int option;union{struct file fileinfo;char chat_msg[MSG_BUFFSIZE];} chat_opt;};struct arg{int fd;sqlite3 *pdb;};// 创建数据库int creat_sqlite(sqlite3 **pdb);// 创建注册人员信息表及聊天记录数据库int creat_table(sqlite3 *pdb, char *sql);int creat_table_chat(sqlite3 *pdb);int update_sqlite3_fd(int confd, int account, sqlite3 *pdb);int update_sqlite3_statu(int account, sqlite3 *pdb);// 超级用户创建int super_root(sqlite3 *pdb);// 创建tcp/udp套接口void create_tcp_sever(int *sockfd, struct sockaddr_in *s_addr);// 注册账号void ero_account_s(const int confd, struct enrollinfo *eninfo, sqlite3 *pdb);// 登录int log_operation(int confd, struct options *option, sqlite3 *pdb);// void chat_start_s(void *args);void chat_start_s(int confd, sqlite3 *pdb);// 套接口操作void *do_use_fd(void *arg);void say_to_one(int confd, struct msg_buff *msg, sqlite3 *pdb);void say_to_all(int confd, struct msg_buff *msg, sqlite3 *pdb);// 保存聊天记录void save_chat_record(struct msg_buff *msg, sqlite3 *pdb);// 添加好友void add_friends(int confd, struct msg_buff *msg, sqlite3 *pdb);// 注册会员修改权限void ero_vip_s(int confd, struct msg_buff *msg, sqlite3 *pdb);int change_permision(int account, sqlite3 *pdb);// 找回密码int search_password(int confd, struct options *option, sqlite3 *pdb);// 禁言,解除(设置权限)void set_someone_per(int confd, int per, int myaccount, int account, sqlite3 *pdb);void tick_out(int confd, int my_account, int account, sqlite3 *pdb);#endif
#include "chat_s.h"void create_tcp_sever(int *sockfd, struct sockaddr_in *s_addr){socklen_t s_len = sizeof(struct sockaddr_in);*sockfd = socket(AF_INET, SOCK_STREAM, 0);if (*sockfd < 0){perror("sockfd creat error:");exit(1);}// 解决无法绑定问题, 重复绑定int opt = 1;setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(s_addr, sizeof(struct sockaddr_in));(*s_addr).sin_family = AF_INET;(*s_addr).sin_port = htons(TCP_PORT);(*s_addr).sin_addr.s_addr = htonl(INADDR_ANY);if (bind(*sockfd, (struct sockaddr *)s_addr, s_len) == -1){perror("bind error:");close(*sockfd);exit(1);}}int main(){int listenfd;int confd;int nfds;int ret;pthread_t chat_id;sqlite3 *pdb;struct sockaddr_in s_addr_tcp;struct sockaddr_in c_addr;socklen_t c_len = sizeof(c_addr);struct epoll_event ev, events[MAX_EVENTS];srand((unsigned)time(NULL));// 创建数据库if (creat_sqlite(&pdb) != SQLITE_OK){sqlite3_close(pdb);exit(1);}// 创建注册人员啊信息表和聊天记录表if (creat_table_chat(pdb) != SQLITE_OK){sqlite3_close(pdb);exit(1);}create_tcp_sever(&listenfd, &s_addr_tcp);listen(listenfd, 1024);while (1){if ((confd = accept(listenfd, (struct sockaddr *)&c_addr, &c_len)) < 0){perror("accept error:");close(listenfd);exit(1);}struct arg args;args.fd = confd;args.pdb = pdb;pthread_create(&chat_id, NULL, do_use_fd, (void *)&args);}close(listenfd);return 0;}
#include "chat_s.h"int creat_sqlite(sqlite3 **pdb){int ret;if((ret = sqlite3_open("chat_room.db", pdb)) != SQLITE_OK){perror("creat sqlite error");exit(1);}return SQLITE_OK;}int creat_table_chat(sqlite3 *pdb){char *sql1 = "create table if not exists chat_account (Account integer primary key, \Nickname text NOT NULL,\Password text NOT NULL,\Permision integer NOT NULL,\Question text,\Answer text,\Fd integer,\STATUtext );";char *sql2 = "create table if not exists chat_record (TIME text,\SEND integer,\RECV integer,\MESG text );";if(creat_table(pdb, sql1) != SQLITE_OK){debug_msg("creat table account error\n");return -1;}if(super_root(pdb)!= SQLITE_OK){sqlite3_close(pdb);exit(1);}if(creat_table(pdb, sql2) != SQLITE_OK){debug_msg("creat table record error\n");return -1;}return SQLITE_OK;}int creat_table(sqlite3 *pdb, char *sql){int ret;char *errmsg = NULL;if((ret = sqlite3_exec(pdb, sql, NULL, NULL,&errmsg)) != SQLITE_OK){perror("creat table error:");return -1;} return SQLITE_OK;}int super_root(sqlite3 *pdb){int ret;char *errmsg;char *sql = NULL;sql = "insert OR IGNORE into chat_account (Account, Nickname, Password, Permision) values (10000, 'root', 'admin', 4);";if((ret = sqlite3_exec(pdb, sql, NULL, NULL,&errmsg)) != SQLITE_OK){perror("insert root error:");printf("%s\n",errmsg);return -1;}return SQLITE_OK;}//客户端上线更新fdint update_sqlite3_fd(int confd, int account,sqlite3 *pdb){char sql[SQL_SIZE];char *errmsg = NULL;sprintf(sql,"update chat_account set Fd = %d,STATU = 'online' where Account = %d;", confd, account);if(sqlite3_exec(pdb,sql,NULL,NULL,&errmsg) != SQLITE_OK){debug_msg("%s\n",errmsg);return -1;}return SQLITE_OK;}int update_sqlite3_statu(int account,sqlite3 *pdb){char sql[SQL_SIZE];char *errmsg = NULL;sprintf(sql,"update chat_account set STATU = 'notonline',Fd = -1 where Account = %d;",account);debug_msg("update account %d\n",account);if(sqlite3_exec(pdb,sql,NULL,NULL,&errmsg) != SQLITE_OK){debug_msg("%s\n",errmsg);return -1;}return SQLITE_OK;}
#include "chat_s.h"void *do_use_fd(void *arg){struct options option;struct arg args;pthread_t chat_id;int bytes_read;int account;struct arg tmp = *((struct arg *)arg);int confd = tmp.fd;sqlite3 *pdb = tmp.pdb;memset(&option, 0, sizeof(option));while (1){if (bytes_read = read(confd, &option, sizeof(option)) account = rand() % 100000 + 100000;sprintf(sql, "insert into chat_account (Account, Nickname, Password, Permision, Question, Answer, Fd, STATU) \values (%d, '%s', '%s', 1, '%s', '%s', %d, 'notonline');",eninfo->account, eninfo->nickname, eninfo->password, eninfo->sc_protect, eninfo->answer, confd);while (sqlite3_exec(pdb, sql, NULL, NULL, &errmsg) != SQLITE_OK){debug_msg("insert new account error:%s\n", errmsg);if (0 == strcmp(errmsg, "UNIQUE constraint failed: chat_count.Account")){eninfo->account = rand() % 100000 + 100000;sprintf(sql, "insert into chat_account (Account, Nickname, Password, Permision, Question, Answer, IP, STATU) \values (%d, '%s', '%s', 1, '%s', '%s', %d, 'notonline');",eninfo->account, eninfo->nickname, eninfo->password, eninfo->sc_protect, eninfo->answer, confd);sqlite3_free(errmsg);}else{debug_msg("insert new account error:%s\n", errmsg);return;}}write(confd, &eninfo->account, sizeof(int));return;}// 登录操作int log_operation(int confd, struct options *option, sqlite3 *pdb){char sql[SQL_SIZE];char **presult = NULL;char *errmsg = NULL;int row, col;sprintf(sql, "select Account,Password from chat_account \where Account = %d AND Password = '%s';",option->info.loginfo.account, option->info.loginfo.password);if (sqlite3_get_table(pdb, sql, &presult, &row, &col, &errmsg) != SQLITE_OK){perror("log error:");sqlite3_free_table(presult);sqlite3_free(errmsg);return -1;}if (0 == row){debug_msg("no account\n");write(confd, "failed", strlen("failed"));return -1;}else{write(confd, "success", strlen("success"));}if (update_sqlite3_fd(confd, option->info.loginfo.account, pdb) info.fgpwd_account);sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg);if (0 == row){write(confd, SEARCH_ERROR, strlen(SEARCH_ERROR));return -1;}strcpy(buff, result[1]);write(confd, buff, sizeof(buff));sqlite3_free_table(result);result = NULL;read(confd, buff, sizeof(buff));sprintf(sql, "select Answer from chat_account where account = %d;", option->info.fgpwd_account);sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg);if (0 == strcmp(buff, result[1])){sprintf(sql, "select Password from chat_account where account = %d;", option->info.fgpwd_account);sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg);strcpy(buff, result[1]);write(confd, buff, sizeof(buff));}else{write(confd, PED_ERROR, sizeof(PED_ERROR));}return SQLITE_OK;}
#include "chat_s.h"// 查找所有在线好友void search_all_fd(int account, int stat, sqlite3 *pdb){char sql[SQL_SIZE];char **result = NULL;char *errmsg = NULL;int row, col;struct msg_buff msg;memset(&msg, 0, sizeof(msg));sprintf(sql, "select Account,Fd from chat_account where STATU = 'online' and Account != %d;", account);if (SQLITE_OK != sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg)){debug_msg("chat_s %d%s\n", __LINE__, errmsg);sqlite3_free(errmsg);return;}if (0 == row){debug_msg("no account\n");return;}msg.my_account = account;for (int i = col; i < (row + 1) * col; i++){if (i % row == 0 && i + 1 < (row + 1) * col){msg.mushin_flag = stat;debug_msg("online account:%dfd:%d\n", account, atoi(result[i + 1]));write(atoi(result[i + 1]), &msg, sizeof(msg));}}sqlite3_free_table(result);}// 查询权限int query_permision(const int account, sqlite3 *pdb){char sql[SQL_SIZE];char **result = NULL;char *errmsg = NULL;int row, col;int per;sprintf(sql, "select Permision from chat_account where Account = %d;", account);if (sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg) != SQLITE_OK){debug_msg("chat_s %d%s\n", __LINE__, errmsg);sqlite3_free(errmsg);return -2;}per = atoi(result[1]);return per;}void chat_start_s(int confd, sqlite3 *pdb){int bytes_read;int account;int a[100][2];int per;char buff[100];struct msg_buff msg;memset(buff, 0, sizeof(buff));memset(&account, 0, sizeof(int));memset(&per, 0, sizeof(int));memset(a, 0, sizeof(a));#if 1read(confd, &account, sizeof(int));per = query_permision(account, pdb);write(confd, &per, sizeof(int));#endif#if 1// 好友上线提醒search_all_fd(account, ONLINE, pdb);#endifwhile (1){memset(&msg, 0, sizeof(msg));if ((bytes_read = read(confd, &msg, sizeof(msg))) <= 0){if (bytes_read < 0){perror("read error");}if (0 == bytes_read){debug_msg("client offline\n");if (SQLITE_OK != update_sqlite3_statu(account, pdb)){printf("update stat error\n");}close(confd);}}switch (msg.chat_mode){case STOA:say_to_one(confd, &msg, pdb);break;case STOO:say_to_all(confd, &msg, pdb);break;case ADD:add_friends(confd, &msg, pdb);break;case VIP:ero_vip_s(confd, &msg, pdb);break;case MUS:set_someone_per(confd, 0, msg.my_account, msg.account[0], pdb);break;case CANCLE:set_someone_per(confd, 1, msg.my_account, msg.account[0], pdb);break;case OUT:tick_out(confd, msg.my_account, msg.account[0], pdb);break;case EXIT:if (SQLITE_OK != update_sqlite3_statu(account, pdb)){printf("update stat error\n");}debug_msg("chat_s %d offline\n", confd);search_all_fd(account, OFFLINE, pdb);//好友下线提醒close(confd);pthread_exit(NULL);return;default:break;}}}// 判断发送者的Permision是否小于1int is_smaller_sp(const int account, sqlite3 *pdb){int per = query_permision(account, pdb);if (per my_account, pdb);if (ret mushin_flag = MUSHIN;write(confd, msg, sizeof(struct msg_buff));return;}else{// 查找聊天对象fdfor (int i = 0; i num; i++){ret = search_friend_fd(msg->account[i], pdb);if (ret mushin_flag = NOT_ONLINE;write(confd, msg, sizeof(struct msg_buff));continue;}write(ret, msg, sizeof(struct msg_buff));if (msg->option == MSG || msg->option == EXP){save_chat_record(msg, pdb);}}}}void say_to_one(int confd, struct msg_buff *msg, sqlite3 *pdb){int ret;char sql[SQL_SIZE];char name[NICKNAME_SIZE];// 判断发送者的Permision是否小于1ret = is_smaller_sp(msg->my_account, pdb);if (ret mushin_flag = MUSHIN;write(confd, msg, sizeof(struct msg_buff));return;}else{// 查找聊天对象fdret = search_friend_fd(msg->account[0], pdb);if (ret mushin_flag = NOT_ONLINE;write(confd, msg, sizeof(struct msg_buff));return;}write(ret, msg, sizeof(struct msg_buff));if (msg->option == MSG || msg->option == EXP){save_chat_record(msg, pdb);}}}int search_friend(int account, char name[NICKNAME_SIZE], sqlite3 *pdb){char sql[SQL_SIZE];char **result = NULL;char *errmsg = NULL;int row, col;sprintf(sql, "select Nickname from chat_account where Account = %d;", account);if (SQLITE_OK != sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg)){debug_msg("chat_s %d%s\n", __LINE__, errmsg);sqlite3_free(errmsg);return -1;}if (0 == row){debug_msg("no account\n");return -1;}strcpy(name, result[1]);sqlite3_free_table(result);return 0;}void add_friends(int confd, struct msg_buff *msg, sqlite3 *pdb){char name[NICKNAME_SIZE];memset(name, 0, sizeof(name));debug_msg("here\n");debug_msg("add%d\n", msg->account[0]);if (search_friend(msg->account[0], name, pdb) != 0){debug_msg("here1\n");write(confd, NO_FRIEND, sizeof(NO_FRIEND));return;}else{debug_msg("here2\n");write(confd, name, sizeof(name));}}int change_permision(int account, sqlite3 *pdb){char sql[SQL_SIZE];char *errmsg = NULL;sprintf(sql, "update chat_account set Permision = 3 where Account = %d;", account);if (sqlite3_exec(pdb, sql, NULL, NULL, &errmsg) != SQLITE_OK){debug_msg("%s\n", errmsg);return -1;}return SQLITE_OK;}void ero_vip_s(int confd, struct msg_buff *msg, sqlite3 *pdb){char buff[100];memset(buff, 0, sizeof(buff));if (msg->mushin_flag == VIP){write(confd, PAY, sizeof(PAY));read(confd, buff, sizeof(buff));if (0 == strcmp(buff, PAY_SUCCED)){change_permision(msg->my_account, pdb);write(confd, ERO_VIP, sizeof(ERO_VIP));}}return;}void set_someone_per(int confd, int per, int myaccount, int account, sqlite3 *pdb){char sql[SQL_SIZE];char *errmsg = NULL;if (query_permision(account, pdb)  3){sprintf(sql, "update chat_account set Permision = %d where Account = %d;", per, account);if (sqlite3_exec(pdb, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("set permision error:%s\n", errmsg);sqlite3_free(errmsg);return;}write(confd, "操作成功", strlen("操作成功"));}else{write(confd, "操作失败", strlen("操作失败"));}}void save_chat_record(struct msg_buff *msg, sqlite3 *pdb){char sql[SQL_SIZE];char *errmsg;for (int i = 0; i num; i++){sprintf(sql, "insert into chat_record (TIME,SEND,RECV,MESG)\values('%s %s',%d,%d,'%s');",__DATE__, __TIME__, msg->my_account, msg->account[i], msg->chat_opt.chat_msg);if (sqlite3_exec(pdb, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("insert chat record error:%s\n", errmsg);sqlite3_free(errmsg);return;}}}void tick_out(int confd, int myaccount, int account, sqlite3 *pdb){char sql[SQL_SIZE];char *errmsg = NULL;char **result = NULL;int row, col;int fd;struct msg_buff msg;memset(&msg, 0, sizeof(msg));if (query_permision(account, pdb)  3){sprintf(sql, "select Fd from chat_account where Account = %d;", account);if (sqlite3_get_table(pdb, sql, &result, &row, &col, &errmsg) != SQLITE_OK){printf("tick out:%s\n", errmsg);sqlite3_free(errmsg);return;}if (0 == row){write(confd, "查无此人", strlen("查无此人"));return;}else if (1 == row){fd = atoi(result[1]);if (fd > 2){msg.mushin_flag = -2;write(fd, &msg, sizeof(msg));update_sqlite3_fd(0, account, pdb);update_sqlite3_statu(account, pdb);close(fd);}else{write(confd, "操作失败", strlen("操作失败"));return;}}write(confd, "操作成功", strlen("操作成功"));}else{write(confd, "操作失败", strlen("操作失败"));}}

注:存在问题

1.有时候登录会阻塞无法正常显示界面

2.读线程读完消息后,光标不能回到原来位置