您的位置:首页 > 理论基础 > 计算机网络

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

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

/*********************************************************************
File Name: tcp_net_socket.h
Author: 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 log 2 //登录
#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_no 82 //不接受
#define file_select 18 //文件选择
#define file_recv 83 //文件接收
#define online_member 20 //查看在线人数
#define online_result 21 //在线人数结果
#define expression 25 //表情
#define e_select 26 //发送表情选择
#define phrases 29 //常用语
#define p_select 31 //发送常用语选择
#define motto 35 //个性签名
#define like 40 //点赞
#define Vip 38 //开会员
#define Shutup 45 //禁言
#define Shutuped 46 //被禁言
#define lifted 50 //解禁
#define kick 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 Exit 12 //退出
#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
10202
>
/*********************************************************************
File Name:               tcp_net_socket.c
Author:                         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);     //申请新的socket
if(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连接至指定的服务器网络地址 serveraddr
if(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: