Tcp C/S架构实现聊天室(数组管理在线用户)(服务器)

来源:互联网 发布:淘宝质量好的杂货铺 编辑:程序博客网 时间:2024/06/04 17:51

  这几天一直在做聊天室,昨天把它做完了,但是服务器是用结构体数组实现的,虽说有些复杂化了,但也是我最开始想到的一种方法,并将之实现了,今天开始做链表来实现管理在线用户,感觉比结构体数组简洁多了。

/*********************************************************************File Name:               tcp_net_socket.hAuthor:                          date:Description:            Fuction List:********************************************************************/#ifndef TCP_NET_SOCKET_H_#define TCP_NET_SOCKET_H_#include <stdio.h>#include <sqlite3.h>#include <sys/types.h>#include <sys/socket.h>#include <string.h>#include <strings.h>#include <stdlib.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <signal.h>#include <pthread.h>#include <semaphore.h>#include <termios.h>#include <time.h>#include <sys/stat.h>#include <fcntl.h>#define SERV_PORT 9000#define reg    1         //注册#define log2  //登录#define group_chat      5         //群聊#define group_result    -6  //群聊接受#define private_chat    10  //私聊#define file_transfer   15  //文件传输对象#define file_confire    80  //文件询问确认接受#define file_yes        81  //接受#define file_no82  //不接受#define file_select     18  //文件选择#define file_recv83  //文件接收#define online_member   20  //查看在线人数#define online_result   21  //在线人数结果#define expression      25  //表情#define e_select        26        //发送表情选择#define phrases         29  //常用语#define p_select        31  //发送常用语选择#define motto35  //个性签名#define like            40        //点赞#define Vip             38        //开会员#define Shutup          45        //禁言#define Shutuped        46  //被禁言#define lifted          50  //解禁#definekick            55        //踢人#define kicked          56  //被踢下线#define exit            100  //退出#define existing_acc    -1  //账号已存在#define logged_acc      -2        //账号已登录#define error           -3    //账号或密码错误#define error1          -4  //重复登录#define log_success     3  //登录成功#define reg_success     4  //注册成功#define Send_success    6         //发送信息成功#define Send_error      7         //发送信息失败#define send_msg        8         //发送信息#define recv_msg        9         //接受信息#define send_result    11        //发送结果#define Exit12  //退出#define kick_fail       16        //踢人失败#define kick_success    17        //踢人成功#define like_success    13        //点赞成功#define file_success    14        //文件传输成功#define motto_change    19  //更改个性签名#define forget          60  //忘记密码extern int tcp_init();extern int tcp_accept(int sfd);extern int tcp_connet();extern void signalhandler(void);extern int mygetch();extern int gettime();extern char* nowtime();#endif
/*********************************************************************File Name:               tcp_net_socket.cAuthor:                         date:Description:            Fuction List:int tcp_init() //用于初始化操作int tcp_accept(int sfd)//用于服务器的接收int tcp_connect(const char* ip)//用于客户端的连接void signalhandler(void)//用于信号处理,让服务器在按下Ctrl+c或Ctrl+\时不会退出********************************************************************/#include "tcp_net_socket.h"//用于初始化操作int tcp_init()  {int sfd = socket(AF_INET, SOCK_STREAM, 0);     //创建套接字if(sfd == -1){perror("socket");return -1;}int ret;struct sockaddr_in serveraddr;memset(&serveraddr,0,sizeof(struct sockaddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(SERV_PORT);serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);ret = bind(sfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr));if(ret == -1){perror("bind");return -1;}ret = listen(sfd,10);           //监听它,并设置允许最大的连接数为10个if(ret == -1){perror("listen");close(sfd);return -1;}return sfd;}//用于服务器的接收int tcp_accept(int sfd){struct sockaddr_in clientaddr;memset(&clientaddr, 0, sizeof(struct sockaddr));int addrlen = sizeof(struct sockaddr);//sfd接受客户端的连接,并创建新的socket为new_fd,将请求连接的客户端的ip、port保存在结构体clientaddr中int new_fd = accept(sfd, (struct sockaddr*)&clientaddr, &addrlen);       if(new_fd == -1){perror("accept");close(sfd);return -1;}printf("%s %d success connet...\n", inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));return new_fd;}//用于客户端的连接int tcp_connect(const char* ip){int ret;int sfd = socket(AF_INET, SOCK_STREAM, 0);     //申请新的socketif(sfd == -1){perror("socket");return -1;}struct sockaddr_in serveraddr;memset(&serveraddr, 0,sizeof(struct sockaddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(SERV_PORT);serveraddr.sin_addr.s_addr = inet_addr(ip);    ret = connect(sfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr));       //将sfd连接至指定的服务器网络地址 serveraddrif(ret == -1){perror("connect");close(sfd);return -1;}return sfd;}//用于信号处理,让服务器在按下Ctrl+c或Ctrl+\时不会退出void signalhandler(void){sigset_t sigSet;sigemptyset(&sigSet);sigaddset(&sigSet,SIGINT);sigaddset(&sigSet,SIGQUIT);sigprocmask(SIG_BLOCK,&sigSet,NULL);}//用于将密码数字转换为*int mygetch( ){struct termios oldt,newt;int ch;tcgetattr( STDIN_FILENO, &oldt );newt = oldt;newt.c_lflag &= ~( ICANON | ECHO );tcsetattr( STDIN_FILENO, TCSANOW, &newt );ch = getchar();tcsetattr( STDIN_FILENO, TCSANOW, &oldt );return ch;}//获取当前时间 int gettime(){time_t rawtime;struct tm * timeinfo;time ( &rawtime );timeinfo = localtime ( &rawtime );printf ( "%s",asctime (timeinfo) );}//获取当前时间   指针 用于消息记录char* nowtime(){time_t rawtime;struct tm * timeinfo;time ( &rawtime );timeinfo = localtime ( &rawtime );return asctime (timeinfo);}

#include "tcp_net_socket.h"struct send{int socket;char account[20];         //账号char passward[20];        //密码char name[20];            //名字char moto[256];   //个性签名int  likes;              //点赞数char question[100];  //密保问题char answer[100];  //密保答案char toname[20];          //接收人int cmd;              //提取操作符char buff[2048];       //发送、接收文件   消息int state;               //是否处于禁言状态int vip;  //是否是会员char e_s;                 //确认发送的表情char p_s;                 //确认发送的常用语char file[2048];          //发送文件存的数据char file_name[30];  //文件名};struct state{int flag[50];             //判断用户有没有登录  1为登录 0未登录struct send user[50];};struct recv{char from_name[20];  //发信人char name[20];            //名字char moto[256];   //个性签名int result;              //返回操作结果int online_num;          //在线人数char num[20][20];      //在线人名char cuff[2048];       //发送、接收文件   消息int cmd_back;             //提取操作符int  likes;              //点赞数int state;               //是否处于禁言状态int vip;  //是否是会员int msg_back;             //确认是接收方还是发送方char e_s;                 //确认发送的表情char p_s;                 //确认发送的常用语char file[2048];          //发送文件存的数据char file_name[30];  //文件名char question[100];  //密保问题char answer[100];  //密保答案char passward[20];        //密码};struct send userInfo;struct recv userBack;struct state userMge;pthread_mutex_t mutex;sqlite3 * db = NULL;//基础信息存放数据库int temp = 0;int i;//保存用户void save_user(){pthread_mutex_lock(&mutex);int ret;char *errmsg = NULL;char auff[200] = {0}; char cuff[200] = {0};sprintf(auff, "insert into save_user values('%s','%s','%s','%s',%d,%d)",userInfo.account, userInfo.passward, userInfo.name, userInfo.moto, userInfo.likes, userInfo.vip);ret = sqlite3_exec(db, auff, NULL, NULL, &errmsg);if(ret != SQLITE_OK){printf("insert fail:%d(%s)\n", ret, errmsg);userBack.result = existing_acc;  //账号已存在pthread_mutex_unlock(&mutex);return;}printf("sqlite save_user insert success...\n");sprintf(cuff,"insert into question values('%s','%s','%s','%s')", userInfo.account, userInfo.passward, userInfo.question, userInfo.answer);ret = sqlite3_exec(db, cuff, NULL, NULL, &errmsg);if(ret != SQLITE_OK){printf("insert fail:%d(%s)\n", ret, errmsg);pthread_mutex_unlock(&mutex);return;}userBack.result = reg_success;                 //注册成功userBack.state = userInfo.state;pthread_mutex_unlock(&mutex);}//登录检查表和客户端发来的数据对比void deal_log(int cfd){pthread_mutex_lock(&mutex);char **resultp = NULL;int nrow;int ncolumn;int ret;int i;char *errmsg = NULL;char cuff[200];userInfo.socket = cfd;sprintf(cuff, "select account,passward,name,moto,likes,vip from save_user where account = '%s' and passward = '%s'", userInfo.account, userInfo.passward);ret = sqlite3_get_table(db, cuff, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("log error : %d(%s)!\n", ret, errmsg);return;}if(nrow == 1){userBack.result = log_success;    //登录成功strcpy(userBack.name, resultp[8]);strcpy(userBack.moto, resultp[9]);userBack.likes = *(resultp[10]) - 48;userBack.vip = *(resultp[11]) - 48;printf("%s logged success...\n", resultp[8]);for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, resultp[8]) == 0){userBack.result = error1;          //重复登录return;}}for(i = 0; i < 50; i++){if(userMge.flag[i] == 1){continue;}userMge.flag[i] = 1;userMge.user[i].socket = cfd;strcpy(userMge.user[i].name, resultp[8]);break;}}else{userBack.result = error;          //账号密码错误}pthread_mutex_unlock(&mutex);}//忘记密码void deal_forget(int cfd){pthread_mutex_lock(&mutex);char auff[100];char **resultp = NULL;int nrow;int ncolumn;int ret;char *errmsg = NULL;sprintf(auff, "select passward, question, answer from question where account = '%s'", userInfo.account);ret = sqlite3_get_table(db, auff,  &resultp, &nrow, &ncolumn, &errmsg);if(ret != SQLITE_OK){printf("select error fail:%d(%s)\n", ret, errmsg);}strcpy(userBack.passward, resultp[3]);strcpy(userBack.question, resultp[4]);strcpy(userBack.answer, resultp[5]);ret = write(cfd, &userBack, sizeof(userBack));if(ret == -1){perror("write");return;}pthread_mutex_unlock(&mutex);}//处理私聊请求int deal_pchar(int cfd){pthread_mutex_lock(&mutex);int ret;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.toname) == 0 && cfd != userMge.user[i].socket){temp = 1;strcpy(userBack.cuff, userInfo.buff);strcpy(userBack.from_name, userInfo.name);userBack.msg_back = recv_msg;ret = write(userMge.user[i].socket,&userBack, sizeof(userBack));if(ret == -1){perror("write");return;}printf("%s send a message to %s...\n", userInfo.name, userInfo.toname);break;}}if(temp == 0){userBack.msg_back = send_result;userBack.result = Send_error;ret = write(cfd,&userBack, sizeof(userBack));if(ret == -1){perror("write");return;}printf("%s send error...\n", userInfo.name);}pthread_mutex_unlock(&mutex);}//处理踢人请求int deal_kick(int cfd){pthread_mutex_lock(&mutex);int temp = 0;int ret;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.toname) == 0 && cfd != userMge.user[i].socket){temp = 1;strcpy(userBack.from_name,userInfo.name);userBack.msg_back = kick;ret = write(userMge.user[i].socket,&userBack,sizeof(userBack));if(ret == -1){perror("write");return -1;}}}if(temp){userBack.msg_back = kick_success;ret = write(cfd,&userBack,sizeof(userBack));if(ret == -1){perror("write");return -1;}}else{userBack.msg_back = kick_fail;ret = write(cfd,&userBack,sizeof(userBack));if(ret == -1){perror("write");return -1;}}pthread_mutex_unlock(&mutex);}//处理点赞请求int deal_like(int cfd){pthread_mutex_lock(&mutex);int ret;int i;char *errmsg = NULL;char **resultp = NULL;int nrow;int ncolumn;char cuff[200];sprintf(cuff, "select likes from save_user where name = '%s'", userInfo.name);ret = sqlite3_get_table(db, cuff, &resultp, &nrow, &ncolumn, &errmsg);if(ret != SQLITE_OK){printf("select fail:%d(%s)\n", ret, errmsg);return -1;}sprintf(cuff, "update save_user set likes = %d where name = '%s'",*(resultp[1]) - 47, userInfo.name);ret = sqlite3_exec(db, cuff, NULL, NULL, &errmsg);if(ret != SQLITE_OK){printf("update fail:%d(%s)\n", ret, errmsg);return -1;}for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.toname) == 0 && cfd != userMge.user[i].socket){userMge.user[i].likes = *(resultp[1]) - 47;userBack.likes = *(resultp[1]) - 47;userBack.msg_back = like_success;strcpy(userBack.from_name,userInfo.name);ret = write(userMge.user[i].socket, &userBack, sizeof(userBack));if(ret == -1){perror("write");return -1;}break;}}printf("like success...\n");pthread_mutex_unlock(&mutex);}//处理禁言请求int deal_Shutup(int cfd){pthread_mutex_lock(&mutex);int ret;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.toname) == 0 && cfd != userMge.user[i].socket){userBack.state = Shutup;strcpy(userBack.from_name, userInfo.name);userBack.msg_back = Shutup;ret = write(userMge.user[i].socket, &userBack,sizeof(userBack));if(ret == -1){perror("write");return;}break;}}printf("shutup success...\n");pthread_mutex_unlock(&mutex);}/* //处理解禁要求int deal_lifted(int cfd){pthread_mutex_lock(&mutex);int ret;printf("解禁\n");for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userInfo.name, userMge.user[i].name) == 0){printf("解禁成功\n");userMge.user[i].state = 0;userBack.state = 0;userBack.msg_back = lifted;ret = write(cfd, &userBack, sizeof(userBack));if(ret == -1){perror("write");return -1;}break;}}pthread_mutex_unlock(&mutex);} *///处理查看在线人数int deal_member(int cfd){pthread_mutex_lock(&mutex);int ret;userBack.online_num = 0;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1){userBack.online_num++;strcpy(userBack.num[i],userMge.user[i].name);}}userBack.msg_back = online_member;ret = write(cfd,&userBack,sizeof(userBack));if(ret == -1){perror("write");return -1;}printf("show online_member success...\n");pthread_mutex_unlock(&mutex);}//处理群聊请求int deal_groupchat(int cfd){pthread_mutex_lock(&mutex);int ret;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && userMge.user[i].socket != cfd){userBack.msg_back = group_chat;strcpy(userBack.cuff,userInfo.buff);strcpy(userBack.from_name, userInfo.name);ret = write(userMge.user[i].socket,&userBack,sizeof(userBack));if(ret == -1){perror("write");return -1;}}}printf("%s group_chat success...\n");pthread_mutex_unlock(&mutex);}//处理发送表情int deal_expression(int cfd){pthread_mutex_lock(&mutex);int ret;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.toname) == 0 && cfd != userMge.user[i].socket){strcpy(userBack.from_name, userInfo.name);userBack.e_s = userInfo.e_s;userBack.msg_back = e_select;ret = write(userMge.user[i].socket, &userBack, sizeof(userBack));if(ret == -1){perror("write");return -1;}printf("send expression success...\n");break;}}pthread_mutex_unlock(&mutex);}//处理发送常用语int deal_phrases(int cfd){pthread_mutex_lock(&mutex);int ret;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.toname) == 0 && cfd != userMge.user[i].socket){strcpy(userBack.from_name,userInfo.name);userBack.p_s = userInfo.p_s;userBack.msg_back = p_select;ret = write(userMge.user[i].socket, &userBack, sizeof(userBack));if(ret == -1){perror("write");return -1;}printf("send phrases success...\n");break;}}pthread_mutex_unlock(&mutex);}//处理文件传输int deal_file_transfer(int cfd){pthread_mutex_lock(&mutex);int ret;for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.toname) == 0 && cfd != userMge.user[i].socket){userBack.msg_back = file_transfer;strcpy(userBack.from_name, userInfo.name);strcpy(userBack.file, userInfo.file);strcpy(userBack.file_name, userInfo.file_name);ret = write(userMge.user[i].socket, &userBack, sizeof(userBack));if(ret == -1){perror("write");return -1;}}}pthread_mutex_unlock(&mutex);}//服务器响应请求void *server_requst(int cfd){int ret;char *errmsg = NULL;while(read(cfd, &userInfo, sizeof(userInfo))){switch (userInfo.cmd){case (reg):                //注册{save_user(db);printf("%s insert success...!\n", userInfo.name);ret = write(cfd, &userBack, sizeof(userBack));if(ret == -1){perror("write");return;}break;}case (log):                //登陆{deal_log(cfd);ret = write(cfd, &userBack, sizeof(userBack));if(ret == -1){perror("write");return;}break;}case (forget)://忘记密码{deal_forget(cfd);break;}case (group_chat):            //群聊{deal_groupchat(cfd);break;}case (private_chat):          //私聊{deal_pchar(cfd);break;}case (file_transfer):    //文件传输{deal_file_transfer(cfd);break;}case (online_member):         //查看在线人数{deal_member(cfd);break;}case (expression):            //表情{deal_expression(cfd);break;}case (phrases):               //常用语{deal_phrases(cfd);break;}case (like)://点赞{deal_like(cfd);break;}case (Vip):                     //注册vip{char guff[200];sprintf(guff, "update save_user set vip = %d where name = '%s'", userInfo.vip, userInfo.name);ret = sqlite3_exec(db,guff,NULL,NULL,&errmsg);if(ret == -1){printf("update fail:%d(%s)\n", ret, errmsg);return;}userBack.vip = 1;userBack.msg_back = 0;ret = write(cfd, &userBack,sizeof(userBack));if(ret == -1){perror("write");return;}break;}case (Shutup)://禁言{deal_Shutup(cfd);break;}/* case (lifted)://解禁{deal_lifted(cfd);break;} */case (kick): //踢人{deal_kick(cfd);break;}case (Exit)://退出{for(i = 0; i < 50; i++){if(userMge.flag[i] == 1 && strcmp(userMge.user[i].name, userInfo.name) == 0){userMge.flag[i] = 0;}}ret = write(cfd, &userBack,sizeof(userBack));if(ret == -1){perror("write");return;}printf("%s log out...\n");break;}case (motto_change):{char xcf[60];sprintf(xcf, "update save_user set moto = '%s' where name = '%s'",userInfo.moto,userInfo.name);ret = sqlite3_exec(db,xcf,NULL,NULL,&errmsg);if(ret == -1){printf("update fail:%d(%s)\n", ret, errmsg);return;}strcpy(userBack.moto, userInfo.moto);ret = write(cfd, &userBack,sizeof(userBack));if(ret == -1){perror("write");return;}break;}default :{break;}}}}int main(){int sfd;int ret;sfd = tcp_init();pthread_mutex_init(&mutex, NULL);// signalhandler();char *errmsg = NULL;ret = sqlite3_open("user.db",&db);if(ret != SQLITE_OK){perror("open user.db error");return -1;}printf("open user.db success...\n");ret = sqlite3_exec(db, "create table if not exists save_user(account TEXT, passward TEXT, name TEXT, moto TEXT, likes INTEGER, vip INTEGER, primary key(account))",NULL,NULL,&errmsg);if(ret != SQLITE_OK){printf("create fail:%d(%s)\n", ret, errmsg);return -1;}printf("create save_user success...\n");ret = sqlite3_exec(db, "create table if not exists question(account TEXT, passward TEXT, question TEXT, answer TEXT, primary key(account))", NULL, NULL, &errmsg);if(ret !=SQLITE_OK){printf("creat fail:%d(%s)\n",ret,errmsg);return -1;}for(i = 0; i < 50; i++){userMge.flag[i] = 0;}pthread_t clientid;while(1){int cfd;cfd = tcp_accept(sfd);if(cfd == -1){perror("accept");return -1;}ret = pthread_create(&clientid, NULL, (void*)server_requst, (void*)cfd);if(ret == -1){perror("pthread create");return -1;}pthread_detach(clientid); // 线程分离pthread_join(clientid, NULL);}sqlite3_close(db);pthread_mutex_destroy(&mutex);return 0;}



0 0
原创粉丝点击