📄 socketsvrthread.cpp
字号:
else
{
nCurLineNum = nTotalLineNum - nLineIndex;
}
// 计算包长度
nPacketLen = 20 + sizeof(st_Pack_LineStatusRec) * nCurLineNum;
// 包长度
_snprintf(stLineStatusRes.sPackLen, sizeof(stLineStatusRes.sPackLen) - 1,
"%d", nPacketLen);
// 包类型
_snprintf(stLineStatusRes.sPackType, sizeof(stLineStatusRes.sPackType) - 1,
"201");
// 总话路数
_snprintf(stLineStatusRes.sTotalLineNum, sizeof(stLineStatusRes.sTotalLineNum) - 1,
"%d", g_DataManage.GetLineNumber());
// 当前话路数
_snprintf(stLineStatusRes.sCurLineNum, sizeof(stLineStatusRes.sCurLineNum) - 1,
"%d", nCurLineNum);
// 线路状态信息记录
g_DataManage.LockTLineStatus();
for(i=0; i < nCurLineNum; i++)
{
g_DataManage.GetTLineStatusRec(nLineIndex, &stTLineStatusRec);
PackLineStatusRec(&stTLineStatusRec, NULL, &stLineStatusRes.stLineStatusRec[i]);
nLineIndex ++;
}
g_DataManage.UnlockTLineStatus();
// 发送
if(m_SocketMod.SendPacket((const char *)&stLineStatusRes, nPacketLen, hSocket))
{
LOG_DBG1(MOD_SOCK_SVR, LOG_INF, "线路状态信息响应包[%d字节]已成功发出", nPacketLen);
}
else
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "线路状态信息响应包发送失败,错误号:%d", GetLastError());
}
}//end while(nLineIndex < nTotalLineNum)
}
/************************************************************
OnClientOpenClose
功 能:开通关闭线路请求处理
性 质:private
输入参数:pPackReq - 请求包地址
nDataLen - 请求包长度
hSocket - 请求套接字
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::OnClientOpenClose(void *pPackReq, int nDataLen, SOCKET hSocket)
{
// 线路号长度
const int nLineIDLen = 8;
// 命令长度
const int nCmdLen = 2;
// 线路控制请求包
st_Pack_OpenCloseReq * pOpenCloseReq = NULL;
// 线路号
char sLineID[nLineIDLen + 1];
// 线路号
int nLineID = 0;
// 控制命令
char sLineCtrlCmd[nCmdLen + 1];
// 控制命令
int nLineCtrlCmd = 0;
LOG_DBG(MOD_SOCK_SVR, LOG_INF, "收到打开关闭请求...");
if(nDataLen != sizeof(st_Pack_OpenCloseReq))
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "打开关闭请求包长度[%d]错误", nDataLen);
return;
}
////////////////////////////////////////////////////////////////////////////
// 1.检查请求包中的线路号、控制命令
////////////////////////////////////////////////////////////////////////////
pOpenCloseReq = (st_Pack_OpenCloseReq *)pPackReq;
// 检查线路号
memset( sLineID, 0, sizeof(sLineID) );
memcpy( sLineID, pOpenCloseReq->sLineNo, nLineIDLen);
nLineID = atoi(sLineID);
if( (nLineID < 0) || (nLineID > g_DataManage.GetLineNumber()) )
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "线路控制请求包中线路号[%d]错误", nLineID);
return;
}
// 检查命令
memset( sLineCtrlCmd, 0, sizeof(sLineCtrlCmd) );
memcpy( sLineCtrlCmd, pOpenCloseReq->sLineState, nCmdLen );
nLineCtrlCmd = atoi(sLineCtrlCmd);
if( (nLineCtrlCmd != 0) && (nLineCtrlCmd != 1) )
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "线路控制请求包中控制命令[%d]错误", nLineCtrlCmd);
return;
}
////////////////////////////////////////////////////////////////////////////
// 2.发消息到卡消息处理线程
////////////////////////////////////////////////////////////////////////////
if(g_pCommSvrThread->PostThreadMessage(WM_USER + nLineID, nLineCtrlCmd, 0))
{
LOG_DBG2(MOD_SOCK_SVR, LOG_INF, "已向卡消息处理线程发送消息,线路号:%d,命令:%d",
nLineID, nLineCtrlCmd);
}
else
{
LOG1(MOD_SOCK_SVR, LOG_INF, "向卡消息处理线程发送消息失败,错误号:%d:", GetLastError());
}
}
/************************************************************
OnSaveBills
功 能:定时保存话单
性 质:private
输入参数:无
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::OnSaveBills()
{
// 话路状态信息记录
static st_TLineStatus_Rec stTLineStatusRec[MAX_TLINE_RECNUM];
// 临时变量
int i=0;
LOG_DBG(MOD_SOCK_SVR, LOG_INF, "定时保存话单...");
// 获取所有话路状态信息记录
g_DataManage.LockTLineStatus();
for(i=0; i<g_DataManage.GetLineNumber(); i++)
{
g_DataManage.GetTLineStatusRec(i, &stTLineStatusRec[i]);
}
g_DataManage.UnlockTLineStatus();
// 将呼入或呼出状态的话路生成话单,写入数据库
try
{
m_dbConn.BeginTrans();
for(i=0; i<g_DataManage.GetLineNumber(); i++)
{
if( (stTLineStatusRec[i].nLineState == LINE_STATE_TALKING) ||
(stTLineStatusRec[i].nLineState == LINE_STATE_RECV) )
{
SaveBill(&stTLineStatusRec[i]);
}
}
m_dbConn.CommitTrans();
LOG_DBG(MOD_SOCK_SVR, LOG_INF, "定时保存话单成功");
}
catch(_com_error & e)
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "定时保存话单失败:%s", ADO_ERR_MSG(e));
try
{
if( m_dbConn.GetState() != adStateClosed ) m_dbConn.RollbackTrans();
// 重新连接数据库
LOG(MOD_SOCK_SVR, LOG_ERR, "重建数据库连接...");
m_dbConn.Close();
m_dbConn.Open(g_Option.m_strConnStr);
}
catch(_com_error & e)
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "连接数据库失败:%s", ADO_ERR_MSG(e));
}
}
}
/************************************************************
SaveBill
功 能:保存某线路的话单
性 质:private
输入参数:pTLineStatusRec - 线路状态信息
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::SaveBill(st_TLineStatus_Rec *pTLineStatusRec)
{
// 记录集
CADORecordset res;
// SQL语句
CString strSQL;
// 开始时间
CString strStartTime;
// 线路表记录
st_TLine_Rec stTLineRec;
// 取最新的房间号
g_DataManage.GetTLineRec(pTLineStatusRec->nLineID - 1, &stTLineRec);
strStartTime.Format("%04d-%02d-%02d %02d:%02d:%02d",
pTLineStatusRec->dtStartTime.wYear,
pTLineStatusRec->dtStartTime.wMonth,
pTLineStatusRec->dtStartTime.wDay,
pTLineStatusRec->dtStartTime.wHour,
pTLineStatusRec->dtStartTime.wMinute,
pTLineStatusRec->dtStartTime.wSecond);
// 查找记录是否已存在
strSQL.Format("SELECT COUNT(*) AS recnum "
" FROM tbill"
" WHERE nLineID=%d AND StartTime='%s'",
pTLineStatusRec->nLineID,
strStartTime);
res.Open(strSQL, &m_dbConn);
if(res.GetFieldInt("recnum") == 0)
{
// 插入记录
strSQL.Format("INSERT INTO tbill"
"(nLineID, sRoomNo, StartTime, nTimeLong, dMoney, sCallerNum, sCalledNum, nFeeRateGrade, nReckoningFlag, dRemainDeposit, sLineState)"
" VALUES (%d, '%s', '%s', %d, %.2f, '%s', '%s', %d, 0, %.2f, '%s')",
pTLineStatusRec->nLineID,
stTLineRec.sRoomNo,
strStartTime,
pTLineStatusRec->nTime,
pTLineStatusRec->nMoney / 100.0,
pTLineStatusRec->sCallerNum,
pTLineStatusRec->sCalledNum,
pTLineStatusRec->nFeeRateGrade,
pTLineStatusRec->nRemainDeposit / 100.0,
g_pCommSvrThread->LineStateToString(pTLineStatusRec->nLineState));
m_dbConn.Execute(strSQL);
}
else
{
// 修改时长和金额
strSQL.Format("UPDATE tbill"
" set nTimeLong = %d, dMoney = %.2f, dRemainDeposit = %.2f, sLineState = '%s'"
" WHERE nLineID=%d AND StartTime='%s'",
pTLineStatusRec->nTime,
pTLineStatusRec->nMoney / 100.0,
pTLineStatusRec->nRemainDeposit / 100.0,
g_pCommSvrThread->LineStateToString(pTLineStatusRec->nLineState),
pTLineStatusRec->nLineID,
strStartTime);
m_dbConn.Execute(strSQL);
}
res.Close();
}
/************************************************************
PackLineStatusRec
功 能:生成话路状态包记录。
如果sException参数不为空就生成异常状态信息;否则生成
正常状态信息。
性 质:private
输入参数:pTLineStatusRec - 线路状态信息
sException - 异常信息
输出参数:pPackLineStatusRec - 话路状态包记录
返 回 值:无
************************************************************/
void CSocketSvrThread::PackLineStatusRec(const st_TLineStatus_Rec *pTLineStatusRec,
const char * sException,
st_Pack_LineStatusRec *pPackLineStatusRec)
{
ASSERT(pTLineStatusRec);
// 要附带给客户端的信息
st_Pack_LineStatusTag * pLineStatusTag = NULL;
// 拨号信息
st_Pack_DialInfo * pDialInfo = NULL;
// 呼入信息
st_Pack_CallinInfo * pCallinInfo = NULL;
// 呼出及挂机信息
st_Pack_CalloutInfo * pCalloutInfo = NULL;
// 异常信息
st_Pack_ErrorInfo * pErrorInfo = NULL;
// 线路表记录
st_TLine_Rec stTLineRec;
memset(pPackLineStatusRec, 0, sizeof(st_Pack_LineStatusRec));
// 线路号
_snprintf(pPackLineStatusRec->sLineNo, sizeof(pPackLineStatusRec->sLineNo)-1,
"%d", pTLineStatusRec->nLineID);
// 房间号
g_DataManage.GetTLineRec(pTLineStatusRec->nLineID - 1, &stTLineRec);
strncpy(pPackLineStatusRec->sRoomNo, stTLineRec.sRoomNo,
sizeof(pPackLineStatusRec->sRoomNo) - 1);
if(pTLineStatusRec->bUseFlag)
{
// 押金
_snprintf(pPackLineStatusRec->sDeposit, sizeof(pPackLineStatusRec->sDeposit)-1,
"%.2f", pTLineStatusRec->nDeposit / 100.0);
// 剩余押金
_snprintf(pPackLineStatusRec->sRemainDeposit, sizeof(pPackLineStatusRec->sRemainDeposit)-1,
"%.2f", pTLineStatusRec->nRemainDeposit / 100.0);
}
// 占用标志
_snprintf(pPackLineStatusRec->sUseFlag, sizeof(pPackLineStatusRec->sUseFlag)-1,
"%d", pTLineStatusRec->bUseFlag);
// 要附带给客户端的信息
if(sException)
{// 异常话路信息
// 线路状态
_snprintf(pPackLineStatusRec->sLineState, sizeof(pPackLineStatusRec->sLineState)-1,
"%d", LINE_STATE_ERROR);
pErrorInfo = &pPackLineStatusRec->m_st_Pack_LineStatusTag.m_st_Pack_ErrorInfo;
strncpy( pErrorInfo->sDiscription, sException,
sizeof(pErrorInfo->sDiscription) - 1 );
}
else
{// 正常话路状态信息
// 线路状态
_snprintf(pPackLineStatusRec->sLineState, sizeof(pPackLineStatusRec->sLineState)-1,
"%d", pTLineStatusRec->nLineState);
switch(pTLineStatusRec->nLineState)
{
case LINE_STATE_OPEN: // 开通信息
case LINE_STATE_CLOSE: // 关闭信息
case LINE_STATE_UNKNOW: // 未知状态信息
break;
case LINE_STATE_DIAL: // 拨号信息
pDialInfo = &pPackLineStatusRec->m_st_Pack_LineStatusTag.m_st_Pack_DialInfo;
// 目的地名称
strncpy(pDialInfo->sAddress, pTLineStatusRec->sAddress,
sizeof(pDialInfo->sAddress) - 1);
// 被叫号码
strncpy(pDialInfo->sCalledNum, pTLineStatusRec->sCalledNum,
sizeof(pDialInfo->sCalledNum) - 1);
break;
case LINE_STATE_RECV: // 呼入信息
pCallinInfo = &pPackLineStatusRec->m_st_Pack_LineStatusTag.m_st_Pack_CallinInfo;
// 被叫号码
strncpy(pCallinInfo->sCalledNum, pTLineStatusRec->sCalledNum,
sizeof(pCallinInfo->sCalledNum) - 1);
// 开始时间
_snprintf(pCallinInfo->sStartTime, sizeof(pCallinInfo->sStartTime)-1,
"%04d-%02d-%02d %02d:%02d:%02d",
pTLineStatusRec->dtStartTime.wYear,
pTLineStatusRec->dtStartTime.wMonth,
pTLineStatusRec->dtStartTime.wDay,
pTLineStatusRec->dtStartTime.wHour,
pTLineStatusRec->dtStartTime.wMinute,
pTLineStatusRec->dtStartTime.wSecond);
// 时长
_snprintf(pCallinInfo->sTimeLen, sizeof(pCallinInfo->sTimeLen) - 1,
"%d", pTLineStatusRec->nTime);
// 金额
_snprintf(pCallinInfo->sMoney, sizeof(pCallinInfo->sMoney) - 1,
"%.2f", pTLineStatusRec->nMoney / 100.0);
break;
case LINE_STATE_HANDON: // 挂机信息
if(pTLineStatusRec->dtStartTime.wYear == 0)
{
break;
}
case LINE_STATE_TALKING: // 呼出信息
pCalloutInfo = &pPackLineStatusRec->m_st_Pack_LineStatusTag.m_st_Pack_CalloutInfo;
// 主叫号码
strncpy(pCalloutInfo->sCallerNum, pTLineStatusRec->sCallerNum,
sizeof(pCalloutInfo->sCallerNum) - 1);
// 被叫号码
strncpy(pCalloutInfo->sCalledNum, pTLineStatusRec->sCalledNum,
sizeof(pCalloutInfo->sCalledNum) - 1);
// 目的地名称
strncpy(pCalloutInfo->sAddress, pTLineStatusRec->sAddress,
sizeof(pCalloutInfo->sAddress) - 1);
// 开始时间
_snprintf(pCalloutInfo->sStartTime, sizeof(pCalloutInfo->sStartTime) - 1,
"%04d-%02d-%02d %02d:%02d:%02d",
pTLineStatusRec->dtStartTime.wYear,
pTLineStatusRec->dtStartTime.wMonth,
pTLineStatusRec->dtStartTime.wDay,
pTLineStatusRec->dtStartTime.wHour,
pTLineStatusRec->dtStartTime.wMinute,
pTLineStatusRec->dtStartTime.wSecond);
// 时长
_snprintf(pCalloutInfo->sTimeLen, sizeof(pCalloutInfo->sTimeLen) - 1,
"%d", pTLineStatusRec->nTime);
// 金额
_snprintf(pCalloutInfo->sMoney, sizeof(pCalloutInfo->sMoney) - 1,
"%.2f", pTLineStatusRec->nMoney / 100.0);
break;
default:
ASSERT(0);
}// end switch
}// end if(sException)
}
/************************************************************
BoradcastLineStatus
功 能:生成话路状态包记录并广播给所有客户端
性 质:private
输入参数:pTLineStatusRec - 线路状态信息
输出参数:无
返 回 值:无
************************************************************/
void CSocketSvrThread::BoradcastLineStatus(st_TLineStatus_Rec *pTLineStatusRec)
{
// 线路状态信息包
st_Pack_LineStatusRes stLineStatusRes;
// 总线路数
int nTotalLineNum = 0;
// 当前状态包中话路数
int nCurLineNum = 1;
// 数据包长度
int nPacketLen = 0;
// 状态包清0
memset( &stLineStatusRes, 0, sizeof(stLineStatusRes) );
// 计算包长度
nPacketLen = 20 + sizeof(st_Pack_LineStatusRec) * nCurLineNum;
// 包长度
_snprintf(stLineStatusRes.sPackLen, sizeof(stLineStatusRes.sPackLen) - 1,
"%d", nPacketLen);
// 包类型
_snprintf(stLineStatusRes.sPackType, sizeof(stLineStatusRes.sPackType) - 1,
"201");
// 总话路数
_snprintf(stLineStatusRes.sTotalLineNum, sizeof(stLineStatusRes.sTotalLineNum) - 1,
"%d", g_DataManage.GetLineNumber());
// 当前话路数
_snprintf(stLineStatusRes.sCurLineNum, sizeof(stLineStatusRes.sCurLineNum) - 1,
"%d", nCurLineNum);
// 线路状态信息
PackLineStatusRec(pTLineStatusRec, NULL, &stLineStatusRes.stLineStatusRec[0]);
// 发送
if(m_SocketMod.BoardcastPacket((const char *)&stLineStatusRes, nPacketLen))
{
LOG_DBG1(MOD_SOCK_SVR, LOG_INF, "线路状态信息广播包[%d字节]已成功发出", nPacketLen);
}
else
{
LOG1(MOD_SOCK_SVR, LOG_ERR, "线路状态信息广播包发送失败,错误号:%d", GetLastError());
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -