头文件
#pragma once
#include <QtNetwork>
#include <QObject>
#include <iostream>
#include <list>
#include "Include/DataDef.h"
#pragma execution_character_set("utf-8")
using namespace std;
class CUdpClient : public QObject
{
Q_OBJECT
public:
CUdpClient();
~CUdpClient();
void Init();
//同步发送
int SynSendData(ST_TRANS_MSG stMsg,int iTimeout);
//同步接收
int GetSyncMsgData(ST_TRANS_MSG &stOutData);
//异步发送
bool AsyncSendData(ST_TRANS_MSG stMsg);
void GetNetAddress(ST_COMM_INFO &stCommInfo);
int SetNetAddress(ST_COMM_INFO stCommInfo);
void CloseComm();
bool BindListenPort();
bool SendCommand(const unsigned char * pszCmd, int iCmdLength, int iTimeout,bool bIsResend = false);
bool ReSendSyscData(const unsigned char * pData, int iDataLength);
bool SendCommandEx(const unsigned char * pszCmd, int iCmdLength);
bool ReSendSyscDataEx(const unsigned char * pData, int iDataLength);
void GetLastCommandData(ST_TRANS_MSG &stlastData);
public:
//组包
virtual void Package(const unsigned char *pszSrcCmd, int iSrcCmdLen
, unsigned char *pszDestCmd, int *piDestLen);
//解包
virtual void UnPackage(const unsigned char*pszSrcPackage, int iSrcPackageLength,
unsigned char *pszValidData, int *piValidDataLength);
//检查报文的合法性
virtual bool CheckMsgHeadAndEnd(const char * pDataBuf, int iBufLen);
virtual bool JudgeIsValidityProtocal(const char * pDataBuf, int iBufLen);
//处理来自服务器的控制命令
virtual void ProServerCmd(RECV_DATA_TYPE, char cCmd);
virtual RECV_DATA_TYPE GetMsgType(char cMsgType);
//分拣处理数据
void SortProData(ST_TRANS_MSG stMsg);
//时间同步
void SysTimeWithServer(const char * pDataBuf, int iBufLen);
private:
void PushRecvData(ST_TRANS_MSG stRecvData);
void PopRecvData(ST_TRANS_MSG &stOutData);
void ClearList();
public slots:
void ProRecvData_Slot();
public:
int m_iSyncCallTimeout; //记录当前同步调用的timeout值
private:
int m_iServerPort; //服务器接收端口号
int m_iLocalProt;//本地接收端口号
QString m_strServerIp; //服务器IP
QString m_strRecvBuf;//接收到的数据
QUdpSocket *m_pUdpSocket;
int m_iRetryCounter;//重试次数
ST_TRANS_MSG m_stLastSendData;//上次同步发送的数据
ST_TRANS_MSG m_stLastAsyncSendData;//上次同步发送的数据
list<ST_TRANS_MSG> m_listSyncMsgData;
ST_TRANS_MSG m_SyncMsgDataBuf;
QMutex m_RecvDataMutex;
QMutex m_UdpMutex; //通信互斥锁
QSemaphore m_RecvDataSem;
bool m_bIsHaveSendData;//表示是否处于同步发送等待接收数据状态
};
源文件
#include "UdpClient.h"
#include <QMessageBox>
#include "TransLogWid/LogNotify.h"
#include "PublicFun/PublicFun.h"
extern CLogOperEx * g_StatusMonitorLog;
CUdpClient::CUdpClient()
{
Init();
}
CUdpClient::~CUdpClient()
{
if (NULL != m_pUdpSocket)
{
delete m_pUdpSocket;
m_pUdpSocket = NULL;
}
}
void CUdpClient::Init()
{
m_bIsHaveSendData = false;
m_pUdpSocket = NULL;
m_iServerPort =3000;
m_iLocalProt = 3001;
m_strServerIp = CPublicFun::getHostIpAddress();
//m_strServerIp = "192.168.1.100";
//创建Socket对象
m_pUdpSocket = new QUdpSocket(this);
connect(m_pUdpSocket, SIGNAL(readyRead()), this, SLOT(ProRecvData_Slot()));
//绑定本地监控端口
BindListenPort();
}
bool CUdpClient::BindListenPort()
{
bool result = m_pUdpSocket->bind(m_iLocalProt);
if (!result)
{
g_StatusMonitorLog->LogError("[%s][%s][%d] 绑定本地端口:%d 失败 ", __FILE__, __FUNCTION__, __LINE__,m_iLocalProt);
return false;
}
QString strShow("Bind Listen Port: ");
strShow.append(QString::number(m_iLocalProt));
CLogNotify::GetInstance().ShowMsgToHeartWid(strShow);
g_StatusMonitorLog->LogError("[%s][%s][%d] %s ", __FILE__, __FUNCTION__, __LINE__, strShow.toStdString().c_str());
return result;
}
bool CUdpClient::SendCommand(const unsigned char * pszCmd, int iCmdLength, int iTimeout, bool bIsResend)
{
if (!bIsResend)
{
//打包
Package(pszCmd, iCmdLength, (unsigned char*)m_stLastSendData.szData, &m_stLastSendData.iDataLen);
CPublicFun::ShowDataToLog("ST", (unsigned char*)m_stLastSendData.szData, m_stLastSendData.iDataLen);
//发送数据
int iLen = m_pUdpSocket->writeDatagram((char*)m_stLastSendData.szData, m_stLastSendData.iDataLen, QHostAddress(m_strServerIp), m_iServerPort);
if (iLen != m_stLastSendData.iDataLen)
{
g_StatusMonitorLog->LogError("[%s][%s][%d] WriteDatagram failed !", __FILE__, __FUNCTION__, __LINE__);
return false;
}
m_stLastSendData.iMsgType = EN_MSG_TYPE_SEND;
CLogNotify::GetInstance().ShowMsgToDataWid(m_stLastSendData);
}
else
{
QString strShow = QString("server没有反馈数据, 进行第 %1 次重发 ").arg(m_iRetryCounter);
CLogNotify::GetInstance().NotifyMsgToDataWid(strShow);
g_StatusMonitorLog->LogFatal("[%s][%s][%d] %s", __FILE__, __FUNCTION__, __LINE__, strShow.toStdString().c_str());
m_stLastSendData.iMsgType = EN_MSG_TYPE_SEND;
CLogNotify::GetInstance().ShowMsgToDataWid(m_stLastSendData);
ReSendSyscData((unsigned char*)m_stLastSendData.szData, m_stLastSendData.iDataLen);
}
int iSemResult;
while ((iSemResult = m_RecvDataSem.tryAcquire(1, iTimeout)) == false && errno == EINTR) continue; /*!<超时等待同步反馈信号量释放>*/
return iSemResult;
}
bool CUdpClient::SendCommandEx(const unsigned char * pszCmd, int iCmdLength)
{
return ReSendSyscDataEx(pszCmd, iCmdLength);
}
bool CUdpClient::ReSendSyscData(const unsigned char * pData, int iDataLength)
{
//发送数据
int iLen = m_pUdpSocket->writeDatagram((char*)m_stLastSendData.szData, m_stLastSendData.iDataLen, QHostAddress(m_strServerIp), m_iServerPort);
if (iLen != m_stLastSendData.iDataLen)
{
g_StatusMonitorLog->LogError("[%s][%s][%d] WriteDatagram failed !", __FILE__, __FUNCTION__, __LINE__);
return false;
}
return true;
}
bool CUdpClient::ReSendSyscDataEx(const unsigned char * pData, int iDataLength)
{
m_bIsHaveSendData = true;
bool bRet = true;
//发送数据
int iLen = m_pUdpSocket->writeDatagram((char*)m_stLastSendData.szData, m_stLastSendData.iDataLen, QHostAddress(m_strServerIp), m_iServerPort);
int iSemResult;
while ((iSemResult = m_RecvDataSem.tryAcquire(1, m_iSyncCallTimeout)) == false && errno == EINTR) continue; /*!<超时等待同步反馈信号量释放>*/
if (iSemResult)//收到数据
{
bRet = true;
}
else
{
g_StatusMonitorLog->LogError("[%s][%s][%d] 发送本地数据 failed !", __FILE__, __FUNCTION__, __LINE__);
CLogNotify::GetInstance().ShowMsgToDataWid("发送本地数据 failed");
bRet = false;
}
m_bIsHaveSendData = false;
return bRet;
}
void CUdpClient::GetLastCommandData(ST_TRANS_MSG &stlastData)
{
stlastData = m_stLastSendData;
}
void CUdpClient::ClearList()
{
m_RecvDataMutex.lock(); /*!<启动互斥锁>*/
m_listSyncMsgData.clear();
m_RecvDataMutex.unlock(); /*!<解除互斥锁>*/
}
void CUdpClient::Package(const unsigned char *pszSrcCmd, int iSrcCmdLen, unsigned char *pszDestCmd, int *piDestLen)
{
}
void CUdpClient::UnPackage(const unsigned char*pszSrcPackage, int iSrcPackageLength, unsigned char *pszValidData, int *piValidDataLength)
{
}
bool CUdpClient::CheckMsgHeadAndEnd(const char * pDataBuf, int iBufLen)
{
return 0;
}
bool CUdpClient::JudgeIsValidityProtocal(const char * pDataBuf, int iBufLen)
{
return true;
}
void CUdpClient::ProServerCmd(RECV_DATA_TYPE enProType, char cCmd)
{
}
RECV_DATA_TYPE CUdpClient::GetMsgType(char cMsgType)
{
return RECV_TYPE_Unknown;
}
void CUdpClient::PushRecvData(ST_TRANS_MSG stRecvData)
{
m_RecvDataMutex.lock();
m_listSyncMsgData.push_back(stRecvData);
m_RecvDataMutex.unlock();
}
void CUdpClient::PopRecvData(ST_TRANS_MSG &stOutData)
{
m_RecvDataMutex.lock();
if (m_listSyncMsgData.size() > 0)
{
stOutData = m_listSyncMsgData.front();
m_listSyncMsgData.pop_front();
}
else
{
CLogNotify::GetInstance().ShowMsgToDataWid("m_listSyncMsgData is NULL when GetSyncMsgData");
g_StatusMonitorLog->LogWarn("[%s][%s][%d] m_listSyncMsgData is NULL when GetSyncMsgData", __FILE__, __FUNCTION__, __LINE__);
}
m_RecvDataMutex.unlock();
}
int CUdpClient::SynSendData(ST_TRANS_MSG stMsg,int iTimeout)
{
m_UdpMutex.lock(); /*!<启动互斥锁>*/
//重置同步数据
ClearList();
int iRet = 0;
m_iSyncCallTimeout = iTimeout*1000;
bool bIsResend = false;
m_iRetryCounter = 0;
while (m_iRetryCounter < RESEND_TIMES)
{
m_bIsHaveSendData = true;
bool bSemResult = SendCommand(stMsg.szData, stMsg.iDataLen, m_iSyncCallTimeout, bIsResend);
if (bSemResult)/*!<收到反馈>*/ /*!<判断结果>*/
{
g_StatusMonitorLog->LogFatal("[%s][%s][%d] have Recv Data ......", __FILE__, __FUNCTION__, __LINE__);
CLogNotify::GetInstance().ShowMsgToDataWid("have Recv Data ......");
iRet = 0;
break;
}
else /*!<没有数据的信号发送的信号>*/
{
iRet = -1;
bIsResend = true;
m_iRetryCounter++;
CLogNotify::GetInstance().ShowMsgToDataWid("No Recv Data ......");
g_StatusMonitorLog->LogError("[%s][%s][%d]No Recv Data ...... ", __FILE__, __FUNCTION__, __LINE__);
}
}
m_bIsHaveSendData = false;
m_UdpMutex.unlock();
return iRet;
}
int CUdpClient::GetSyncMsgData(ST_TRANS_MSG &stOutData)
{
PopRecvData(stOutData);
return 0;
}
bool CUdpClient::AsyncSendData(ST_TRANS_MSG stMsg)
{
memset(&m_stLastAsyncSendData, 0, sizeof(ST_TRANS_MSG));
//打包
Package(stMsg.szData, stMsg.iDataLen, (unsigned char*)m_stLastAsyncSendData.szData, &m_stLastAsyncSendData.iDataLen);
CPublicFun::ShowDataToLog("Heat", m_stLastAsyncSendData.szData, m_stLastAsyncSendData.iDataLen);
//发送数据
int iLen = m_pUdpSocket->writeDatagram((char*)m_stLastAsyncSendData.szData, m_stLastAsyncSendData.iDataLen, QHostAddress(m_strServerIp), m_iServerPort);
if (iLen != m_stLastAsyncSendData.iDataLen)
{
g_StatusMonitorLog->LogError("[%s][%s][%d]haved send len: %d != need send len:%d ", __FILE__, __FUNCTION__, __LINE__, iLen, m_stLastAsyncSendData.iDataLen);
return false;
}
m_stLastAsyncSendData.iMsgType = stMsg.iMsgType;
CLogNotify::GetInstance().ShowMsgToHeartWid(m_stLastAsyncSendData);
return true;
}
void CUdpClient::GetNetAddress(ST_COMM_INFO &stCommInfo)
{
stCommInfo.strServerIP = m_strServerIp;
stCommInfo.iServerPort = m_iServerPort;
stCommInfo.iLocalPort = m_iLocalProt;
}
int CUdpClient::SetNetAddress(ST_COMM_INFO stCommInfo)
{
if (!stCommInfo.strServerIP.isEmpty())
{
m_strServerIp = stCommInfo.strServerIP;
}
if (0 != stCommInfo.iServerPort)
{
m_iServerPort = stCommInfo.iServerPort;
}
if (0 != stCommInfo.iLocalPort)
{
m_iLocalProt = stCommInfo.iLocalPort;
}
//先断开连接
CloseComm();
//绑定本地监听断开
BindListenPort();
return 0;
}
void CUdpClient::CloseComm()
{
m_pUdpSocket->close();
ST_TRANS_MSG stMsg;
stMsg.iMsgType = EN_MSG_TYPE_NOTIFY;
stMsg.iDataLen = sizeof("Close Connect");
memcpy(stMsg.szData, "Close Connect", sizeof("Close Connect"));
CLogNotify::GetInstance().ShowMsgToHeartWid(stMsg);
g_StatusMonitorLog->LogFatal("[%s][%s][%d] CloseComm ", __FILE__, __FUNCTION__, __LINE__);
}
void CUdpClient::SortProData(ST_TRANS_MSG stRecvMsg)
{
RECV_DATA_TYPE enRecvDataType = GetMsgType(stRecvMsg.szData[1]);
if (RECV_TYPE_DATA_ACK_81 == enRecvDataType)
{
if (m_bIsHaveSendData)
{
//放入接收队列中
PushRecvData(stRecvMsg);
m_RecvDataSem.release();//释放信号量
}
}
else if (RECV_TYPE_QUERY_82 == enRecvDataType)
{
ProServerCmd(RECV_TYPE_QUERY_82, stRecvMsg.szData[stRecvMsg.iDataLen - 9]);
}
else if (RECV_TYPE_CONL_83 == enRecvDataType)
{
ProServerCmd(RECV_TYPE_CONL_83, stRecvMsg.szData[stRecvMsg.iDataLen - 9]);
}
else //未知数据类型
{
CLogNotify::GetInstance().ShowMsgToHeartWid("Recv Unknown Type Data.....");
g_StatusMonitorLog->LogFatal("[%s][%s][%d] Recv Unknown Type Data ", __FILE__, __FUNCTION__, __LINE__);
}
}
void CUdpClient::SysTimeWithServer(const char * pDataBuf, int iBufLen)
{
if (NULL == pDataBuf || iBufLen < 2)
{
return ;
}
int iTime = 0;
memcpy(&iTime, &pDataBuf[14], 4);
CPublicFun::SetTime(iTime);
//获取 时间戳 + 2000年1月1日0点0分0秒 的 时间
QString strServerTime = CPublicFun::GetDateTimeStringByStamp(iTime);
QString strShow = QString("serverStamp: %1 strTime:%2").arg(strServerTime).arg(strServerTime.toStdString().c_str());
CLogNotify::GetInstance().ShowMsgToHeartWid(strShow);
g_StatusMonitorLog->LogFatal("[%s][%s][%d] %s ", __FILE__,
__FUNCTION__, __LINE__, strShow.toStdString().c_str());
}
void CUdpClient::ProRecvData_Slot()
{
//hasPendingDatagrams返回true时表示至少有一个数据报在等待被读取
while (m_pUdpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(m_pUdpSocket->pendingDatagramSize());
m_pUdpSocket->readDatagram(datagram.data(), datagram.size());
m_strRecvBuf = datagram.data();
if (!m_strRecvBuf.isEmpty() && CheckMsgHeadAndEnd(datagram.data(), datagram.size()))
{
CPublicFun::ShowDataToLog("RT",(unsigned char*)datagram.data(),datagram.size());
ST_TRANS_MSG stRecvData;
stRecvData.iMsgType = EN_MSG_TYPE_RECV;
//解包
UnPackage((unsigned char*)datagram.data(), datagram.size(), stRecvData.szData, &stRecvData.iDataLen);
bool bRet = JudgeIsValidityProtocal((char*)stRecvData.szData, stRecvData.iDataLen);
if (bRet)
{
//时间同步
SysTimeWithServer((char*)stRecvData.szData, stRecvData.iDataLen);
//分拣处理数据
SortProData(stRecvData);
}
CLogNotify::GetInstance().ShowMsgToDataWid(stRecvData);
}
}
}