⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socketsvrthread.cpp

📁 PDA通讯网关服务器源码程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		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 + -