📄 sgiapi.cpp
字号:
#include "sgipapi.h"
#include "sgip_function.h"
using namespace std;
/************************************************************************************
网关接入sp处理,
创建上行工作,获取socket处理上行接收状态
*/
CJobSgip::CJobSgip(SOCKET &hSocket, CSgip* sgip, unsigned remoteport)
{
m_sgip = sgip;
sp_conn.hSocket = hSocket; //网关连接sp信息结构体
sp_conn.remotePort = remoteport;
sp_conn.fBinded = false;
sp_conn.fBusy = false;
sp_conn.nCount = 0;
sp_conn.nSrcNum = 0; //不清楚是啥数
nType = 1; //上行消息处理
}
/*
下行操作,
*/
CJobSgip::CJobSgip(sgipg_submit pss, CSgip* sgip, unsigned int nSeq, unsigned int nDateTime)
{
m_sgip = sgip;
m_nSeq = nSeq;
m_nDateTime = nDateTime;
nType = 2; //下行消息处理
}
CJobSgip::~CJobSgip()
{
m_sgip = NULL;
}
/*
接受上行MO信息处理
处理后发送
*/
void CJobSgip::RecvMOProc()
{
sgipg_deliver *pkdeliver = NULL;
sgipg_report *pkreport = NULL;
CString sLoginName,sPeerPwd;
sgipg_head sh;
sgipg_packet sp;
int nTimeOut = 10;
int iLen,
iRetResp = 0;
while(1)
{
iLen = sgip_recv(&sp_conn, &sp, nTimeOut);
if (iLen != -1)
{
memcpy(&sh.nSequenceId,&sp.pk_head.nSequenceId, sizeof(sgipg_seqid)); //拷贝序列号
//解包处理,则所有的解包在这里处理,处理完后通知onDeliver
switch(sp.pk_head.nCommandId)
{
case SGIP_BIND: //smg发送login包
sLoginName = m_sgip->GetPeerName();
sPeerPwd = m_sgip->GetPeerPwd();
if((strcmp(sp.pk_data.pk_login.sLoginName, (LPCSTR)sLoginName) == 0)
&& strcmp(sp.pk_data.pk_login.sLoginPwd, (LPCSTR)sPeerPwd) == 0)
{
iRetResp = 0;
sh.nCommandId = SGIP_BIND_RESP; //返回bind_reponse 包信息
}else
{
//关闭连接
m_sgip->RemoveSmgConn(sp_conn.hSocket);
return;
}
break;
case SGIP_UNBIND: //smg 申请断开
sh.nCommandId = SGIP_UNBIND_RESP;
sgip_auto_resp(&sp_conn, &sh, iRetResp);
m_sgip->RemoveSmgConn(sp_conn.hSocket);
return;
//break;
case SGIP_DELIVER: //smg 上行用户信息
pkdeliver = (sgipg_deliver*)&sp.pk_data;
DeliverStr deliverStr;
//如果信息错误应该返回错误代码
deliverStr.nSrcNum = sp.pk_head.nSequenceId.nSrcNodeNum;
deliverStr.nDateTime = sp.pk_head.nSequenceId.nDateTime;
deliverStr.nSeq = sp.pk_head.nSequenceId.nSeqId;
deliverStr.nMsgLen = SGIP_DELIVERLEN;
strcpy(deliverStr.sUserNumber, pkdeliver->sUserNumber);
strcpy(deliverStr.sSPNumber, pkdeliver->sSpNumber);
deliverStr.tp_pid = pkdeliver->cTpPid;
deliverStr.tp_udhi = pkdeliver->cUdhi;
deliverStr.cMsgCoding = pkdeliver->cMsgCoding;
deliverStr.nMsgLen = pkdeliver->nMsgLen;
strcpy((char*)deliverStr.sMsgContent,(char*) pkdeliver->sMsgContent);
strcpy(deliverStr.sLinkId, pkdeliver->sLinkId);
iRetResp = m_sgip->OnDeliver(deliverStr); //传递出去处理,处理完后返回
sh.nCommandId = SGIP_DELIVER_RESP;
break;
case SGIP_REPORT: //smg ->report
pkreport = (sgipg_report*)&sp.pk_data;
//整理出reportstr 给用户
ReportStr reportStr;
reportStr.nSrcNum = sp.pk_head.nSequenceId.nSrcNodeNum;
reportStr.nDateTime = sp.pk_head.nSequenceId.nDateTime;
reportStr.nSeq = sp.pk_head.nSequenceId.nSeqId;
strcpy(reportStr.sUserNumber, pkreport->sUserNumber);
reportStr.cState = pkreport->cState;
reportStr.cErrcode = pkreport->cErrorCode;
reportStr.cReportType = pkreport->cReportType;
strcpy(reportStr.sReserved, pkreport->sReserved);
reportStr.nSubmitSeq = pkreport->nSubmitSeqNum.nSeqId;
reportStr.nSubmitDateTime = pkreport->nSubmitSeqNum.nDateTime; //提交时间,这个字段???
//响应事件
iRetResp = m_sgip->OnReport(reportStr);
sh.nCommandId = SGIP_REPORT_RESP;
break;
}
//回复response
sgip_auto_resp(&sp_conn, &sh, iRetResp);
}
else //网关接收断开情况
{
m_sgip->RemoveSmgConn(sp_conn.hSocket);
break;
}
}
}
/*
MT处理
下行过程处理,其下行完后要处理response。若采用短连接,可以发完退出
1.检查bind,如果未bind,则需要bind处理
2.发送完以后recv,如果recv没有,直到取到为止。
当多条sumbit发送时,采用并发的socket来处理,
若连接网关的socket只有一个时,
recv会处于阻塞状态,直到recv完以后才能发送下一条.
response不见得马上返回,估计还有个过程
发送SUBMIT消息失败时调用该函数 OnMTError()
MT_Error的错误码描述:
1:因为连接不上SMG网关系统
2:登录网关失败
3:包发送失败且超过重发次数
4. 超时无应答
5. 消息长度为零
6. 没有可用的连接
*/
void CJobSgip::SendMTProc()
{
sgipg_submit cs;
sgip_submit_sm_init(&cs);
int iCheckConn = 0,
nConnIndex,iRet, nTimeOut = 100;
MTErrorStr mterror;
mterror.nErrorType = 0;
while(1)
{
//选择一个空闲的socket发送
if (sp_conn.hSocket == NULL || sp_conn.fBusy)
{
sgip_conn * freeConn = m_sgip->GetSubmitConn(nConnIndex); //是指针
sp_conn.hSocket = freeConn->hSocket;
sp_conn.remotePort = freeConn->remotePort;
sp_conn.nCount = freeConn->nSrcNum;
sp_conn.fBinded = freeConn->fBinded;
}
if (!sp_conn.fBusy)
{
m_sgip->ChangeStatus(nConnIndex, true); //改变忙状态
iRet = m_sgip->LoginSmg(&sp_conn); //登陆
if (iRet != 0)
{
m_sgip->ChangeStatus(nConnIndex, false);
mterror.nErrorType = 2; //登陆失败
goto errorProcess;
}
iRet = sgip_submit(&sp_conn, &ss, m_nSeq, m_nDateTime);
if(iRet != SGIP_SUCCESS)
{
// 3:包发送失败且超过重发次数
// 4. 超时无应答
// 5. 消息长度为零
m_sgip->ChangeStatus(nConnIndex, false);
mterror.nErrorType = iRet; //返回错误结果
goto errorProcess;
}
else
{
break;
}
}
iCheckConn++;
//没有找到可以用的连接
if(iCheckConn > 100)
{
mterror.nErrorType = 6;
goto errorProcess;
}
}
//调用错误处理
errorProcess:
if (mterror.nErrorType > 0)
{
mterror.nID = 0;
mterror.nSrcNum = sp_conn.nSrcNum;
mterror.nDateTime = m_nDateTime;
mterror.nSeq = m_nSeq;
memcpy(&mterror.ss, &ss, sizeof(ss));
m_sgip->OnMTError(mterror);
}
}
/*************************************************************
CWorkerSgip 类
nType == 1 上行模式 RecvMoProc
== 2 下行接受 SendMTPorc
*/
void CWorkerSgip::ProcessJob( IJobDesc* pJobDesc )
{
CJobSgip * tmpJob = (CJobSgip*)pJobDesc;
if (tmpJob->nType == 1)
tmpJob->RecvMOProc();
else
if (tmpJob->nType == 2)
//下行发送模式
tmpJob->SendMTProc();
}
/**************************************************************************************
CSgip 类
构造函数,初始化WinSock,初始化变量值
*/
CSgip::CSgip():submitCountTotal(0),submitSucceedCountTotal(0),submitFailedCountTotal(0),respSucceedCountTotal(0),
respFailedCountTotal(0), deliverCountTotal(0), sreportCountTotal(0)
{
WSADATA wsaD;
WORD m_wVersion = MAKEWORD(2,2); // Version number requested
int result = WSAStartup( m_wVersion, &wsaD ); // Initialize Winsock
if( result != 0 )
{
//set_LastError( "WSAStartup failed!", WSAGetLastError() );
return;
}
}
/*
析构函数,释放WinSock
*/
CSgip::~CSgip()
{
WSACleanup();
}
/*
启动本地监听,连接网关,和启动线城池。
1.在调用Start函数启动后,如果想重新调用Start函数,
* 必须首先调用Release函数释放资源才能重新调用Start函数,否则会调用失败。
* 2.可以通过设定nLocalPort = -1,或nPeerPort = -1实现收发分离功能。
* @param sLocalIP SGIP本地监听地址
* @param nLocalPort SGIP的本地监听端口(注意:如果设为-1则不启动本地监听,即不接收网关的连接和消息,只启用发送功能)
* @param sPeerIP 联通网关地址
* @param nPeerPort 联通网关端口(注意:如果设为-1,则不连接网关,即不执行发送功能,可以只接收MO消息)
* @param sLoginName 登录联通网关的用户名
* @param sLoginPwd 登录联通网关的口令
* @param nConnType 登录网关的连接类型(按照协议规定,应该一直是1。<1:SP向SMG建立的连接,用于发送命令>)
* @param sSrcNum 源节点编号(SP的编号规则:3AAAAQQQQQ AAAA表示四位长途区号,QQQQQ表示5位企业代码。详见协议3.3)
* @param nConnCount 同网关建立的发送连接数
* @param sPeerName 网关登录SP的用户名(如果用户名或者口令为空的话,则不对网关连接进行用户名口令鉴权)
* @param sPeerPwd 网关登录SP的口令
* @param nMaxSmgConn 允许的网关到SP的最大连接数
* @param nMinWorkThreadsCount 线程池的最小线程数(即初始线程数,建议为CPU个数*2 + 2)
* @param nMaxWorkThreadsCount 线程池的最大线程数(建议为CPU个数*2 + 6,线程池会根据忙碌状态在此范围内自动调整)
* @return 0:成功; -1:失败
启动连接网关,同时bind后发送,
完了以后,等待submit
*/
int CSgip::Start(char *sLocalIP, int nLocalPort, char *sPeerIP,
int nPeerPort, char *sLoginName, char *sLoginPwd,
int nConnType, char *sSrcNum, int nConnCount,
char *sPeerName, char *sPeerPwd , unsigned nMaxSmgConn ,
unsigned nMinWorkThreadsCount ,unsigned nMaxWorkThreadsCount)
{
m_sLocalIPAddr = sLocalIP;
m_nLocalPort = nLocalPort;
m_sPeerAddr = sPeerIP;
m_nPeerPort = nPeerPort;
m_sUserName = sLoginName;
m_sPwd = sLoginPwd;
m_nConnType = nConnType; //连接类型,1 = sp 到网关, 2 = ? 网关到sp?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -