📄 socketsvrthread.cpp
字号:
#include "stdafx.h"
#include "SocketSvrThread.h"
#include "Option.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CSocketSvrThread, CWinThread)
CSocketSvrThread::CSocketSvrThread()
{
m_bStopFlag = false;
m_bAutoDelete = false;
}
CSocketSvrThread::~CSocketSvrThread()
{
try
{
m_dbConn.Close();
}
catch(_com_error &e)
{
TRACE("Close connection object error: %s", ADO_ERR_MSG(e));
}
m_SocketMod.Close();
}
BOOL CSocketSvrThread::InitInstance()
{
return TRUE;
}
int CSocketSvrThread::ExitInstance()
{
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(CSocketSvrThread, CWinThread)
//{{AFX_MSG_MAP(CSocketSvrThread)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/************************************************************
InitAndStart
功 能:初始化
性 质:public
输入参数:bStart - 是否马上运行线程
输出参数:无
返 回 值:true - 成功;false - 失败
************************************************************/
bool CSocketSvrThread::InitAndStart(bool bStart)
{
// 连接数据库
LOG(MOD_SOCK_SVR, LOG_INF, "连接数据库...");
try
{
m_dbConn.Open(g_Option.m_strConnStr);
}
catch(_com_error & e)
{
LOG1(MOD_COMM_SVR, LOG_ERR, "连接数据库失败:%s", ADO_ERR_MSG(e));
LOG(MOD_COMM_SVR, LOG_INF, "请点击“工具”菜单修改数据库连接设置!");
return false;
}
// 开始侦听客户端请求
if(!m_SocketMod.Listen(g_Option.m_nServerPort))
{
m_dbConn.Close();
LOG1(MOD_COMM_SVR, LOG_ERR, "侦听失败,错误号:%d", GetLastError());
return false;
}
// 运行线程
if(bStart)
{
if(ResumeThread() == 0xFFFFFFFF)
{
m_dbConn.Close();
LOG(MOD_COMM_SVR, LOG_ERR, "恢复线程运行失败!");
return false;
}
}
return true;
}
/************************************************************
Stop
功 能:停止并等待线程退出
性 质:public
输入参数:无
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::Stop()
{
m_bStopFlag = true;
WaitForSingleObject(m_hThread, INFINITE);
}
/************************************************************
Run
功 能:线程运行函数
性 质:protected
输入参数:无
输出参数:无
返 回 值:线程退出代码
************************************************************/
int CSocketSvrThread::Run()
{
// 请求包类型长度
const int nReqTypeLen = 4;
// 接收缓冲区
char RecvBuf[RECV_BUFF_SIZE];
// 接收到的请求包长度
int nRecvDataLen = 0;
// 请求包类型
char sReqType[nReqTypeLen + 1];
// 套接字句柄
SOCKET hSocket;
// 消息
MSG msg;
// 话路状态包
st_Pack_LineStatusRes * pLineStatusRes = NULL;
// 话路状态包长度
int nLineStatusResLen = 0;
// 最后一次保存话单时间
long LastSaveBillTime;
// 休眠标志
bool bSleep = true;
LastSaveBillTime = time(NULL);
LOG(MOD_SOCK_SVR, LOG_INF, "已运行");
// 线程主循环
while(!m_bStopFlag)
{
bSleep = true;
//////////////////////////////////////////////////////////////////
// 1、从客户端接收请求数据包并处理
//////////////////////////////////////////////////////////////////
if(m_SocketMod.RecvPacket(RecvBuf, sizeof(RecvBuf), &nRecvDataLen, &hSocket))
{
// 判断请求类型,并进行处理
memset(sReqType, 0, sizeof(sReqType));
memcpy(sReqType, RecvBuf + 8, nReqTypeLen);
switch(atoi(sReqType))
{
case PACK_GETLINESTATUS_REQ:
OnClientGetLineStatus(RecvBuf, nRecvDataLen, hSocket);
break;
case PACK_OPENROOM_REQ:
OnClientOpenRoom(RecvBuf, nRecvDataLen, hSocket);
break;
case PACK_CHECKOUT_REQ:
OnClientCheckOut(RecvBuf, nRecvDataLen, hSocket);
break;
case PACK_OPENCLOSE_REQ:
OnClientOpenClose(RecvBuf, nRecvDataLen, hSocket);
break;
case PACK_SETDEPOSIT_REQ:
OnClientSetDisposit(RecvBuf, nRecvDataLen, hSocket);
break;
case PACK_GETCFG_REQ:
OnClientGetTable(RecvBuf, nRecvDataLen, hSocket);
break;
case PACK_SETCFG_REQ:
OnClientSetTable(RecvBuf, nRecvDataLen, hSocket);
break;
default:
LOG1(MOD_SOCK_SVR, LOG_ERR, "请求包类型%d错误", atoi(sReqType));
break;
}
bSleep = false;
}//end if(m_SocketMod.Recv...
//////////////////////////////////////////////////////////////////
// 2、检查消息队列,如果有发送请求,取出发送请求进行发送
//////////////////////////////////////////////////////////////////
if(PeekMessage(&msg, NULL, WM_SEND_LINESTATUS, WM_SEND_LINESTATUS, PM_REMOVE))
{
pLineStatusRes = (st_Pack_LineStatusRes *)msg.wParam;
nLineStatusResLen = msg.lParam;
ASSERT(pLineStatusRes);
ASSERT(nLineStatusResLen > 0);
LOG_DBG1(MOD_SOCK_SVR, LOG_INF, "准备向客户端广播话路状态包[%d]字节", nLineStatusResLen);
m_SocketMod.BoardcastPacket((const char *)pLineStatusRes, nLineStatusResLen);
delete pLineStatusRes;
pLineStatusRes = NULL;
bSleep = false;
}
//////////////////////////////////////////////////////////////////
// 3、定时存话单
//////////////////////////////////////////////////////////////////
if(time(NULL) - LastSaveBillTime >= g_Option.m_nSaveBillTimer)
{
OnSaveBills();
LastSaveBillTime = time(NULL);
bSleep = false;
}
if(bSleep)
{
Sleep(10);
}
}//end of while
// 释放消息队列中未发送完毕的话路状态信息包
while(PeekMessage(&msg, NULL, WM_SEND_LINESTATUS, WM_SEND_LINESTATUS, PM_REMOVE))
{
pLineStatusRes = (st_Pack_LineStatusRes *)msg.wParam;
delete pLineStatusRes;
}
return 0;
}
/************************************************************
OnClientGetTable
功 能:取表请求处理
性 质:private
输入参数:pPackReq - 请求包地址
nDataLen - 请求包长度
hSocket - 请求套接字
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::OnClientGetTable(void *pPackReq, int nDataLen, SOCKET hSocket)
{
// 表标识长度
const int nTableFlagLen = 4;
// 取表请求包
st_Pack_GetConfigReq * pGetConfigReq = NULL;
// 表标识
char sTableFlag[nTableFlagLen + 1];
// 发送标志
bool bSend = true;
// 响应包长度
int nResPackLen = 0;
// 取得的表长度
int nTableLen = 0;
// 取表响应包
st_Pack_GetConfigRes stGetConfigRes;
LOG_DBG(MOD_SOCK_SVR, LOG_INF, "收到取表请求...");
if(nDataLen != sizeof(st_Pack_GetConfigReq))
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "取表请求包长度[%d]错误", nDataLen);
return;
}
////////////////////////////////////////////////////////////////////////////
// 1.从请求包中取得表标识,根据表标识读取表内容
////////////////////////////////////////////////////////////////////////////
pGetConfigReq = (st_Pack_GetConfigReq *)pPackReq;
memset( &stGetConfigRes, 0, sizeof(stGetConfigRes) );
memset( sTableFlag, 0, sizeof(sTableFlag) );
memcpy( sTableFlag, pGetConfigReq->sTableFlag, nTableFlagLen );
switch(atoi(sTableFlag))
{
case TTELNUM:// 号码表
g_DataManage.GetTTelNum(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TFEERATEGRADE:// 费率等级表
g_DataManage.GetTFeeRateGrade(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TFEERATE:// 费率信息表
g_DataManage.GetTFeeRate(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TDISCOUNTDAY:// 日折扣表
g_DataManage.GetTDiscountDay(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TDISCOUNTWEEK:// 星期折扣表
g_DataManage.GetTDiscountWeek(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TDISCOUNTTIME:// 分段折扣表
g_DataManage.GetTDiscountTime(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TROOM:// 房间信息表
g_DataManage.GetTRoom(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TLINE:// 线路信息表
g_DataManage.GetTLine(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
case TOPERATOR:// 操作员表
g_DataManage.GetTOperator(stGetConfigRes.sTableComment, sizeof(stGetConfigRes.sTableComment), &nTableLen);
break;
default:
bSend = false;
LOG1(MOD_SOCK_SVR, LOG_ERR, "取表请求包表标志[%d]错误", atoi(sTableFlag));
break;
}
if(bSend)
{
////////////////////////////////////////////////////////////////////////////
// 2.发送响应包
////////////////////////////////////////////////////////////////////////////
// 包长度 = 包头16字节 + 表内容长度
nResPackLen = 16 + nTableLen;
_snprintf( stGetConfigRes.sPackLen, sizeof(stGetConfigRes.sPackLen) - 1,
"%d", nResPackLen );
// 包类型
_snprintf(stGetConfigRes.sPackType, sizeof(stGetConfigRes.sPackType) - 1,
"%d", PACK_GETCFG_RES);
// 表标识
strncpy( stGetConfigRes.sTableFlag, sTableFlag, sizeof(stGetConfigRes.sTableFlag) - 1 );
if(m_SocketMod.SendPacket((const char *)&stGetConfigRes, nResPackLen, hSocket))
{
LOG_DBG1(MOD_SOCK_SVR, LOG_INF, "取表响应包%d字节已成功发出", nResPackLen);
}
else
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "取表响应包发送失败,错误号:%d", GetLastError());
}
}
}
/************************************************************
OnClientSetTable
功 能:写表请求处理
性 质:private
输入参数:pPackReq - 请求包地址
nDataLen - 请求包长度
hSocket - 请求套接字
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::OnClientSetTable(void *pPackReq, int nDataLen, SOCKET hSocket)
{
// 表标识长度
const int nTableFlagLen = 4;
// 写表请求包
st_Pack_SetConfigReq * pSetConfigReq = NULL;
// 表标识
char sTableFlag[nTableFlagLen + 1];
// 表内容长度
int nTableLen = 0;
// 写表成功标志
bool bSetTableOK = false;
// 写表响应包
st_Pack_SetConfigRes SetConfigRes;
LOG_DBG(MOD_SOCK_SVR, LOG_INF, "收到写表请求...");
////////////////////////////////////////////////////////////////////////////
// 1.从请求包中取得表标识,根据表标识写表
////////////////////////////////////////////////////////////////////////////
pSetConfigReq = (st_Pack_SetConfigReq *)pPackReq;
memset( sTableFlag, 0, sizeof(sTableFlag) );
memcpy( sTableFlag, pSetConfigReq->sTableFlag, nTableFlagLen );
// 表内容长度 = 包长度 - 包头长度16字节
nTableLen = nDataLen - 16;
switch(atoi(sTableFlag))
{
case TTELNUM:// 号码表
bSetTableOK = g_DataManage.SetTTelNum(pSetConfigReq->sTableComment, nTableLen);
break;
case TFEERATEGRADE:// 费率等级表
bSetTableOK = g_DataManage.SetTFeeRateGrade(pSetConfigReq->sTableComment, nTableLen);
break;
case TFEERATE:// 费率信息表
bSetTableOK = g_DataManage.SetTFeeRate(pSetConfigReq->sTableComment, nTableLen);
break;
case TDISCOUNTDAY:// 日折扣表
bSetTableOK = g_DataManage.SetTDiscountDay(pSetConfigReq->sTableComment, nTableLen);
break;
case TDISCOUNTWEEK:// 星期折扣表
bSetTableOK = g_DataManage.SetTDiscountWeek(pSetConfigReq->sTableComment, nTableLen);
break;
case TDISCOUNTTIME:// 分段折扣表
bSetTableOK = g_DataManage.SetTDiscountTime(pSetConfigReq->sTableComment, nTableLen);
break;
case TROOM:// 房间信息表
bSetTableOK = g_DataManage.SetTRoom(pSetConfigReq->sTableComment, nTableLen);
break;
case TLINE:// 线路信息表
bSetTableOK = g_DataManage.SetTLine(pSetConfigReq->sTableComment, nTableLen);
break;
case TOPERATOR:// 操作员表
bSetTableOK = g_DataManage.SetTOperator(pSetConfigReq->sTableComment, nTableLen);
break;
default:
LOG1(MOD_SOCK_SVR, LOG_ERR, "写表请求包表标志[%d]错误", atoi(sTableFlag));
break;
}
////////////////////////////////////////////////////////////////////////////
// 2.发送响应包
////////////////////////////////////////////////////////////////////////////
memset( &SetConfigRes, 0, sizeof(SetConfigRes) );
// 包长度
_snprintf( SetConfigRes.sPackLen, sizeof(SetConfigRes.sPackLen) - 1,
"%d", sizeof(st_Pack_SetConfigRes) );
// 包类型
_snprintf(SetConfigRes.sPackType, sizeof(SetConfigRes.sPackType) - 1,
"%d", PACK_SETCFG_RES);
// 表标识
strncpy( SetConfigRes.sTableFlag, sTableFlag, sizeof(SetConfigRes.sTableFlag) - 1 );
// 写表结果
if(bSetTableOK)
{
_snprintf( SetConfigRes.sSuccFlag, sizeof(SetConfigRes.sSuccFlag) - 1,
"%d", CODE_OK);
}
else
{
_snprintf( SetConfigRes.sSuccFlag, sizeof(SetConfigRes.sSuccFlag) - 1,
"%d", CODE_ERR);
}
if(m_SocketMod.SendPacket((const char *) &SetConfigRes, sizeof(SetConfigRes), hSocket))
{
LOG_DBG(MOD_SOCK_SVR, LOG_INF, "写表响应包已成功发出");
}
else
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "写表响应包发送失败,错误号:%d", GetLastError());
}
}
/************************************************************
OnClientOpenRoom
功 能:开房请求处理
性 质:private
输入参数:pPackReq - 请求包地址
nDataLen - 请求包长度
hSocket - 请求套接字
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::OnClientOpenRoom(void *pPackReq, int nDataLen, SOCKET hSocket)
{
// 线路号长度
const int nLineIDLen = 8;
// 押金长度
const int nDepositLen = 8;
// 开房请求包
st_Pack_OpenRoomReq * pOpenRoomReq = NULL;
// 线路状态信息记录
st_TLineStatus_Rec stTLineStatusRec;
// 线路号
char sLineID[nLineIDLen + 1];
// 线路号
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -