LinuxC TCP实现简易聊天室
一只快乐的哈士奇 2024-06-20 11:07:04 阅读 57
目录
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 <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/epoll.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <netinet/in.h>#include <ctype.h>#include <sys/socket.h>#include <arpa/inet.h>#include <pthread.h>#include <sqlite3.h>#include <errno.h>#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 create_tcp_client(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); } 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 = inet_addr(IPADDR);}int main(){ int sockfd_tcp; sqlite3 *pdb; struct sockaddr_in s_addr_tcp; // 创建数据库 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_client(&sockfd_tcp, &s_addr_tcp); if (connect(sockfd_tcp, (struct sockaddr *)&s_addr_tcp, sizeof(s_addr_tcp)) < 0) { perror("connect error"); exit(1); } user_options(sockfd_tcp, pdb); close(sockfd_tcp); sqlite3_close(pdb); return 0;}
#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); } else printf("\033[%dC你的密码是:> %s\n", CTRL1 + 4, buff); printf("\033[u");}
#include "chat_c.h"void chat_start_c(int confd, struct options *option, sqlite3 *pdb){ pthread_t tid_read; pthread_t tid_write; FILE *fp = fopen("chat_record.text", "a"); struct cp arg; memset(&arg, 0, sizeof(arg)); arg.confd = confd; arg.pdb = pdb; arg.account = option->info.loginfo.account; arg.fp = fp; if (pthread_create(&tid_read, NULL, (void *)read_thread, (void *)&arg) < 0) { perror("thread read error:"); exit(1); } if (pthread_create(&tid_write, NULL, (void *)write_thread, (void *)&arg) < 0) { perror("thread read error:"); exit(1); } pthread_join(tid_write, NULL); pthread_cancel(tid_read); return;}
#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 into chat_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"); // 查看自己是否是vip chat_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 < 1) { return; } msg->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 < num; i++) { memset(name, 0, sizeof(name)); printf("\033[%dC请输入聊天好友:>\033[K", CTRL3 + 2); scanf("%s", name); ret = search_account(msg, name, pdb); if (ret < 1) { return; } msg->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 < (row * col) + 2; i++) { printf("%-4s", result[i]); if ((i + 1) % 2 == 0) { if ((i - 1) % 4 == 0) { printf("\n"); printf("\033[%dC", CTRL3 + 4); } else printf(" "); } } printf("\n"); printf("\033[u");}// 查询本地表情库int find_exp(struct msg_buff *msg, int id, sqlite3 *pdb){ int row, col; char *errmsg = NULL; char sql[SQL_SIZE]; char **presult = NULL; sprintf(sql, "select exp from expression where id = %d;", id); if (sqlite3_get_table(pdb, sql, &presult, &row, &col, &errmsg) != SQLITE_OK) { debug_msg("find exp error:%s\n", errmsg); printf("查找失败:\n"); sqlite3_free(errmsg); return -1; } if (0 == row) { sqlite3_free_table(presult); printf("输入错误\n"); return -1; } else { strcpy(msg->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 < 1) { return; } msg->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 < num; i++) { memset(name, 0, sizeof(name)); printf("\033[%dC请输入聊天好友:>\033[K", CTRL3 + 2); scanf("%s", name); ret = search_account(msg, name, pdb); if (ret < 1) { return; } msg->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) < 0) { printf("\033[%dC添加好友失败!!\n", CTRL3 + 6); } else { printf("\033[%dC添加好友成功!!\n", CTRL3 + 6); }}// 删除好友 单方面删除,对面无法知道int delete_friend(sqlite3 *pdb){ char sql[SQL_SIZE]; char *errmsg = NULL; char name[NICKNAME_SIZE]; printf("请输入要删除的好友:>\033[K"); scanf("%s", name); sprintf(sql, "delete from chat_friend where 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 < (row * col) + 2; i++) { printf("%-7s", result[i]); if ((i + 1) % 2 == 0) { printf("\n"); printf("\033[%dC", CTRL3 + 52); } } printf("\n"); printf("\033[u");}// 通过服务器查询自己的权限,更新界面int sure_my_permision(int confd, int account){ int per; write(confd, &account, sizeof(int)); read(confd, &per, sizeof(per)); return per;}// 具有禁言解除禁言踢人操作功能void mush_friend_cancle(int confd, struct msg_buff *msg, sqlite3 *pdb){ char name[NICKNAME_SIZE]; char buff[100]; int ret; memset(buff, 0, sizeof(buff)); printf("\033[u\033[2B\033[10D"); printf("请输入操作的好友:>\033[K"); scanf("%s", name); if ((ret = search_account(msg, name, pdb)) < 0) { printf("\033[%dC查无此人!!]", CTRL3 + 2); printf("\033[u"); return; } msg->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 < 1) { return; } msg->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)) < 0) { debug_msg("file %d\n", ret); sleep(5); return; } msg->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; else msg->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 < num; i++) { memset(name, 0, sizeof(name)); printf("\033[%dC请输入聊天好友:>\033[K", CTRL3 + 2); scanf("%s", name); ret = search_account(msg, name, pdb); if (ret < 1) { return; } msg->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)) < 0) { return; } msg->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; else msg->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) < 0) { printf("error:\n"); } printf("\033[u"); printf("\033[16A\033[16D收到%s的文件:%s(%d)\n", name, msg->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) < 0) { printf("error:\n"); } printf("\033[u"); printf("\033[16A\033[13D%s向你发送了:%s\n", name, msg->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[?25l"); //隐藏光标 printf("\033[2B\033[13D正在登入:"); fflush(stdout); for (i = 0; i < 10; i++) { printf("*"); fflush(stdout); usleep(200000); } printf("\033[?25h"); printf("\n");}
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 <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/epoll.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <netinet/in.h>#include <ctype.h>#include <sys/socket.h>#include <arpa/inet.h>#include <sqlite3.h>#include <time.h>#include <errno.h>#include <pthread.h>#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, \ STATU text );"; 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)) <= 0) { if (bytes_read == 0) { printf("%d offline\n", confd); if (SQLITE_OK != update_sqlite3_statu(option.info.loginfo.account, pdb)) { printf("update stat error\n"); } close(confd); return NULL; } } switch (option.option) { case ERO: ero_account_s(confd, &option.info.eninfo, pdb); break; case LOG: if (log_operation(confd, &option, pdb) != 0) { break; } chat_start_s(confd, pdb); break; case FGPD: search_password(confd, &option, pdb); break; case EXIT: if (SQLITE_OK != update_sqlite3_statu(option.info.loginfo.account, pdb)) { printf("update stat error\n"); } debug_msg("do_use %d offline\n", confd); close(confd); return NULL; break; default: break; } } return NULL;}void ero_account_s(const int confd, struct enrollinfo *eninfo, sqlite3 *pdb){ char sql[SQL_SIZE]; char *errmsg = NULL; debug_msg("ero_account %d", __LINE__); eninfo->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) < 0) { printf("update confd error\n"); } sqlite3_free_table(presult); return 0;}// 找回密码int search_password(int confd, struct options *option, sqlite3 *pdb){ char buff[100]; char sql[SQL_SIZE]; char **result = NULL; char *errmsg = NULL; int row, col; char password[PASSWORD_SIZE]; sprintf(sql, "select Question from chat_account where account = %d;", option->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:%d fd:%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 1 read(confd, &account, sizeof(int)); per = query_permision(account, pdb); write(confd, &per, sizeof(int));#endif#if 1 // 好友上线提醒 search_all_fd(account, ONLINE, pdb);#endif while (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 < 1) { return -1; } return 0;}// 查找聊天好友套接字int search_friend_fd(int account, sqlite3 *pdb){ char sql[SQL_SIZE]; char **result = NULL; char *errmsg = NULL; int row, col; int fd; sprintf(sql, "select Fd 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; } else { fd = atoi(result[1]); } sqlite3_free_table(result); return fd;}void say_to_all(int confd, struct msg_buff *msg, sqlite3 *pdb){ int ret; char sql[SQL_SIZE]; char name[NICKNAME_SIZE]; // 判断发送者的Permision是否小于1 ret = is_smaller_sp(msg->my_account, pdb); if (ret < 0) { msg->mushin_flag = MUSHIN; write(confd, msg, sizeof(struct msg_buff)); return; } else { // 查找聊天对象fd for (int i = 0; i < msg->num; i++) { ret = search_friend_fd(msg->account[i], pdb); if (ret < 0) { msg->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是否小于1 ret = is_smaller_sp(msg->my_account, pdb); if (ret < 0) { msg->mushin_flag = MUSHIN; write(confd, msg, sizeof(struct msg_buff)); return; } else { // 查找聊天对象fd ret = search_friend_fd(msg->account[0], pdb); if (ret < 0) { msg->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 || query_permision(myaccount, 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 < msg->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 || query_permision(myaccount, 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.读线程读完消息后,光标不能回到原来位置
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。