服务器端
#ifndef SERVER_H
#define SERVER_H
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <pthread.h>
#include <signal.h>
#define SIZ 20
#define SIZE 10
#define SIZE1 20 //线程数
#define FAILURE 10000
#define SUCCESS 10001
#define FALSE 10002
#define TRUE 10003
struct sockaddr_in server_addr;//保存服务器信息
enum Enum
{
REG,
LOGIN,
PRIVATE,
GROUP
};
typedef enum Enum ENUM;
/* 定义一个结构体,含有用户的所有信息类型*/
struct user
{
char petname[32]; //昵称
char age[32];
char sex[32];
char key[32];
int cmd; //用户指令
int member; //会员状态
char buf[32]; //文件内容
};
typedef struct user User;
struct judge
{
int cmd; //用户命令
char buf[32]; //文件名
char petname[32]; //昵称
char t2[128]; //发送消息的时间
};
typedef struct judge Judge;
struct info
{
int ToFd; //要发送消息的套接字
char petname[32]; //用户昵称
char ptr[64]; //聊天内容
};
typedef struct info InFo;
int sockfdInit(int sockfd);
int show2(void *para, int columnCount, char **columnValue, char **columnName);
void send0(int fd);
void send1(int fd);
void sendlogin(int fd);
void sendLogin(int fd);
void sendlogin1(int fd);
int count(sqlite3 *pdb);
#endif
/**************************************************************
> File Name: Server.c
> Author: yangxuan
> Mail: [email protected]
> Created Time: 2018年08月23日 星期四 23时23分18秒
**************************************************************/
#include <stdio.h>
#include "Server.h"
#include <time.h>
#include <unistd.h>
//全局变量
char sql[128] = {0}; //存储数据库要用的命令字符串
sqlite3 *pdb; //定义一个sqlite3指针, 指向数据库
int ret; //接受函数调用后的返回值
int sockfd; //定义一个文件描述符,基于ipv4,采用TCP协议的套接字
//char *data = NULL;
//int k = 0;
pthread_mutex_t mutex; //定义pthread_mutex_t 类型的锁,实现线程同步
pthread_cond_t con; //当某些线程在工作时, 有必要让一些线程等待
char buf[32] = {0}; //定义一个buf数组,即时方便的向客户端传递信息
User RecvInfo; //定义一个结构体变量
User T;
int Tofd; //记下被邀请私聊好友的文件描述符
int fdon; //记下私聊发起人的fd
fd_set ReadFd, tmpfd; //定义一个可读集合,中间变量集合
char ptr[32] = {0}; //记下私聊发起人的昵称
int j; //用来计数连了多少客户端 j + 1
int fd[SIZE] = {0};
char reg[32] = {0}; //记下注册好的用户名
int grpfd = 0; //记群聊发起人的fd
int S = 0; //记群聊邀请了几个好友
int groupfd[SIZ]; //群聊最大人数
int receivefd;
int fdcancel;
int fdcheck; //记下私聊记录查询用户的fd
int ID; //用来记录聊天记录中的数据条数
int group;
int a[2];
int I;
char namegroup[32];
int FD;
int count1(void *para, int columnCount, char **columnValue, char **columnName)
{
ID = atoi(*columnValue);
printf("IDID %d\n", ID);
return 0;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:登录时查询该用户是否存在,不存在返回0, 存在返回-1
*/
int select1(void *para, int columnCount, char **columnValue, char **columnName)
{
memset(buf, 0, sizeof(buf));
char buf[32] = {0};
strcpy(buf, columnValue[0]);
if(strcmp(buf, RecvInfo.petname) == 0) //将读取的用户名与数据库查询到的结果比较,若存在返回-1
{
return -1;
}
return 0;
}
/*
作者:杨宣
函数原型:回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:登录时查询该用户密码,正确返回-1, 不正确返回0
*/
int select2(void *para, int columnCount, char **columnValue, char **columnName)
{
char buf[32] = {0};
strcpy(buf, columnValue[0]);
if(strcmp(buf, RecvInfo.key) == 0) //与数据库中查到的密码比较,相同则说明密码正确,返回-1
{
return -1;
}
return 0;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明: 参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:登录时查询该用户是否在线,不在线返回-1, 在线返回0,
*/
int loginfd(void *para, int columnCount, char **columnValue, char **columnName)
{
int a = *columnValue[0] - '0'; //char型数据转换成int型 取值减去0的ASCII码值
if(a == 1) //标志位为 1说明不在线,返回-1
{
return -1;
}
return 0;
}
int filecmd(void *para, int columnCount, char **columnValue, char **columnName)
{
Judge J;
J.cmd = 18;
FILE *fp;
int fd = *(int *)para;
if(columnCount >= 0)
{
strcpy(J.petname, columnValue[0]);
strcpy(J.buf, columnValue[2]);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
fp = fopen(J.buf, "r");
if(fp == NULL)
{
printf("failure");
}
while(1)
{
memset(J.buf, 0, sizeof(J.buf));
ret = fread(J.buf, 1, sizeof(J.buf) - 1, fp);
if(ret == -1)
{
perror("fread failure");
}
if(ret == 0)
{
strcpy(J.buf, "SUCCESS");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
break;
}
else
{
J.cmd = ret;
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
}
fclose(fp);
}
sprintf(sql, "update file set cmd = 2 where namerecv = '%s';", RecvInfo.petname);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("update cmdfile");
}
return 0;
}
/*
作者:杨宣
函数原型:void *pthread(void *arg)
函数说明:带有一个void *型的参数,返回值为void *
函数功能:处理用户登录请求
*/
void *pthreadlogin(void *arg)
{
pthread_detach(pthread_self()); //线程分离,线程运行完自动释放线程
int fd = *(int *)arg; //取出文件描述符
int ret;
User U;
U = RecvInfo;
while(1)
{
memset(sql, 0, sizeof(sql));
sprintf(sql, "select petname from User where petname = '%s';", U.petname); //查找数据库中是否存在该用户
ret = sqlite3_exec(pdb, sql, select1, NULL, NULL);
if(ret == SQLITE_OK) //若不存在发送FALSE 给客户端
{
Judge J;
strcpy(J.petname, U.petname);
printf("12%s\n", U.petname);
J.cmd = 2;
strcpy(J.buf, "FALSE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendlogin1");
}
break;
}
else
{
sprintf(sql, "select key from User where petname = '%s';", U.petname); //若存在,再查找密码是否正确
ret = sqlite3_exec(pdb, sql, select2, NULL, NULL); //若不正确,则发送FAILURE 给客户端
if(ret == SQLITE_OK)
{
Judge J;
strcpy(J.petname, U.petname);
J.cmd = 2;
strcpy(J.buf, "FAILURE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendlogin1");
}
break;
}
else
{
sprintf(sql, "select cmd from User where petname = '%s';", U.petname); //若正确, 再判断该用户是否已在线
ret = sqlite3_exec(pdb, sql, loginfd, NULL, NULL);
if(ret == SQLITE_OK) //若在线,发送TRUE给客户端
{
Judge J;
strcpy(J.petname, U.petname);
J.cmd = 2;
strcpy(J.buf, "TRUE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
else
{
Judge J;
strcpy(J.petname, U.petname);
J.cmd = 2;
strcpy(J.buf, "SUCCESS"); //各种情况排除完毕, 发送SUCCESS给客户端
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendlogin1");
}
T = U;
sprintf(sql, "update User set cmd = '2' where petname = '%s';", U.petname); //更新数据库用户在线状态
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("update");
}
sprintf(sql, "update User set fd = '%d' where petname = '%s';", fd, U.petname); //更新用户登录的客户端fd
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("update");
}
sprintf(sql, "select * from file where cmd = 1 and namerecv = '%s';", U.petname);
ret = sqlite3_exec(pdb, sql, filecmd, &fd, NULL);
if(ret != SQLITE_OK)
{
perror("filecmd");
}
}
break;
}
}
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:用户注册时查找数据库中是否有同名用户,存在返回-1, 不存在返回0
*/
int show(void *para, int columnCount, char **columnValue, char **columnName)
{
Judge J;
J.cmd = 1;
int fd = *(int *)para;
if(columnCount >= 1)
{
strcpy(J.buf, "FAILURE"); //若用户名已存在, 发送FAILURE给客户端
send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("用户名已存在!\n");
}
return -1;
}
return 0;
}
/*
作者:杨宣
指针函数, 函数名pthreadHandle, 含有一个void *的参数, 返回指为void *
函数说明:循环中不断接受文件描述符的信息, 并将其存到结构体中,接收一个将其写入数据库的表中
函数功能:处理用户注册请求
*/
void *pthreadHandle(void *arg)
{
int fd = *(int *)arg; //将主函数的传过来的文件描述符赋给变量
pthread_detach(pthread_self()); //线程分离
sprintf(sql, "select petname from User where petname = '%s';", RecvInfo.petname); //查询数据库中是否存在该用户
ret = sqlite3_exec(pdb, sql, show, &fd, NULL);
if(ret != SQLITE_OK)
{
pthread_mutex_unlock(&mutex);
//printf("select %s\n", sqlite3_errmsg(pdb));
}
else //若不存在,将用户信息插入数据库
{
strcpy(reg, RecvInfo.petname);
sprintf(sql, "insert into User (petname, age, sex, key, cmd, fd, member) values ('%s', '%s', '%s', '%s', '%d', '%d', '%d');", RecvInfo.petname, RecvInfo.age, RecvInfo.sex, RecvInfo.key,RecvInfo.cmd, fd, 0);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
}
send0(fd); //并调用send0()函数发送 SUCCESS给客户端
memset(&RecvInfo, 0, sizeof(RecvInfo)); //读完后需对结构体进行清空,以便下次再读
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:登录时显示在线好友,无好友在线时返回0, 有一个或多个好友在线时返回好友名
*/
int exhibit(void *para, int columnCount, char **columnValue, char **columnName)
{
int fd = *(int *)para;
int i;
Judge J;
for(i = 0; i < columnCount; i++) //将查到的用户名发送给客户端
{
memset(&J, 0, sizeof(J));
J.cmd = 3;
strcpy(J.buf, columnValue[i]);
if(strcmp(J.buf, RecvInfo.petname) != 0)
{
printf("buf %s\n", J.buf);
printf("Recv %s\n", RecvInfo.petname);
ret = send(fd, &J, sizeof(J), 0);
/*if(ret == -1) //else与最近的未配对的if相匹配,得注掉
{
perror("sendp");
}*/
}
else
{
continue;
}
}
return 0; //回调函数return 0不可以少
}
/*
作者:杨宣
函数原型:void *pthreadshow(void *arg)
函数行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端显示当前在线好友请求
*/
void *pthreadshow(void *arg)
{
int fd = *(int *)arg;
char sql[64] = {0};
Judge J;
sprintf(sql, "select petname from User where cmd = '2';"); //采用数据库回调函数,找出cmd 状态为2即登录状态的用户
ret = sqlite3_exec(pdb, sql, exhibit, &fd, NULL);
if(ret != SQLITE_OK)
{
perror("sqlite3show");
}
J.cmd = 3;
strcpy(J.buf, "SUCCESS");
ret = send(fd, &J, sizeof(J), 0);
if(-1 == ret)
{
perror("send");
}
return NULL; // void不应该没有返回?为何会报错控制流程到结尾
}
char dtr[32] = {0};
/*
作者:杨宣
函数原型:void *pthreadexit(void *arg)
函数说明:行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端退出登录请求
*/
void *pthreadexit(void *arg)
{
int fd = *(int *)arg;
Judge J;
printf("exit = %s\n", RecvInfo.petname);
sprintf(sql, "update User set cmd = '1' where petname = '%s';", RecvInfo.petname); //更新客户端用户登录状态
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(SQLITE_OK != ret)
{
J.cmd = 11;
strcpy(J.buf, "FAILURE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
memset(&J, 0, sizeof(J));
perror("sqlite3exit");
}
else
{
J.cmd = 11;
strcpy(J.buf, "SUCCESS");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
memset(&J, 0, sizeof(J));
/*close(fd);
FD_CLR(fd, &ReadFd); //从集合里面清除
fd= 0;*/
}
sprintf(sql, "update User set fd = '0' where petname = '%s';", RecvInfo.petname); //更新客户端设备的文件描述符号
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("sqlite3_exec");
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:查找被邀请好友的fd
*/
int privatefd(void *para, int columnCount, char **columnValue, char **columnName)
{
Judge J;
User U;
int fd = *(int *)para; //私聊发起用户的fd
Tofd = *columnValue[0] - '0'; //被邀请好友的fd, 全局变量
strcpy(J.petname, RecvInfo.buf);
strcpy(J.buf, RecvInfo.age);
J.cmd = 12;
ret = send(Tofd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
time_t t1 = time(NULL);
char *t2 = ctime(&t1);
memset(sql, 0, sizeof(sql));
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
ID++;
sprintf(sql, "insert into Chat (id, petname, Tofd, ptr, time) values ('%d', '%s', '%d', '%s', '%s');", ID, RecvInfo.petname, Tofd, RecvInfo.buf, t2);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("chatinsert");
}
memset(&J, 0, sizeof(J));
strcpy(J.buf, "SUCCESS");
J.cmd = 4;
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
/*strcpy(J.buf, "SUCCESS");
J.cmd = 12;
strcpy(J.petname, ptr);
printf("2e33\n");
ret = send(Tofd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("invite");
}
memset(&U, 0, sizeof(U)); //接受好友的验证结果
ret = recv(Tofd, &U, sizeof(U), 0);
if(ret == -1)
{
perror("receive");
}
if(strcmp(U.buf, "y") == 0) //比较结果,并发送给邀请用户
{
memset(&J, 0, sizeof(J));
strcpy(J.buf, "对方已接受你的邀请");
J.cmd = 4;
strcpy(dtr, RecvInfo.petname);
strcpy(J.petname ,T.petname);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("receive");
}
}
else
{
memset(&J, 0, sizeof(J));
strcpy(J.buf, "对方拒绝你的聊天邀请");
J.cmd = 4;
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("receive");
}
}*/
return 0;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:查看被邀请私聊的好友是否在线,
*/
int privateon(void *para, int columnCount, char **columnValue, char **columnName)
{
int fd = *(int *)para;
if(columnCount >= 1) //若在线返回非 0 值
{
sprintf(sql, "select fd from User where petname = '%s' and cmd = '2';", RecvInfo.petname);
ret = sqlite3_exec(pdb, sql, privatefd, &fd, NULL);
if(ret != SQLITE_OK)
{
perror("private");
}
return -1;
}
return 0;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:查看被邀请私聊的好友是否存在,
*/
int private(void *para, int columnCount, char **columnValue, char **columnName)
{
int fd = *(int *)para;
if(columnCount >= 1) //存在再查看是否在线
{
sprintf(sql, "select petname from User where petname = '%s'and cmd = '2';", RecvInfo.petname);
ret = sqlite3_exec(pdb, sql, privateon, &fd, NULL);
printf("ret2 = %d\n", ret);
if(ret != SQLITE_OK)
{
perror("2private");
}
else
{
Judge J;
J.cmd = 4;
strcpy(J.buf, "FAILURE");
printf("bufoo %s\n", buf);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send not exist");
}
return -1;
}
}
return 0;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:全局变量记下发起私聊的fd
*/
int private1(void *para, int columnCount, char **columnValue, char **columnName)
{
fdon = *columnValue[0] - '0';
return 0;
}
/*
作者:杨宣
函数原型:void *pthreadprivate(void *arg)
函数说明:线程处理函数,case 4中起的线程,行参 :文件描述符 代表连接的客户端
函数功能:处理客户端私聊请求
*/
void *pthreadprivate(void *arg)
{
int ret;
int fd = *(int *)arg;
strcpy(ptr, RecvInfo.buf); //全局变量记下发起邀请好友的fd
memset(sql, 0, sizeof(sql));
sprintf(sql, "select fd from User where petname = '%s'", RecvInfo.buf);//查找发起私聊的fd
ret = sqlite3_exec(pdb, sql, private1, &fd, NULL);
if(ret != SQLITE_OK)
{
perror("private");
}
memset(sql, 0, sizeof(sql));
sprintf(sql, "select petname from User where petname = '%s';", RecvInfo.petname);//查看邀请的好友是否存在
ret = sqlite3_exec(pdb, sql, private, &fd, NULL);
if(ret != SQLITE_OK)
{
perror("private");
}
else //若不存在,发送FALSE 给客户端
{
Judge J;
J.cmd = 4;
strcpy(J.buf, "FALSE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendprivate");
}
}
return NULL;
}
/*
作者:杨宣
函数原型:void *pthreadmember(void *arg)
函数说明:线程处理函数,充值会员,行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端充值会员请求
*/
void *pthreadmember(void *arg)
{
Judge J;
int fd = *(int *)arg;
memset(sql, 0, sizeof(sql));
sprintf(sql, "update User set member = '%d' where petname = '%s';", RecvInfo.member, RecvInfo.petname); //更新用户会员信息
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK) //充值失败
{
J.cmd = 9;
memset(&J, 0, sizeof(J));
strcpy(J.buf, "FAILURE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendfailure");
}
}
else
{
memset(&J, 0, sizeof(J));
J.cmd = 9;
strcpy(J.buf, "SUCCESS"); //充值成功
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("FAILUREMEm");
}
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:发送点赞信息给好友
*/
int praise(void *para, int cloumnCount, char **columnValue, char **columnName)
{
Judge J;
Tofd = *columnValue[0] - '0';
strcpy(J.buf, "有好友给你点赞");
J.cmd = 13;
ret = send(Tofd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("praise");
}
return 0;
}
/*
作者:杨宣
函数原型:void *pthreadpraise(void *arg)
函数说明:线程处理函数,点赞好友,,行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端点赞好友请求
*/
void *pthreadpraise(void *arg)
{
int fd = *(int *)arg;
memset(sql, 0, sizeof(sql));
sprintf(sql, "select fd from User where petname = '%s';", RecvInfo.petname);//找出要点赞好友的文件描述符
ret = sqlite3_exec(pdb, sql, praise, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("praise");
}
return NULL;
}
/*
作者:杨宣
函数原型:void *pthreadactive(void *arg)
函数说明:线程处理函数,主动发起私聊的发送线程,行参 : 文件描述符 代表连接的客户端
函数功能:不断发送主动发起私聊的用户的信息
*/
void *pthreadactive(void *arg)
{
int fd = *(int *) arg;
time_t t1 = time(NULL);
char *t2 = ctime(&t1);
Judge J;
J.cmd = 12;
strcpy(J.buf, RecvInfo.buf); //将用户发送消息拷贝到结构体 J 中
strcpy(J.petname, RecvInfo.petname);
ret = send(Tofd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendactive");
}
memset(sql, 0, sizeof(sql));
if(strcmp(J.buf, "bye") != 0)
{
//ID = count(pdb);
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
ID++;
sprintf(sql, "insert into Chat (id, petname, Tofd, ptr, time) values ('%d','%s', '%d', '%s', '%s');",ID, ptr, fdon, J.buf, t2); //将聊天记录插入到表中
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("charinsert");
}
}
return NULL;
}
/*
作者:杨宣
函数原型:void *pthreadnegtive(void *arg)
函数说明:线程处理函数,发送被邀请私聊用户的消息,行参 : 文件描述符 代表连接的客户端
函数功能:不断发送被邀请私聊好友的消息
*/
void *pthreadnegtive(void *arg)
{
//int fd = *(int *)arg;
Judge J;
J.cmd = 4;
strcpy(J.buf, RecvInfo.buf);
strcpy(J.petname, RecvInfo.petname);
time_t t1 = time(NULL);
char *t2 = ctime(&t1);
ret = send(fdon, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendnegtive");
}
memset(sql, 0, sizeof(sql));
if(strcmp(J.buf, "bye") != 0)
{
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
ID++;
sprintf(sql, "insert into Chat (id, petname, Tofd, ptr, time) values ('%d', '%s', '%d', '%s', '%s');", ID, RecvInfo.petname, Tofd, RecvInfo.buf, t2);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("chatinsert");
}
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:处理客户端主动发起的私聊请求,验证被邀请好友是否愿意私聊
*/
int checkchat(void *para, int columnCount, char **columnValue, char **columnName)
{
Judge J;
int i;
fdcheck = *(int *)para;
//for(i = 0; i < columnCount - 1; i++)
strcpy(J.petname, columnValue[1]);
strcpy(J.buf, columnValue[3]);
strcpy(J.t2, columnValue[4]);
J.cmd = 7;
ret = send(fdcheck, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sengchat");
}
memset(&J, 0, sizeof(J));
/*sprintf(sql, "select petname from Chat where ptr = '%s';", columnValue[i]);
ret = sqlite3_exec(pdb, sql, checkname, columnValue[i], NULL);
if(ret != SQLITE_OK)
{
perror("petname");
}*/
return 0;
}
/*
作者:杨宣
函数原型:void *pthreadcheck(void *arg)
函数说明:线程处理函数,查看私聊聊天记录,行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端想要查看聊天记录的请求
*/
void *pthreadcheck(void *arg)
{
int fd = *(int *)arg;
Judge J;
sprintf(sql, "select * from Chat where petname = '%s' or petname = '%s';", RecvInfo.petname, RecvInfo.buf);
ret = sqlite3_exec(pdb, sql, checkchat, &fd, NULL);
if(ret != SQLITE_OK)
{
perror("checkchat");
}
J.cmd = 7;
strcpy(J.buf, "SUCCESS"); //发送完毕
ret = send(fdcheck, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sengchat");
}
/*ret = sqlite3_exec(pdb, sql, checkchat2, &fd, NULL);
if(ret != SQLITE_OK)
{
perror("checkchat");
}*/
return NULL;
}
/*
作者:杨宣
函数原型:void *keyprotest(void *arg)
函数说明:线程处理函数,密码保护,行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端设置密保请求
*/
void *keyprotest(void *arg)
{
int fd = *(int *)arg;
Judge J;
sprintf(sql, "insert into protest(petname, que1, que2, que3) values ('%s', '%s', '%s', '%s');",reg, RecvInfo.age, RecvInfo.sex, RecvInfo.key); //将密保答案存入表中
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
J.cmd = 14;
strcpy(J.buf, "FAILURE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("senfkey");
}
perror("keyprotest");
}
else
{
J.cmd = 14;
strcpy(J.buf, "SUCCESS");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("senfkey");
}
}
return NULL;
}
/*
作者:杨宣
函数原型:void StopClient(int num)
函数说明:自定义函数:正常关闭客户端
函数功能:当服务器捕捉到 ctrl + c信号,挨个发送BYE 给客户端,让客户端正常关闭自身
*/
void StopClient(int num) //进程收到SIGINT信号,退出, num 表述信号值,只能有着一个参数
{
sprintf(sql, "update User set cmd = '1';");
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("setcmd1");
}
Judge J;
strcpy(J.buf, "BYE");
while(j >= 0)
{
ret = send(fd[j], &J, sizeof(J), 0);
if(ret == -1)
{
perror("senfstop");
}
j--;
close(fd[j]);
}
close(sockfd);
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:挨个比较每一问题答案
*/
int keyfind(void *para, int columnCount, char **columnValue, char **columnName)
{
if(strcmp(RecvInfo.age, columnValue[1]) != 0)
{
return -1;
}
else
{
if(strcmp(RecvInfo.sex, columnValue[2]) == 0)
{
if(strcmp(RecvInfo.key, columnValue[3]) == 0)
{
printf("******\n");
return 0;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
}
/*
作者:杨宣
函数原型:void *findkey(void *arg)
函数说明:线程处理函数:重设密码, 行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端核对密保问题请求
*/
void *findkey(void *arg)
{
int fd = *(int *)arg;
memset(sql, 0, sizeof(sql));
sprintf(sql, "select *from protest where petname = '%s';", RecvInfo.petname);//找出表中所以问题的答案
ret = sqlite3_exec(pdb, sql, keyfind, NULL, NULL);
if(ret != SQLITE_OK) //若有一个不正确,就发送FAILURE给客户端
{
Judge J;
J.cmd = 15;
strcpy(J.buf, "FAILURE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
else
{
Judge J;
J.cmd = 15;
strcpy(J.buf, "FALSE"); //回答正确,则发送 FALSE给客户端
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
return NULL;
}
/*
作者:杨宣
函数原型:void *correctkey(void *arg)
函数说明:线程处理函数,重设密码,行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端重新设置密码请求
*/
void *correctkey(void *arg)
{
int fd = *(int *)arg;;
sprintf(sql, "update User set key = '%s' where petname = '%s';", RecvInfo.key, RecvInfo.petname); //更新用户表中密码信息
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret == SQLITE_OK) //正常执行的话,发送SUCCESS给客户端
{
Judge J;
J.cmd = 16;
strcpy(J.buf, "SUCCESS");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendcorrect");
}
}
else
{
Judge J;
J.cmd = 16;
strcpy(J.buf, "FAILURE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("sendcorrect");
}
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:查看群聊邀请好友是否在线
*/
int groupcmd(void *para, int columnCount, char **columnValue, char **columnName)
{
int a = *columnValue[0] - '0'; //若状态 为 1说明不在线, 返回非 0 值
if(a == 1)
{
return -1;
}
return 0;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:查找被邀请好友的fd
*/
int fdgroup(void *para, int columnCount, char **columnValue, char **columnName)
{
int fd = *columnValue[0] - '0';
int i;
Judge J;
J.cmd = 10;
strcpy(J.petname, RecvInfo.petname); //发送询问信息给被邀请好友(某某 邀请你进行群聊)
strcpy(J.buf, RecvInfo.age);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("groupfd");
}
User U;
ret = recv(fd, &U, sizeof(U), 0);//接收询问结果
if(ret == -1)
{
perror("recv");
}
if(strcmp(U.sex, "y") == 0)
{
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
//ID = count(pdb);
ID++;
strcpy(namegroup, RecvInfo.sex);
sprintf(sql, "insert into Chat (id, petname) values ('%d', '%s');", ID, RecvInfo.sex); //将聊天信息存入表中
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("Insertgroup");
}
groupfd[S] = fd; //若同意群聊,记下被邀请好友的fd, 并且用户数加 1
S++;
Judge J;
strcpy(J.buf, "SUCCESS"); //发送邀请成功信息给邀请人
strcpy(J.petname, RecvInfo.petname);
J.cmd = 5;
ret = send(grpfd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send1");
}
J.cmd = 17; //每一位在此用户进入群聊之前的用户,都可看到该用户进群的消息
for(i = 0; i < S; i++)
{
if(groupfd[i] != fd) //该用户自身无须接收
{
ret = send(groupfd[i], &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
}
}
else
{
Judge J;
strcpy(J.buf, "FAILURE"); //若用户拒绝,则发送FAILURE 给客户端,提示邀请失败
strcpy(J.petname, RecvInfo.petname);
J.cmd = 5;
ret = send(grpfd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send1");
}
}
return 0;
}
/*
作者:杨宣
函数原型:void *groupchat(void *arg)
函数说明:线程处理函数,群聊,行参 : 文件描述符 代表连接的客户端
函数功能:处理客户端发起群聊的请求
*/
void *groupchat(void *arg)
{
int fd = *(int *)arg;
grpfd = fd; //将群聊发起人的fd 用全局变量记下
sprintf(sql, "select cmd from User where petname = '%s';", RecvInfo.petname);//查看邀请的好友是否在线
ret = sqlite3_exec(pdb, sql, groupcmd, NULL, NULL);
if(ret != SQLITE_OK) //用户不在线,发送FALSE 给邀请人
{
Judge J;
strcpy(J.buf, "FALSE");
J.cmd = 5;
strcpy(J.petname, RecvInfo.petname);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("groupcmd");
}
}
else
{
sprintf(sql, "select fd from User where petname = '%s';", RecvInfo.petname);//若在线,找出好友的fd
ret = sqlite3_exec(pdb, sql, fdgroup, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("qroupfd");
}
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能: 查看发言好友的fd
*/
int fdreceive(void *para, int columnCount, char **columnValue, char **columnName)
{
receivefd = *columnValue[0] - '0'; //用全局变量记下发言好友的fd
return 0;
}
/*
线程处理函数,发送群聊信息,
行参 : 文件描述符 代表连接的客户端
功能:不断发送群聊用户聊天信息
*/
void *receivegroup(void *arg)
{
int i;
Judge J;
int fd = *(int *)arg;
int flag, j;
sprintf(sql, "select fd from User where petname = '%s';", RecvInfo.petname);//找出发言用户的fd
ret = sqlite3_exec(pdb, sql, fdreceive, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("qroupfd");
}
if(strcmp(RecvInfo.age, "e") == 0 || strcmp(RecvInfo.age, "bye") == 0)//若用户收到bye 或 e,说明有用户退出群聊
{
for(i = 0; i < S; i++) //找出该用户fd在集合中的位置
{
if(groupfd[i] == fd)
{
flag = i;
break;
}
}
if(flag < S -1) //将该用户的fd从集合中删除,若不为最后一个
{
for(j = 0; j < S - flag - 1; j++)
{
groupfd[flag + j] = groupfd[flag + 1 + j];
}
S--; //用户数减 1
}
else //若位于集合最后一位,直接将用户数减 1
{
S--;
}
if(S == 0) //全部用户退出群聊
{
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
ID++;
printf("ID %d\n", ID);
sprintf(sql, "insert into chat (id, petname) values ('%d', '%s');", ID, namegroup);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("sqlite");
}
}
}
else
{
time_t t1 = time(NULL);
char *t2 = ctime(&t1);
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
//ID = count(pdb);
ID++;
printf("ID %d\n", ID);
sprintf(sql, "insert into Chat (id, petname, Tofd, ptr, time ) values ('%d', '%s', '%d', '%s', '%s');", ID, RecvInfo.petname, groupfd[S], RecvInfo.age, t2); //将聊天信息存入表中
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("Insertgroup");
}
}
for(i = 0; i < S; i++) //将发言信息发给每一位群聊用户
{
if(groupfd[i] != fd)
{
J.cmd = 17;
strcpy(J.buf, RecvInfo.age);
strcpy(J.petname, RecvInfo.petname);
ret = send(groupfd[i], &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
}
J.cmd = 5;
strcpy(J.buf, RecvInfo.age);
strcpy(J.petname, RecvInfo.petname);
ret = send(grpfd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
return 0;
}
/*
作者:杨宣
函数原型:void *activegroup(void *arg)
函数说明:线程处理函数,发送群聊信息,行参 : 文件描述符 代表连接的客户端
函数功能:不断发送主动发起聊天的用户聊天信息
*/
void *activegroup(void *arg)
{
int i;
Judge J;
J.cmd = 17;
for(i = 0; i < S; i++) //发给每一个群聊用户
{
strcpy(J.buf, RecvInfo.age);
strcpy(J.petname, RecvInfo.petname);
ret = send(groupfd[i], &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
if(strcmp(J.buf, "e") == 0 || strcmp(J.buf, "bye") == 0)
{
//ID = count(pdb);
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
ID++;
printf("ID %d\n", ID);
sprintf(sql, "insert into chat (id, petname) values ('%d','%s');", ID, namegroup);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("sqlite");
}
}
else
{
time_t t1 = time(NULL);
char *t2 = ctime(&t1);
// ID = count(pdb);
sprintf(sql, "select count(*) from chat;");
ret = sqlite3_exec(pdb, sql, count1, NULL, NULL);
ID++;
printf("ID1 %d\n", ID);
sprintf(sql, "insert into Chat (id, petname, Tofd, ptr, time) values ('%d','%s', '%d', '%s', '%s');", ID, RecvInfo.petname, groupfd[S], RecvInfo.age, t2); //将聊天信息存入表中
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("Insertgroup");
}
}
return NULL;
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:禁言群聊用户
注:禁言也是可以接受消息的,不需要将fd此数组中踢出
*/
int silencefd(void *para, int columnCount, char **columnValue, char **columnName)
{
int fd = *columnValue[0] - '0';
Judge J;
J.cmd = 17;
if(strcmp(RecvInfo.age, "FAILURE") == 0) //若相等则说明是禁言用户,
{
strcpy(J.buf, "FAILURE");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
else
{
strcpy(J.buf, "TRUE"); //若与TRUE相等,为解禁用户
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
return 0;
}
/*
作者:杨宣
函数原型:void silence(int fd
函数说明:自定义函数:函数名silence 带有一个int 型参数,返回值为void型
函数功能:完成客户端解禁言用户请求
*/
void silence(int fd)
{
sprintf(sql, "select fd from User where petname = '%s';", RecvInfo.petname);
ret = sqlite3_exec(pdb, sql, silencefd, NULL, NULL); //找出要解禁言用户的fd
if(ret != SQLITE_OK)
{
perror("qroupfd");
}
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:完成管理员踢出普通用户的请求
*/
int kickfd(void *para, int columnCount, char **columnValue, char **columnName)
{
int fd = *columnValue[0] - '0';
int i, flag;
Judge J;
J.cmd = 17;
strcpy(J.buf, "FALSE"); //发送踢出群聊信息给被踢用户
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
for(i = 0; i < S; i++) //将被踢用户fd在数组中下标找出
{
if(groupfd[i] == fd)
{
flag = i;
break;
}
}
if(flag < S -1) //将该用户fd从数组中踢出
{
for(j = 0; j < S - flag - 1; j++)
{
groupfd[flag + j] = groupfd[flag + 1 + j];
}
S--;
}
else
{
S--;
}
return 0;
}
/*
作者:杨宣
函数原型:void kick()
函数说明:自定义函数:函数名 kick 不带参数,返回值为void
函数功能: 完成客户端踢出群聊用户的请求
*/
void kick()
{
sprintf(sql, "select fd from User where petname = '%s';", RecvInfo.petname);//找出要踢出用户的fd
ret = sqlite3_exec(pdb, sql, kickfd, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("qroupfd");
}
}
/*
作者:杨宣
函数原型: 回调函数:int show(void *para, int columnCount, char **columnValue, char **columnName)
函数说明:参1:为调用函数传过来的参数, 参2: 为查询到的信息有几条 参3:查询到的结果 参4:查询结构的名称即类型
函数功能:/发送设置成为管理员信息给用户
*/
int adminfd(void *para, int columnCount, char **columnValue, char **columnName)
{
int fd = *columnValue[0] - '0';
Judge J;
J.cmd = 17;
strcpy(J.buf, "TRUE"); //发送设置成为管理员信息给用户
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
return 0;
}
/*
作者:杨宣
函数原型:void admin()
函数说明:自定义函数:函数名 admin 不带参数, 返回值为void
函数功能:完成群主设置普通用户成为管理员的功能
*/
void admin()
{
sprintf(sql, "select fd from User where petname = '%s';", RecvInfo.petname);//找出要设置用户的fd
ret = sqlite3_exec(pdb, sql, adminfd, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("qroupfd");
}
}
/*
作者:杨宣
函数原型:int cancelfd(void *para, int columnCount, char **columnValue, char **columnName)
函数功能:帐号注销前,先将文件描述符记下,以备发送注销结果
*/
int cancelfd(void *para, int columnCount, char **columnValue, char **columnName)
{
fdcancel = *columnValue[0] - '0';
return 0;
}
/*
作者:杨宣
函数原型:void cancel()
函数功能:自定义函数实现功能:注销帐号
*/
void cancel()
{
memset (sql, 0, sizeof(sql));
sprintf(sql, "select fd from User where petname = '%s';",RecvInfo.petname);
ret = sqlite3_exec(pdb, sql, cancelfd, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("sqlite3");
}
memset (sql, 0, sizeof(sql));
sprintf(sql, "delete from User where petname = '%s';", RecvInfo.petname);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK) //注销失败
{
Judge J;
strcpy(J.buf, "FAILURE");
J.cmd = 8;
ret = send(fdcancel, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
perror("SQLITE_ok");
}
else //注销成功
{
Judge J;
strcpy(J.buf, "SUCCESS");
J.cmd = 8;
ret = send(fdcancel, &J, sizeof(J), 0);
if(ret == -1)
{
perror("cancel success");
}
}
}
/*
*/
/*int groupname(void *para, int columnCount, char **columnValue, char **columnName)
{
Judge J;
J.cmd = 6;
char buf[32] = {0};
strcpy(J.petname, columnValue[0]);
strcpy(J.buf, para);
printf("J.buf %s\n", J.buf);
ret = send(group, &J, sizeof(J), 0);
if(ret == -1)
{
perror("group");
}
return 0;
}*/
int sendgroup(void *para, int columnCount, char **columnValue, char **columnName)
{
Judge J;
if(strcmp(columnValue[1], RecvInfo.petname) != 0)
{
strcpy(J.petname, columnValue[1]);
strcpy(J.buf, columnValue[3]);
strcpy(J.t2, columnValue[4]);
J.cmd = 6;
ret = send(group, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
printf("j.buf %s\n", J.buf);
memset(&J, 0, sizeof(J));
}
else
{
J.cmd = 6;
strcpy(J.buf, "SUCCESS");
ret = send(group, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
return 0;
}
}
return 0;
}
int checkrecord(void *para, int columnCount, char **columnValue, char **columnName)
{
memset(sql, 0, sizeof(sql));
a[I] = atoi(*columnValue);
printf("a[i] %d\n", a[I]);
I++;
printf("a= %d\n", I);
return 0;
}
/*
*/
void groupcheck(int sockfd)
{
group = sockfd;
memset(sql, 0, sizeof(sql));
sprintf(sql, "select id from chat where petname = '%s';", RecvInfo.petname);
ret = sqlite3_exec(pdb, sql, checkrecord, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("sqlite");
}
sprintf(sql, "select * from chat limit '%d','%d';", a[0], a[1] - 1);
ret = sqlite3_exec(pdb, sql, sendgroup, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("group");
}
}
int convertcmd(void *para, int columnCount, char **columnValue, char **columnName)
{
FILE *fp;
User U;
int fd = *(int *)para;
int cmd = atoi(*columnValue);
Judge J;
char buf[32] = {0};
fp = fopen(RecvInfo.buf, "w+");
if(fp == NULL)
{
perror("fopen");
}
while(1)
{
ret = recv(fd, &U, sizeof(U), 0);
if(ret == -1)
{
perror("recv");
}
if(strcmp(U.age, "bye") == 0 || ret == 0)
{
break;
}
ret = fwrite(U.buf, 1, U.cmd, fp);
if(ret == -1)
{
perror("fwrite");
}
memset(U.buf, 0, sizeof(U.buf));
}
fclose(fp);
/*Judge J;
J.cmd = 19;
strcpy(J.petname, RecvInfo.petname);
strcpy(J.buf, "SUCCESS");
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("convert");
}*/
if(cmd == 1)
{
sprintf(sql, "Insert into file (namesend, namerecv, file, cmd) values ('%s', '%s', '%s', '%d');", RecvInfo.age, RecvInfo.petname, RecvInfo.buf, 1);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("insert file failure");
}
}
else
{
fp = fopen(RecvInfo.buf, "r");
if(fp == NULL)
{
printf("failure\n");
}
J.cmd = 18;
strcpy(J.petname, RecvInfo.age);
strcpy(J.buf, RecvInfo.buf);
ret = send(FD, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
while(1)
{
memset(J.buf, 0, sizeof(J.buf));
ret = fread(J.buf, 1, sizeof(J.buf) - 1, fp);
if(ret == -1)
{
perror("fread");
}
if(ret == 0)
{
J.cmd = 0;
strcpy(J.buf, "SUCCESS");
ret = send(FD, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
break;
}
else
{
J.cmd = ret;
ret = send(FD, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
fclose(fp);
sprintf(sql, "Inset into file (namesend, namerecv, file, cmd) values ('%s', '%s', '%s', '%d');", RecvInfo.age, RecvInfo.petname, RecvInfo.buf, 2);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("insert file failure");
}
}
}
return 0;
}
int convertfd(void *para, int columnCount, char **columnValue, char **columnName)
{
FD = atoi(*columnValue); //记下要接受文件的fd
return 0;
}
void convert(int sockfd)
{
memset(sql, 0, sizeof(sql));
sprintf(sql, "select fd from User where petname = '%s';", RecvInfo.petname);//找出要接受用户的fd
ret = sqlite3_exec(pdb, sql, convertfd, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("qroupfd");
}
memset(sql, 0, sizeof(sql));
sprintf(sql, "select cmd from User where petname = '%s';", RecvInfo.petname);//找出要接受文件用户的cmd
ret = sqlite3_exec(pdb, sql, convertcmd, &sockfd, NULL);
if(ret != SQLITE_OK)
{
perror("qroupfd");
}
}
int findfile(void *para, int columnCount, char **columnValue, char **columnName)
{
Judge J;
J.cmd = 19;
int fd = *(int *)para;
if(columnCount >= 0)
{
strcpy(J.petname, columnValue[0]);
strcpy(J.buf, columnValue[2]);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
return 0;
}
void checkfile(int sockfd, User U)
{
Judge J;
sprintf(sql, "select * from file where namerecv = '%s';", U.petname);
ret = sqlite3_exec(pdb, sql, findfile, &sockfd, NULL);
if(ret != SQLITE_OK)
{
perror("findfile");
}
J.cmd = 19;
strcpy(J.buf, "SUCCESS");
ret = send(sockfd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}
/*
main()主函数,
功能:完成服务器的初始化,绑定,并监测所有已连接的客户端的fd,
*/
int main()
{
pthread_mutex_init(&mutex, NULL); //对锁和条件变量进行初始化
pthread_cond_init(&con, NULL);
//pthread_detach(pthread_self()); //线程分离
struct sockaddr_in client_addr;//客户端结构体变量,保存客户端信息
pthread_t tid; //线程号
int i = 0; //
fd_set ReadFd, tmpfd; //定义可读集合和中间变量
int MaxFd; //用来记下最大的文件描述符
signal(SIGINT, StopClient); //捕捉ctrl+c信号,当捕捉到这个信号时,执行StopClient函数
/*创建一个套接字, 采用TCP协议*/
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
perror("sockfd");
exit(1);
}
int opt = 1; //地址可被复用,man手册可查看函数原型 man setsockopt
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/*定义好后进行初始化, 并对返回值进行判断*/
ret = sockfdInit(sockfd);
if(ret == FAILURE)
{
printf("Init FAILURE");
}
FD_ZERO(&ReadFd); //将集合清0, man手册 man FD_SERO可查看一切与select 有关的函数原型
FD_SET(sockfd, &ReadFd); //将刚创建的文件描述符sockfd 放入可读集合中
MaxFd = sockfd; //目前最大的文件描述符为sockfd,为 4,
/*
打开一个数据库若不存在则自动创建, 用来建表保存信息
数据库名字User.db
pdb为该数据库句柄, 可通过句柄访问数据库
*/
ret = sqlite3_open("User.db", &pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open1");
exit(1);
}
/*
在数据库中建一张表, 用来保存注册信息
sqlite3_errmsg(sqlite3 *pdb) 用来返回错误说明指针
pdb 打开的数据库句柄
该表中含有用户 昵称,年龄,性别,密码,在线状态,在线设备,会员等级
*/
sprintf(sql, "create table if not exists User (petname text, age text, sex text, key text, cmd register, fd register, member register);");
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
printf("sqlite3_exec error : %s \n", sqlite3_errmsg(pdb));
}
/*
在数据库中另建一张表,用来存储聊天记录,
该表含有用户 昵称,在线设备, 聊天记录
*/
sprintf(sql, "create table if not exists Chat (id register, petname text, Tofd register, ptr text, time register);");
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
printf("sqlite3_exec error : %s \n", sqlite3_errmsg(pdb));
}
sprintf(sql, "create table if not exists file (namesend text, namerecv text, file text, cmd register);");
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
printf("sqlite3_exec error : %s \n", sqlite3_errmsg(pdb));
}
/*
在表中再建一张表,用来存储用户的密保答案
该表中含用户昵称,三个问题的答案
*/
sprintf(sql, "create table if not exists protest (petname text, que1 text, que2 text, que3 text);");
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
printf("sqlite3_exec error : %s \n", sqlite3_errmsg(pdb));
}
int length = sizeof(client_addr);
/*不断接受客户端请求,并创建线程处理客户端请求*/
while(1)
{
tmpfd = ReadFd; //用中间变量记下集合状态
/*
函数原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参1:为最大文件描述符+1,
参2:需要监听的可读集合
参3:需要监听的可写集合,若不需要监听是否可写,则置为NULL,
*/
ret = select(MaxFd + 1, &tmpfd, NULL, NULL, NULL); //用select 去监听这个集合
if(ret == -1)
{
perror("select");
}
if (FD_ISSET(sockfd, &tmpfd)) //有客户端发起连接,将集合中的文件描述符遍历一遍,查看之前是否有连接的客户端断开连接, 若有客户端退出连接fd被置为 0,则跳出
{
for (j = 0; j < i; j++)
{
if (fd[j] == 0)
{
break;
}
}
//接受客户端的连接请求
fd[j] = accept(sockfd, (struct sockaddr *)&client_addr, (socklen_t *)&length);
if(-1 == fd[j])
{
return FAILURE;
}
if (MaxFd < fd[j]) //如果最大的fd比刚连接的fd小,则将刚连接的fd赋给MaxFd
{
MaxFd = fd[j];
}
FD_SET(fd[j], &ReadFd); //将刚连接的fd放入监听的可读集合中
if(j == i) //若i== j说明之前连接的客户端中并没有退出的,计数 i++
{
i++;
}
}
else
{
for (j = 0; j < i; j++) //有客户端发消息
{
if (FD_ISSET(fd[j], &tmpfd)) //挨个监听哪个客户端发了消息
{
memset(&RecvInfo, 0, sizeof(RecvInfo));
ret = recv(fd[j], &RecvInfo, sizeof(RecvInfo), 0);
printf("Cmd = %d\n", RecvInfo.cmd);
if(strcmp(RecvInfo.petname, "BYE") == 0) //若有客户端发了BYE,则断开该客户端连接
{
if(RecvInfo.cmd == 1)
{
sprintf(sql, "update User set cmd = '1' where petname = '%s';", RecvInfo.buf);
ret = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
if(ret != SQLITE_OK)
{
perror("setonecmd");
}
}
close(fd[j]);
FD_CLR(fd[j], &ReadFd); //并将该客户端从集合中清除
fd[j] = 0;
j--;
break;
}
switch(RecvInfo.cmd)
{
case 1:
ret = pthread_create(&tid, NULL, pthreadHandle, &fd[j]);
printf("Ccmd\n");
if(ret == -1)
{
printf("create failure1");
exit(1);
}
break;
case 2:
ret = pthread_create(&tid, NULL, pthreadlogin, &fd[j]);
if(ret == -1)
{
printf("create failure2");
exit(1);
}
break;
case 3:
ret = pthread_create(&tid, NULL, pthreadshow, &fd[j]);
if(ret == -1)
{
printf("create failure3");
exit(1);
}
//memset(&RecvInfo, 0, sizeof(RecvInfo));
break;
case 4:
ret = pthread_create(&tid, NULL, pthreadprivate, &fd[j]);
if(ret == -1)
{
printf("create failure4");
exit(1);
}
//memset(&RecvInfo, 0, sizeof(RecvInfo));
break;
case 5:
ret = pthread_create(&tid, NULL, groupchat, &fd[j]);
if(ret == -1)
{
printf("create failure4");
exit(1);
}
break;
case 6:
groupcheck(fd[j]);
break;
case 7:
ret = pthread_create(&tid, NULL, pthreadcheck, &fd[j]);
if(ret == -1)
{
printf("create failure4");
exit(1);
}
break;
case 8:
cancel();
break;
case 9:
ret = pthread_create(&tid, NULL, pthreadmember, &fd[j]);
if(ret == -1)
{
printf("create failure9");
exit(1);
}
break;
case 10:
ret = pthread_create(&tid, NULL, pthreadpraise, &fd[j]);
if(ret == -1)
{
printf("create failure10");
exit(1);
}
break;
case 11:
ret = pthread_create(&tid, NULL, pthreadexit, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 12:
ret = pthread_create(&tid, NULL, pthreadactive, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 13:
ret = pthread_create(&tid, NULL, pthreadnegtive, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 14:
printf("buf%s\n", RecvInfo.buf);
break;
case 15:
ret = pthread_create(&tid, NULL, keyprotest, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 16:
ret = pthread_create(&tid, NULL, findkey, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 17:
ret = pthread_create(&tid, NULL, correctkey, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 18:
ret = pthread_create(&tid, NULL, receivegroup, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 19:
ret = pthread_create(&tid, NULL, activegroup, &fd[j]);
if(ret == -1)
{
printf("create failure11");
exit(1);
}
break;
case 20:
silence(fd[j]);
break;
case 21:
kick();
break;
case 22:
admin();
break;
case 23:
convert(fd[j]);
break;
case 24:
checkfile(fd[j], RecvInfo);
break;
}
}
}
}
}
// for(j = 0; j < i; j++) //为什么加了线程等待,就段错误
// {
//void *status;
// pthread_join(tid, &status);
// }
while(j >= 0)
{
close(fd[j]);
j--;
}
close(sockfd);
return 0;
}
/**************************************************************
> File Name: SockServer.c
> Author: yangxuan
> Mail: [email protected]
> Created Time: 2018年08月23日 星期四 23时27分19秒
**************************************************************/
#include <stdio.h>
#include "Server.h"
#define PORT 8888
/* 函数原型:int sockfdInit(int sockfd), 函数名:sockfdInit 函数带有一个int型的参数,
函数返回值为 int型
功能: 完成服务端初始化
*/
int sockfdInit(int sockfd)
{
int ret;
/*初始化服务器信息*/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("192.168.1.113");
/*绑定本地服务器信息*/
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(ret == -1)
{
printf("----\n");
return FAILURE;
}
/*从sockfd 中一次监听5个客户端*/
ret = listen(sockfd, 5);
if(ret == -1)
{
return FAILURE;
}
return SUCCESS;
}
/*void send1(int fd)
{
int ret;
Judge J;
strcpy(J.buf, "FAILURE");
J.cmd = 1;
printf("J.buf %s\n",J.buf);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}*/
//
void send0(int fd)
{
int ret;
Judge J;
strcpy(J.buf, "SUCCESS");
J.cmd = 1;
printf("J.buf %s\n",J.buf);
ret = send(fd, &J, sizeof(J), 0);
if(ret == -1)
{
perror("send");
}
}