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
- Tcp C/S架构实现聊天室(数组管理在线用户)(服务器)
- Tcp C/S架构实现聊天室(链表管理在线用户)(服务器)
- Tcp C/S架构实现聊天室(数组管理在线用户)(客户端)
- Tcp C/S架构实现聊天室(链表管理在线用户)(客户端)
- 聊天室(c/s架构)
- C 版本聊天室 C/S架构——服务器程序
- 聊天室 1.0 (TCP协议)服务器
- Android实现C/S聊天室
- TCP C/S 聊天室项目初篇
- unix 服务器篇之基本 Tcp c/s架构
- 基于C/S架构的网络聊天室
- Android 网络:基于TCP协议通信,多线程,实现简单的C/S聊天室
- 实现在同一台服务器上登录的ssh用户的群聊(聊天室)功能
- 采用TCP协议的C/S架构实现API详解
- Linux下TCP协议的C/S架构实现
- Asp.Net制作聊天室(显示在线用户列表,禁止发言,允许发言,踢出聊天室,退出聊天室)
- TCP/IP Scoket编程之UDP聊天室(C语言实现)
- C# 异步TCP Socket聊天室(1服务器,N客户端)
- Python正则表达式指南
- 假期训练——OpenJ_Bailian - 2745 显示器 模拟
- Codeforces 604B - Alan Wake(二分)
- 使用spring-data-jpa的JpaRepository来进行类的db操作(配置)
- POJ 2488 A Knight's Journey (dfs)
- Tcp C/S架构实现聊天室(数组管理在线用户)(服务器)
- 【Android开发】App版本号
- 基于范德蒙矩阵的Erasure code技术详解
- 假期训练——OpenJ_Bailian - 1833 排列 全排序
- hadoop中使用java.util.ServiceLoader
- 调整数组顺序使奇数位于偶数前面
- 查找单词是否存在于单词表格中
- github的命令总结
- 2.0 STL泛型编程