可以借鉴一下程序的思路
main.c
#include "DB/inc/db_user.h"
#include "DB/inc/db_message.h"
#include "net/inc/socket_core.h"
#include "userControl.h"
extern struct ServerClass serverClass;
void serverStop(void);
void serverStart(void);
void serverEntry(void);
void serverExit(void);
void receiveClose(void);
// 用户处理函数
void msgReceive(char *buff, int *psize); //接受到数据报时响应,其中buff和size为数据报到内存首地址和长度
void clientBody(void *connfd); // 客户机连接上的处理主函数,其中connfd为连接符
void *sendHandle(void *arg); //客户机发送线程函数
int msgSend(void *arg); // 客户机发送处理函数,由userControl.ifRespond=TRUE触发,将userControl.p打包发送
//数据库连接符
struct DB db;
struct DB_User db_user;
struct DB_Message db_message;
extern struct UserControl userControl;
int main(){
serverClass.stop = serverStop;
serverClass.start= serverStart;
serverClass.entry= serverEntry;
serverClass.Exit = serverExit;
serverClass.body = clientBody;
serverClass.receiveEvent = msgReceive;
serverClass.closeEvent = receiveClose;
serverClass.run();
return 0;
}
/*
* @function: 线程接收消息函数
* 服务器接收到客户发来的数据报时触发
* @psize: 返回实际接收到的数据报字节数
* @buff: 接收数据的临时缓冲
*/
void msgReceive(char *buff, int *psize){
printf("触发消息接收函数... ...\n");
char user[20];
char passwd[20];
int num;
printf("receive size:%d\n", *psize);
struct Package *pack = (struct Package *)buff;
struct Package tempPack;
printf("Pack Type:%s\n", pack->type);
if (strcmp(pack->type, "") == 0) //type为空,数据传输有问题
{
printf("接收数据格式有问题\n");
return ;
}
//客户机请求类别
if (strcmp(pack->type, TP_LOAD) == 0){ //登陆请求
//验证用户名和密码是否正确,若正确则给登陆成功应答
if (pack->data == NULL) //数据传输有问题
{
printf("接收数据格式有问题\n");
return ;
}
strcpy(user, pack->data[0].fromuser);
strcpy(passwd, pack->data[0].passwd);
printf("user:%s,passwd:%s\n", user, passwd);
printf("用户登陆验证中... ...\n");
if ((num = db_user.checkUser(&db, user, passwd)) >= 0){
printf("用户%s登陆验证成功\n", user);
//设置用户登陆在线
onLoad(user, TRUE);
if ((num = db_user.setUserState(&db, user, TRUE)) >= 0){
printf("User %s Load\n", user);
}
//设置应答缓冲
strcpy(tempPack.type, TP_ACK_LOAD);
strcpy(tempPack.msg, "load success");
tempPack.success = TRUE;
tempPack.len = 0;
setPackage(&tempPack);
}else{
//登陆失败
printf("用户%s登陆验证失败\n", user);
//设置应答缓冲
//设置应答缓冲
strcpy(tempPack.type, TP_ACK_LOAD);
tempPack.len = 0;
strcpy(tempPack.msg, "fail to load");
tempPack.success = FALSE;
setPackage(&tempPack);
}
respond();
}else if (strcmp(pack->type, TP_REFRESH) == 0){ //刷新请求
printf("用户刷新请求... ... \n");
// 互斥锁加锁
pthread_mutex_lock(&userControl.mutex);
printf("加锁********************\n");
if (strcmp(userControl.user, "") == 0 || userControl.ifLoad == FALSE) //用户名为空或者未登陆
{
printf("未登录,无法刷新... ...\n");
// 互斥锁解锁
pthread_mutex_unlock(&userControl.mutex);
printf("解锁********************\n");
goto QUIT;
}
// 互斥锁解锁
pthread_mutex_unlock(&userControl.mutex);
printf("解锁********************\n");
int device_num = pack->len;
int ifRefresh = 0; //0表示刷新成功,其他值表示刷新失败的设备编号
printf("用户正在刷新... ...%d\n", device_num);
//获取客户机发过来的数据包进行刷新
struct Message msg;
int i = 0;
for (i=0;i<(device_num);i++)
{
printf("正在尝试刷新第%d个设备\n",i);
strcpy(msg.fromuser, pack->data[i].fromuser);
strcpy(msg.touser, pack->data[i].touser);
strcpy(msg.data, pack->data[i].data);
strcpy(msg.state, pack->data[i].state);
if ((num = db_message.setMessage(db_message.db, msg)) >= 0){
printf("成功刷新设备%s\n这是第%d个设备\n",pack->data[i].data, i);
continue;
}
printf("刷新失败,错误码:%d ... ...\n", num);
ifRefresh = i; //刷新失败的设备
}
//应答
if (ifRefresh == 0) // 刷新成功
{
strcpy(tempPack.type, TP_ACK_REFRESH);
tempPack.len = 0;
strcpy(tempPack.msg, "success to refresh");
tempPack.success = TRUE;
setPackage(&tempPack);
printf("刷新成功\n");
}else{ //刷新失败,返回刷新失败的设备编号
strcpy(tempPack.type, TP_ACK_REFRESH);
strcpy(tempPack.msg, "fail to refresh");
tempPack.success = FALSE;
tempPack.len = 0;
setPackage(&tempPack);
printf("刷新失败\n");
}
respond();
}else if(strcmp(pack->type, TP_CONTROL) == 0){ //控制请求
printf("控制请求... ... \n");
// 互斥锁加锁
pthread_mutex_lock(&userControl.mutex);
printf("加锁********************\n");
if (strcmp(userControl.user, "") == 0 || userControl.ifLoad == FALSE) //用户名为空或者未登陆
{
printf("未登录,无法请求控制... ...\n");
// 互斥锁解锁
pthread_mutex_unlock(&userControl.mutex);
printf("解锁********************\n");
goto QUIT;
}
strcpy(user, userControl.user);
// 互斥锁解锁
pthread_mutex_unlock(&userControl.mutex);
printf("解锁********************\n");
struct Message msg[MSG_SIZE];
int num;
if ((num = db_message.getMessage(db_message.db, user, msg, MSG_SIZE)) < 0){
printf("获取控制数据失败%d\n", num);
goto QUIT;
}
printf("总共%d个设备\n准备控制发送... ...", num);
// 加锁
int i = 0;
pthread_mutex_lock(&userControl.mutex);
printf("加锁********************\n");
for (i=0;i<num;i++)
{
strcpy(userControl.p.type, TP_ACK_CONTROL); // 设置为应答类型
strcpy(userControl.p.msg, "control");
userControl.p.success = TRUE; //错误
userControl.p.len = num; //msg长度
strcpy(userControl.p.data[i].fromuser,msg[i].fromuser);
strcpy(userControl.p.data[i].touser,msg[i].touser);
strcpy(userControl.p.data[i].data,msg[i].data);
strcpy(userControl.p.data[i].state,msg[i].state);
}
// 解锁
pthread_mutex_unlock(&userControl.mutex);
printf("解锁********************\n");
respond();
}else{ //未知请求
strcpy(tempPack.type, TP_ACK_UNDEFINED);
strcpy(tempPack.msg, "unknown type");
tempPack.success = FALSE;
tempPack.len = 0;
setPackage(&tempPack);
respond();
}
QUIT:
return ;
}
/*
* @function: 客户端连接主处理线程
* 客户机连接后完成初始化等操作后的主处理线程函数
* @arg: 为客户机连接成功的网络连接符
*/
void clientBody(void *arg){
printf("进入客户连接主处理线程... ...\n");
int connfd = *((int*)arg);
void *status;
pthread_t wpid;
pthread_create(&wpid, NULL, &sendHandle, &connfd); // 发送消息线程
pthread_join(wpid, &status); // 等待线程退出
printf("退出客户连接主处理线程... ...\n");
return ;
}
/*
* @function: 客户端主线程函数分离出来的线程
* 主要是为了msgSend的触发作用做环境搭建
* @arg: 为客户机连接成功的网络描述符
*/
void *sendHandle(void *arg){
printf("启动发送线程... ...\n");
while(1){
// 加锁
pthread_mutex_lock(&userControl.cond_mutex);
printf("加变量锁**********************\n");
while (userControl.ifRespond == FALSE) // 条件为假则休眠等待
{
pthread_cond_wait(&userControl.cond, &userControl.cond_mutex);
}
// 条件为真触发执行msgSend后,修改条件变量ifRespond
if (msgSend(arg) < 0 || userControl.ifExit == 1) //userControl.ifExit是当receive接收到-1退出时触发这个也退出
{
userControl.ifRespond = FALSE;
// 解锁
pthread_mutex_unlock(&userControl.cond_mutex);
printf("解变量锁*****************\n");
break;
}
userControl.ifRespond = FALSE;
// 解锁
pthread_mutex_unlock(&userControl.cond_mutex);
printf("解变量锁**************************\n");
}
printf("退出发送线程... ...\n");
return 0;
}
/*
* @function: 发送消息
* 设置条件变量userControl.ifRespond=TRUE时触发
* 触发后将会按照userControl.len长度,将userContro.p的数据报进行格式打包并发送
* @ret: 返回值负值时结束整个发送监听线程,userControl.ifRespond触发功能失效
*/
int msgSend(void *arg){
int connfd = *((int *)arg);
sleep(1); //延时1s才发送
pthread_mutex_lock(&userControl.mutex);
printf("加锁********************\n");
char *buff = (char *)&userControl.p;
pthread_mutex_unlock(&userControl.mutex);
printf("解锁********************\n");
int size = sizeof(struct Package)+userControl.p.len*(sizeof(struct MSG))-MSG_SIZE*(sizeof(struct MSG));
printf("发送数据 -----------\n");
size = write(connfd, buff, size);
printf("ret:%d\n",size);
return size;
}
/*
* @function: 服务器启动时运行
*/
void serverStart(void){
printf("启动服务器... ...\n");
// TODO将用户在线状态全部清0,服务器启动后用户还未连接是不在线的
}
void serverStop(void){
printf("关闭服务器... ...\n");
}
void serverEntry(void){
printf("新客户机连接... ...!\n");
db_init(&db); //初始化db
db.open(&db.conn); //打开db
db_user_init(&db_user, &db); //初始化user_db
db_message_init(&db_message, &db); //初始化user_db
// 初始化数据库连接符还有用户控制结构体等客户连接全局变量
// 初始化互斥锁
if (pthread_mutex_init(&userControl.mutex, NULL))
{
printf("初始化互斥锁失败\n");
exit(1);
}
// 初始化条件变量互斥锁
if (pthread_mutex_init(&userControl.cond_mutex, NULL))
{
printf("初始化条件互斥锁失败\n");
exit(1);
}
// 初始化条件变量
if (pthread_cond_init(&userControl.cond, NULL))
{
printf("初始化条件变量失败\n");
exit(1);
}
// 互斥锁加锁
// pthread_mutex_lock(&userControl.mutex);
strcpy(userControl.user,"");
userControl.ifLoad = FALSE; //用户不在线
userControl.ifRespond = FALSE; //不用应答客户机
userControl.ifExit = 0;
// 互斥锁解锁
// pthread_mutex_unlock(&userControl.mutex);
}
void serverExit(void){
char temp[20];
printf("客户机退出连接!\n");
//设置用户不在线
int num;
// 互斥锁加锁
// pthread_mutex_lock(&userControl.mutex);
strcpy(temp, userControl.user);
//互斥锁解锁
// pthread_mutex_unlock(&userControl.mutex);
if (strcmp(temp, "") == 0) //fromuser为空,用户没登陆
{
goto QUIT;
}
if ((num = db_user.setUserState(&db, temp, FALSE)) >= 0){
printf("Set User UnLoad Success:%d\n", num);
}
//释放数据库连接符还有用户控制结构体等客户连接全局变量
QUIT:
// 释放互斥锁
pthread_mutex_destroy(&userControl.mutex);
printf("释放锁********************\n");
// 释放条件变量互斥锁
pthread_mutex_destroy(&userControl.cond_mutex);
printf("释放条件锁*******************\n");
// 释放条件变量
pthread_cond_destroy(&userControl.cond);
printf("释放条件变量***************\n");
userControl.ifExit = 0;
db.close(&db.conn); //释放数据库连接符
}
void receiveClose(void){
printf("接收连接线程断开... ...\n");
//触发body退出
pthread_mutex_lock(&userControl.cond_mutex);
printf("加变量锁************************\n");
if (userControl.ifRespond == FALSE)
{
pthread_cond_signal(&userControl.cond);
}
userControl.ifRespond = TRUE;
userControl.ifExit = 1;
pthread_mutex_unlock(&userControl.cond_mutex);
printf("解变量锁************************\n");
}
usercontrol.h
#include "userControl.h"
struct UserControl userControl;
void onLoad(char user[], int ifLoad){
pthread_mutex_lock(&userControl.mutex);
printf("加锁************************\n");
strcpy(userControl.user, user);
userControl.ifLoad = ifLoad;
pthread_mutex_unlock(&userControl.mutex);
printf("解锁************************\n");
}
void setPackage(struct Package *pack){
pthread_mutex_lock(&userControl.mutex);
printf("加锁************************\n");
strcpy(userControl.p.type, pack->type);
strcpy(userControl.p.msg, pack->msg);
userControl.p.success = pack->success;
userControl.p.len = pack->len;
memcpy(userControl.p.data, pack->data, pack->len*(sizeof(struct MSG)));
pthread_mutex_unlock(&userControl.mutex);
printf("解锁************************\n");
}
void getPackage(struct Package *pack){
pthread_mutex_lock(&userControl.mutex);
printf("加锁************************\n");
strcpy(pack->type, userControl.p.type);
strcpy(pack->msg, userControl.p.msg);
pack->success = userControl.p.success;
pack->len = userControl.p.len;
memcpy(pack->data, userControl.p.data, userControl.p.len*(sizeof(struct MSG)));
pthread_mutex_unlock(&userControl.mutex);
printf("解锁************************\n");
}
void respond(){
pthread_mutex_lock(&userControl.cond_mutex);
printf("加变量锁************************\n");
if (userControl.ifRespond == FALSE)
{
pthread_cond_signal(&userControl.cond);
}
userControl.ifRespond = TRUE;
pthread_mutex_unlock(&userControl.cond_mutex);
printf("解变量锁************************\n");
}
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。