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

📄 socketsvrthread.cpp

📁 PDA通讯网关服务器源码程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:

#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 + -