📄 systemexit.cpp
字号:
/**********************************************************************
FileName : SystemExit.cpp
Description : 网关系统安全退出模块
Version : 1.0
Date : 2003年10月27日
Author : 刘荣辉
Other :
***********************************************************************/
#include "GateWay.h"
//===============网关系统退出信号处理函数===================
void CGateWay::ExitSig(int sig)
{
printf("\n Notice: Got Signal[%d] = [%s].\n",sig,strsignal(sig));
CGateWay::ToExit = 1;
return;
}
void CGateWay::SetTSD(int signo) //线程TSD置1
{
//printf("\n SetTSD========== \n");
*(int*)pthread_getspecific(ThreadKey)=1;
return;
}
//===================网关系统安全退出模块===================
void CGateWay::SafeExit()
{
int RetCode;
char FileName[80]; //备份文件路径名
int PackType,RecvNum,SendNum;
int RecvBak,SendBak;
RecvQUnit RUnit;
SendQUnit SUnit;
char sSysEvent[SYS_EVENT_LEN]; //记录系统事件的字符串
FileOpr *Qbackup = new FileOpr(); //用于将队列单元备份到文件的操作对象
strcpy(sSysEvent,"LOG: Got Terminate Signal,System is preparing to exit....");
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG); //写系统日志
//退出网关控制台线程
if(ConsoleThr)
pthread_kill(ConsoleThr, SIGUSR1);
//退出MO、MT短消息分发线程
if(MTForwordThr)
pthread_kill(MTForwordThr, SIGUSR1);
if(MOForwordThr)
pthread_kill(MOForwordThr, SIGUSR1);
//退出下端连接监听线程
if(DnListenThr)
pthread_kill(DnListenThr, SIGUSR1);
int AliveUpNode=0; //在线上节点数
int AliveDnNode; //在线下节点数
for(int i=0;i<UPNODE_NUM; i++) //检查在线上节点数
{
UpNode[i].ToExit=1; //置退出标识
if(UpNode[i].State==0)
AliveUpNode++;
if(UpNode[i].WriteThr)
pthread_kill(UpNode[i].WriteThr, SIGUSR1); //退出所有上节点发送线程
}
Map_Pos Pos;
CDnNode *theDnNode;
Sock_CP_Map.PosInit(&Pos);
while(1)
{
RetCode = Sock_CP_Map.GetNext((char **)&theDnNode, &Pos);
if(theDnNode==NULL || RetCode<0) //读到的是最后一个元素或者早已为空,下次将从头开始取
break;
theDnNode->ToExit=1; //置退出标识
if(theDnNode->SendThr)
pthread_kill(theDnNode->SendThr, SIGUSR1); //退出所有下节点的发送线程
}
//================轮流检查各在线节点,找适当时机断开连接================
while(1)
{
if(AliveUpNode)
{
for(int i=0;i<UPNODE_NUM; i++) //检查一遍所有在线上节点
{
//检查各节点的已发送队列是否为空
if(UpNode[i].SentQ.IsEmpty())
{
UpNode[i].SendLogout(); //直接发送Logout包
/*是否需要?
RetCode = shutdown(UpNode[i].TcpSock.sock, SHUT_RDWR); //关闭连接,对应收发线程将退出
if(RetCode)
{
sprintf(sSysEvent,"Error: Failed to shutdown the socket of UpNode[%d]!",UpNode[i].NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG); //写系统日志
}*/
AliveUpNode--;
#ifdef DEBUG
printf("\n SafeExit: Connection[%d] to UpNode[%d] is cut!RetCode=[%d].\n",UpNode[i].TcpSock.sock,UpNode[i].NodeID,RetCode);
#endif
}
}
}//if(AliveUpNode)
AliveDnNode = Sock_CP_Map.GetSize(); //在线下节点数
if(AliveDnNode)
{
for(;;) //检查一遍所有在线下节点
{
//获取下一个下节点的指针
theDnNode=NULL;
RetCode = Sock_CP_Map.GetNext((char **)&theDnNode, &Pos);
if(theDnNode==NULL || RetCode<0) //读到的是最后一个元素或者早已为空,下次将从头开始取
break;
if(theDnNode->SentQ.IsEmpty()) //检查下节点的已发送队列是否为空
{
RetCode = shutdown(theDnNode->TcpSock.sock, SHUT_RDWR); //关闭连接,对应发送线程将退出
if(RetCode)
{
sprintf(sSysEvent,"Error: Failed to shutdown the socket of DnNode[%d]!",theDnNode->NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG); //写系统日志
}
AliveDnNode--;
#ifdef DEBUG
printf("\n SafeExit: Connection to DnNode[%d] is cut!\n",theDnNode->NodeID);
#endif
if(!AliveDnNode) //最后一个下节点的连接被关闭后
{
if(DnRecvThr)
pthread_kill(DnRecvThr, SIGUSR1); //退出DnReceiver
break;
}
}
}//for(;;)
}//if(AliveDnNode)
if(AliveUpNode==0 && AliveDnNode==0) //所有节点都已断开
break;
}//while(1)
//退出上、下端接收队列轮询处理线程
if(UpRecvQ_PollThr)
pthread_kill(UpRecvQ_PollThr, SIGUSR2);
if(DnRecvQ_PollThr)
pthread_kill(DnRecvQ_PollThr, SIGUSR2);
//退出上、下端已发送队列定时(轮询)线程
if(UpSentQ_PollThr)
pthread_kill(UpSentQ_PollThr, SIGUSR1);
if(DnSentQ_PollThr)
pthread_kill(DnSentQ_PollThr, SIGUSR1);
strcpy(sSysEvent,"LOG: All connections have been cut! Backuping data in Queues...");
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG); //写系统日志
//=======================保存队列中的数据包=========================
CDnNode *DnNode[MAX_DNNODE];
int DnNode_Num;
int UpSaved = 0;
while(1)
{
if(UpSaved < UPNODE_NUM)
{
for(int i=0; i<UPNODE_NUM; i++)
{
if(UpNode[i].ToExit==0 && UpNode[i].State) //补充处理某些上节点在退出命令发出前连接已断的情况
{
UpNode[i].ToExit=1; //置退出标识
if(UpNode[i].ReadThr)
pthread_kill(UpNode[i].ReadThr, SIGUSR1);
if(UpNode[i].WriteThr)
pthread_kill(UpNode[i].WriteThr, SIGUSR1);
}
//上节点的收发线程都已退出时
if(UpNode[i].ToExit!=2 && UpNode[i].ReadThr==0 && UpNode[i].WriteThr==0)
{
RecvBak = 0;
RecvNum = UpNode[i].RecvQ->GetLen();
if(RecvNum) //接收队列不为空
{
//-----------接收队列备份------------
memset(FileName,0,sizeof(FileName));
sprintf(FileName,"%s%s%s",UpNode[i].UpQueueBak,UpNode[i].SP_Id,UpNode[i].UpRecvQ_File);
RetCode=Qbackup->RWOpen(FileName, "ow"); //打开备份文件
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Opening %s file for backuping RecvQ of UpNode[%d].",RetCode,FileName,UpNode[i].NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
while(1)
{
memset(&RUnit,0,sizeof(RUnit));
if(UpNode[i].RecvQ->Get(RUnit)==false)
break;
PackType = ntohl(*(unsigned int *)(RUnit.Pack + 4));
printf("\n UpSendQ_Backup: PackType=%x, xxx=%x, deliver=%d. \n",PackType, *(int *)(RUnit.Pack + 4), CMPP_DELIVER);
if((UpNode[i].Protocol==0 && PackType==CMPP_DELIVER) || (UpNode[i].Protocol==1 && PackType==REQUEST_ID_DELIVER))
{
//保存接收队列中的数据包
RetCode = Qbackup->RecvQ_Backup(&RUnit);
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Failed to Backup RecvQ of UpNode[%d].",RetCode,UpNode[i].NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
RecvBak++;
}
}//while(1)
Qbackup->RWClose(); //关闭备份文件
}
SendBak = 0;
SendNum = UpNode[i].SendQ->GetLen();
if(SendNum) //发送队列不为空
{
//-----------发送队列备份------------
memset(FileName,0,sizeof(FileName));
sprintf(FileName,"%s%s%s",UpNode[i].UpQueueBak,UpNode[i].SP_Id,UpNode[i].UpSendQ_File);
RetCode = Qbackup->RWOpen(FileName, "ow"); //打开备份文件
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Opening %s file for backuping SendQ of UpNode[%d].",RetCode,FileName,UpNode[i].NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
while(1)
{
memset(&SUnit,0,sizeof(SUnit));
if(UpNode[i].SendQ->Get(SUnit)==false)
break;
PackType = ntohl(*(unsigned int *)(SUnit.Pack + 4));
printf("\n UpSendQ_Backup: PackType=%x, xxx=%x, submit=%d. \n",PackType, *(int *)(SUnit.Pack + 4), CMPP_SUBMIT);
if((UpNode[i].Protocol==0 && PackType==CMPP_SUBMIT) || (UpNode[i].Protocol==1 && PackType==REQUEST_ID_SUBMIT))
{
//保存发送队列中的数据包
RetCode = Qbackup->SendQ_Backup(&SUnit);
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Failed to Backup SendQ of UpNode[%d].",RetCode,UpNode[i].NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
SendBak++;
}
}//while(1)
Qbackup->RWClose(); //关闭备份文件
}
#ifdef DEBUG
printf("\n SafeExit: Packets in RecvQ[%d/%d] and SendQ[%d/%d] of UpNode[%d] are saved!\n",RecvBak,RecvNum,SendBak,SendNum,UpNode[i].NodeID);
#endif
UpNode[i].ToExit=2;
UpSaved++;
}
}//for
}//if(UpSaved < UPNODE_NUM)
//获取所有曾经上线的下节点
DnNode_Num = Code_CP_Map.GetAllNode((char **)DnNode,MAX_DNNODE);
for(int i=0; i<DnNode_Num; i++)
{
if(DnRecvThr==0 && DnNode[i]->SendThr==0) //下节点的收发线程都已退出
{
RecvBak = 0;
RecvNum = DnNode[i]->RecvQ->GetLen();
if(RecvNum) //接收队列不为空
{
//-----------接收队列备份------------
memset(FileName,0,sizeof(FileName));
sprintf(FileName,"%s%d%s",DnQueueBak,DnNode[i]->NodeID,DnRecvQ_File);
RetCode = Qbackup->RWOpen(FileName, "ow"); //打开备份文件
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Opening %s file for backuping RecvQ of DnNode[%d].",RetCode,FileName,DnNode[i]->NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
while(1)
{
memset(&RUnit,0,sizeof(RUnit));
if(DnNode[i]->RecvQ->Get(RUnit)==false)
break;
PackType = ntohl(*(unsigned int *)(RUnit.Pack + 4));
//printf("\n DnRecvQ_Backup: PackType=%x, xxx=%x, submit=%d. \n",PackType, *(int *)(RUnit.Pack + 4), CMPP_SUBMIT);
if(PackType==CMPP_SUBMIT)
{
//保存接收队列中的数据包
RetCode = Qbackup->RecvQ_Backup(&RUnit);
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Failed to Backup RecvQ of DnNode[%d].",RetCode,DnNode[i]->NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
RecvBak++;
}
}//while(1)
Qbackup->RWClose(); //关闭备份文件
}
SendBak = 0;
SendNum = DnNode[i]->SendQ->GetLen();
if(SendNum) //发送队列不为空
{
//-----------发送队列备份------------
memset(FileName,0,sizeof(FileName));
sprintf(FileName,"%s%d%s",DnQueueBak,DnNode[i]->NodeID,DnSendQ_File);
RetCode = Qbackup->RWOpen(FileName, "ow"); //打开备份文件
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Opening %s file for backuping SendQ of DnNode[%d].",RetCode,FileName,DnNode[i]->NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
while(1)
{
memset(&SUnit,0,sizeof(SUnit));
if(DnNode[i]->SendQ->Get(SUnit)==false)
break;
PackType = ntohl(*(unsigned int *)(SUnit.Pack + 4));
//printf("\n DnSendQ_Backup: PackType=%x, xxx=%x, deliver=%d. \n",PackType, *(int *)(SUnit.Pack + 4), CMPP_DELIVER);
if(PackType==CMPP_DELIVER)
{
//保存发送队列中的数据包
RetCode = Qbackup->SendQ_Backup(&SUnit);
if(RetCode)
{
sprintf(sSysEvent,"Error[%d]: Failed to Backup SendQ of DnNode[%d].",RetCode,DnNode[i]->NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG);
}
SendBak++;
}
}//while(1)
Qbackup->RWClose(); //关闭备份文件
}
#ifdef DEBUG
printf("\n SafeExit: Packets in RecvQ[%d/%d] and SendQ[%d/%d] of DnNode[%d] are saved!\n",RecvBak,RecvNum,SendBak,SendNum,DnNode[i]->NodeID);
#endif
int DelNum = Code_CP_Map.Delete(DnNode[i]->NodeID); //从下节点映射表中清除
if(DelNum!=1)
{
sprintf(sSysEvent,"Error: DelNum=[%d], Failed to Delete a DnNode[%d] in Code_CP_Map!",DelNum,theDnNode->NodeID);
WrSystemLog->WriteLog(sSysEvent,SYSTEMLOG); //写系统日志
}
delete DnNode[i];
}
else //下节点的收发线程未完全退出
{
#ifdef DEBUG
//printf("\n SafeExit: DnNode_Num=%d, DnRecvThr=%d, DnNode[%d]->SendThr=%d\n",DnNode_Num,(int)DnRecvThr,DnNode[i]->NodeID,(int)DnNode[i]->SendThr);
#endif
}
}
if(UpSaved==UPNODE_NUM && DnNode_Num==0) //所有节点的队列数据保存完毕
break;
else
{
//printf("\n SafeExit: UpSaved=%d, DnNode_Num=%d.\n",UpSaved,DnNode_Num);
}
usleep(50000);
}
delete Qbackup;
//sleep(2);
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -