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

📄 sgiapi.cpp

📁 看到联通的接口协议的dll没
💻 CPP
📖 第 1 页 / 共 2 页
字号:

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