📄 utcmppcom.pas
字号:
{ DONE : 可以发送数据标志,发送登陆消息 }
SysLog.LogInfo('发送Login');
CMPPMsg_SendLogin;
end;
procedure TCMPPService.CMPP_ConnectSuc(Sender: TObject;
Socket: TCustomWinSocket);
begin
SysLog.LogInfo('ConnectSuc');
end;
procedure TCMPPService.CMPP_DisConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
SysLog.LogInfo('DisConnect');
bComCanWrite := False;
if ServiceStatus = SS_WORK then
begin
bComReboot := True;
ReConTimer.Enabled := True;
end;
end;
procedure TCMPPService.CMPP_Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
const
ErrorEventStr : array[TErrorEvent] of string = ('eeGeneral', 'eeSend', 'eeReceive',
'eeConnect',
'eeDisconnect', 'eeAccept', 'eeLookup');
begin
ErrorCode := 0;
if ErrorEvent = eeConnect then
begin
CMPPClient.Close;
//如果是在业务开启状态则设置连接错误,setevent
if ServiceStatus = SS_WaitLoginResult then
begin
//设置登陆失败
ErrCode := ICP_ERR_CONERR;
ServiceEvent.SetEvent;
end
else
begin
{ DONE : socket Err eeCOnnect 自动重连时,失败处理 }
SysLog.LogInfo('重连接Connect错误 Interval=' + inttostr(ReConTimer.Interval));
//if ReConTimer.Interval < 10000 then
// ReConTimer.Interval := ReConTimer.Interval + 1000;
bComReboot := True;
ReConTimer.Enabled := True;
end;
end
else if ErrorEvent = eeDisconnect then
begin
SysLog.LogInfo('错误 eeDisconnect:重连接 ');
bComCanWrite := False;
if ServiceStatus = SS_WORK then
begin
CMPPClient.Close;
bComReboot := True;
ReConTimer.Enabled := True;
end;
end
else
begin
//设置自动重新启动
SysLog.LogInfo('错误: ' + ErrorEventStr[ErrorEvent]);
{ TODO : socket Err 其它错误时 是否 重新启动连接 }
// SysLog.LogInfo('重新启动连接');
end;
end;
procedure TCMPPService.CMPP_Read(Sender: TObject;
Socket: TCustomWinSocket);
procedure SocketErr;
begin
//socket错误处理
csSocket.Enter;
try
socket.ReceiveText;
except
end;
csSocket.Leave;
end;
var
pBuf : pChar;
iRevLen : Cardinal;
IsMine : boolean;
begin
if FbIsReceiveData then
Exit
else
FbIsReceiveData := True;
try
try
//开始消息头接收
ZeroMemory(@pRevData, sizeof(pRevData));
if not CMPPMsg_Receive(Recmh, SizeOf(Recmh)) then
begin
//消息头接受错误
SocketErr;
Exit;
end;
{ DONE : 读数据解码,如果是Active,则回复,如果是Submit Resp,则交给相应线程处理,如果是Deliver,则添加到队列 }
//检查消息头
//消息头验证正确则接收消息体
iRevLen := ntohl(Recmh.PacketLength) - SizeOf(Recmh);
//接受数据的处理
if iRevLen > 0 then
begin
pBuf := @pRevData[0];
//接收消息体
if not CMPPMsg_Receive(pBuf^, iRevLen) then
begin
//消息体接收错误
SocketErr;
Exit;
end;
end;
//处理消息命令字
// SysLog.LogInfo('接受数据 CMD=' + IntToHex(ntohl(Recmh.Command_Id), 4));
// SysLog.LogInfo(@Recmh, SizeOf(Recmh));
// SysLog.LogInfo(pBuf, iRevLen);
case ntohl(Recmh.Command_Id) of
CMD_CONNECT_RESP: CMPPMsg_DealLoginResp(PCMPPMsgBody_Login_Resp(pBuf));
CMD_SUBMIT_RESP: CMPPMsg_DealSubmitResp(Recmh.SwquenceID, PCMPPMsgBody_Submit_Resp(pBuf));
CMD_DELIVER: CMPPMsg_DealDeliver(Recmh.SwquenceID, PCMPPMsgBody_Deliver(pBuf));
CMD_ACTIVE: CMPPMsg_SendActiveResp(Recmh.SwquenceID); //心跳消息
CMD_ACTIVE_RESP: ;
CMD_TERMINATE_RESP: CMPPMsg_DealExitResp;
else
//命令字不正确时的处理
// SocketErr;
end;
except
on e: Exception do
begin
SysLog.LogInfo('接受数据错误:' + Socket.RemoteAddress + ':' + IntToStr(Socket.RemotePort));
end;
end;
finally
FbIsReceiveData := False;
end;
end;
function TCMPPService.Start: Integer;
begin
if not bServiceActive then
begin
// 开启socket,开始连接,发送登陆消息
CMPPClient.Active := True;
//创建等待登陆成功事件
Result := SetServiceStatus(SS_WaitLoginResult);
if Result = 0 then
begin
bServiceActive := True;
MsgSend.Suspended := True;
SetServiceStatus(SS_WORK);
end
else
begin
CMPPClient.Active := False;
end;
end
else
begin
Result := ICP_ERR_HADLOGIN;
end;
end;
function TCMPPService.Stop: Integer;
begin
if bServiceActive then
begin
bServiceActive := False;
//关闭发送线程
MsgSend.Suspended := true;
// 发送登出消息,关闭socket
Result := SetServiceStatus(SS_WaitLogOutResult);
SetServiceStatus(SS_IDLE);
CMPPClient.Active := False;
// 清空消息队列
ClearList;
end
else
begin
Result := ICP_ERR_NOLOGIN;
end;
end;
function TCMPPService.CMPPMsg_SendActiveResp(SwquenceID: Integer): integer;
var
Len : integer;
PMsg : PChar;
begin
{ DONE : 发送Exit消息 }
//组合消息
Len := CMPPMsg_SeTCMPPMsgHeadEx(@CMPPMsg_Active_Resp, CMD_ACTIVE_RESP, 0, ntohl(
SwquenceID));
//发送消息
PMsg := @CMPPMsg_Active_Resp;
Result := CMPPMsg_Send(PMsg^, Len);
end;
procedure TCMPPService.CMPPMsg_DealLoginResp(PMsg: PCMPPMsgBody_Login_Resp);
begin
{ DONE : Deal Login Resp Msg 如果是Start
服务状态,则返回,如果是自动重连,则设置状态 }
ErrCode := ntohl(PMsg.Status);
//如果是在业务开启状态则设置连接错误,setevent
if ServiceStatus = SS_WaitLoginResult then
begin
ServiceEvent.SetEvent;
if ErrCode = 0 then
begin
bComCanWrite := True;
SysLog.LogInfo('登陆成功!');
end;
end
else
begin
if ErrCode <> 0 then
begin
SysLog.LogInfo('重连接登陆错误 err=' + inttostr(PMsg.Status));
try
CMPPClient.close;
except
SysLog.LogInfo('重连接登陆错误 close Socket 异常');
end;
end
else
begin
bComReboot := False;
bComCanWrite := True;
SysLog.LogInfo('重连接登陆成功!');
end
end
end;
procedure TCMPPService.CMPPMsg_DealExitResp();
begin
{ DONE : Deal Exit Msg }
ErrCode := 0;
//如果是在业务开启状态则设置连接错误,setevent
if ServiceStatus = SS_WaitLogOutResult then
begin
ServiceEvent.SetEvent;
end
end;
procedure TCMPPService.CMPPMsg_DealDeliver(SwquenceID: Integer; PMsg: PCMPPMsgBody_Deliver);
var
pDeliverMsg : PCMPPDeliverResp;
tmpMsgID : Int64;
tmpMsgIDStr : string;
begin
{ DONE : Deal Deliver Msg 添加到Deliver 队列 }
new(pDeliverMsg);
ZeroMemory(pDeliverMsg, sizeof(TCMPPDeliverResp));
with pDeliverMsg^, PMsg^ do
begin
StrLCopy(@rDestAddr, @Dest_Id, 21);
rbySrcTerminalType := Src_terminal_type;
StrLCopy(@rOrgAddr, @Src_terminal_Id, 32);
StrLCopy(@rService_Id, @Service_Id, 10);
rUDHI := TP_udhi;
rPID := TP_pid;
rMsg_Fmt := Msg_Fmt;
StrPLCopy(@rTimeStamp, FormatDateTime('yyyymmddhhnnss', now), 20);
rUDLen := Msg_Length;
CopyMemory(@rUserData, @Msg_Content, rUDLen);
StrLCopy(@rsLinkID, Pchar(Integer(@Msg_Content) + rUDLen), 20);
rStatusReport := Registered_Delivery;
if rStatusReport = 1 then
begin
//解析report
tmpMsgID := PInt64(@Msg_Content)^;
tmpMsgID := ntohll(tmpMsgID);
tmpMsgIDStr :=
IntToHex(tmpMsgID and $000000000000FFFF, 4) + //序列号
IntToHex((tmpMsgID and $0000003FFFFF0000) shr 16, 6) + //短信网关代码
IntToHex((tmpMsgID and $F000000000000000) shr 60, 2) + //月份的二进制表示
IntToHex((tmpMsgID and $0F80000000000000) shr 55, 2) + //日的二进制表示
IntToHex((tmpMsgID and $007C000000000000) shr 50, 2) + //小时的二进制表示
IntToHex((tmpMsgID and $0003F00000000000) shr 44, 2) + //分的二进制表示
IntToHex((tmpMsgID and $00000FC000000000) shr 38, 2); //秒的二进制表示
StrPLCopy(Pchar(@rsReportMsgID), tmpMsgIDStr, 21);
StrPLCopy(@rsStatus, Pchar(Integer(@Msg_Content) + 8), 7);
StrPLCopy(@rsSubmitdate, Pchar(Integer(@Msg_Content) + 15), 10);
StrPLCopy(@rsDonedate, Pchar(Integer(@Msg_Content) + 25), 10);
end
else
begin
tmpMsgID := rMsg_Id;
tmpMsgIDStr :=
IntToHex(tmpMsgID and $000000000000FFFF, 4) + //序列号
IntToHex((tmpMsgID and $0000003FFFFF0000) shr 16, 6) + //短信网关代码
IntToHex((tmpMsgID and $F000000000000000) shr 60, 2) + //月份的二进制表示
IntToHex((tmpMsgID and $0F80000000000000) shr 55, 2) + //日的二进制表示
IntToHex((tmpMsgID and $007C000000000000) shr 50, 2) + //小时的二进制表示
IntToHex((tmpMsgID and $0003F00000000000) shr 44, 2) + //分的二进制表示
IntToHex((tmpMsgID and $00000FC000000000) shr 38, 2); //秒的二进制表示
StrPLCopy(Pchar(@rsReportMsgID), tmpMsgIDStr, 21);
end;
end;
AddDeliverMsg(pDeliverMsg);
//发送回复
CMPPMsg_SendDeliverResp(ntohl(SwquenceID), PMsg^.Msg_Id);
end;
procedure TCMPPService.CMPPMsg_DealSubmitResp(SwquenceID: Integer; PMsg: PCMPPMsgBody_Submit_Resp);
begin
{ DONE : Deal Submit Msg 选择消息返回,Reset Event }
SetWaitMsg(ntohl(SwquenceID), ntohl(Pmsg.Status), PMsg.MsgID);
end;
function TCMPPService.CMPPMsg_SendDeliverResp(SwquenceID: Integer; AMsgID: Int64): integer;
var
Len : integer;
PMsg : PChar;
begin
{ DONE : 发送Login消息 }
//组合消息
with CMPPMsg_Deliver_Resp.Body do
begin
CopyMemory(@MsgID, PChar(@AMsgID), 10);
Status := 0;
end;
Len := CMPPMsg_SeTCMPPMsgHeadEx(@CMPPMsg_Deliver_Resp.Head, CMD_DELIVER_RESP,
sizeof(CMPPMsg_Deliver_Resp.Body), SwquenceID);
//发送消息
PMsg := @CMPPMsg_Deliver_Resp;
Result := CMPPMsg_Send(PMsg^, Len);
end;
function TCMPPService.AddDeliverMsg(pMsg: PCMPPDeliverResp): integer;
begin
csRecMsg.Enter;
RecQueue.Push(pMsg);
//激活等待接收线程
if RecQueue.Count = 1 then
RecEvent.SetEvent;
csRecMsg.Leave;
end;
function TCMPPService.GetDeliverMsg(const nTimeoutIn: Integer;
pDeliverRespInfo: PCMPPDeliverResp): integer;
var
pMsg : PCMPPDeliverResp;
begin
//验证是否有消息,如果没有等待
if RecQueue.Count = 0 then
case RecEvent.WaitFor(nTimeoutIn) of //
wrSignaled:
begin
Result := 0;
end;
wrTimeout:
begin
result := ICP_ERR_DELIVERTIMEOUT;
exit;
end;
wrAbandoned:
begin
result := ICP_ERR_OTHER;
exit;
end;
wrError:
begin
result := ICP_ERR_OTHER;
exit;
end;
end;
//取消息
csRecMsg.Enter;
if RecQueue.Count > 0 then
begin
pMsg := PCMPPDeliverResp(RecQueue.Pop);
//复制消息
CopyMemory(pDeliverRespInfo, pMsg, sizeof(TCMPPDeliverResp));
//释放内存
Dispose(pMsg);
end
else
begin
result := ICP_ERR_DELIVERTIMEOUT;
end;
csRecMsg.Leave;
end;
function TCMPPService.AddSubmitMsg(pSubmitInfo: PCMPPSubmit): integer;
var
pMsg : PCMPPMsg_Submit;
pMsgSub : PCMPPMsgBody_Submit_Sub;
Len : Integer;
SwquenceID : Integer;
MsgWait : TCMPPMsgWait;
tmpMsgID : integer;
tmpMsgIDStr : string;
begin
//如果服务没有启动,则返回
try
if not bServiceActive then
begin
Result := ICP_ERR_NOLOGIN;
exit;
end;
//如果socket在 重新连接,则返回
if bComReboot then
begin
Result := ICP_ERR_CONTRETRY;
exit;
end;
//如果发送窗口满了,则返回
if (WaitList.Count + SendList.Count) >= RequestWindow * 1.5 then
begin
Result := ICP_ERR_SUBMITOUTOFWINDOW;
exit;
end;
//组合消息
new(pMsg);
ZeroMemory(pMsg, sizeof(TCMPPMsg_Submit));
with pMsg.Body, pSubmitInfo^ do
begin
Msg_Id := 0;
Pk_total := byPKTotal;
Pk_number := byPKNumber;
Registered_Delivery := byneedReport;
Msg_level := byMsglevel;
StrLCopy(@Service_Id, @sServiceID, 10);
Fee_UserType := byFeeUserType;
StrLCopy(@Fee_terminal_Id, @sFeeAddr, 20);
Fee_terminal_type := bychargTermidType;
TP_pId := byPID;
TP_udhi := byUDHI;
Msg_Fmt := byMsg_Fmt;
StrLCopy(@Msg_src, @sSPID, 6);
StrLCopy(@FeeType, @sFeeType, 2);
StrLCopy(@FeeCode, @sFeeCode, 6);
StrLCopy(@ValId_Time, @sSchedule, 17);
StrLCopy(@At_Time, @sExpire, 17);
StrLCopy(@Src_Id, @sOrgAddr, 20);
DestUsr_tl := byUserNum;
StrLCopy(@Dest_terminal_Id, @sDestAddrs, 20);
pMsgSub := PCMPPMsgBody_Submit_Sub((Pchar(@Dest_terminal_Id) + DestUsr_tl * 32));
pMsgSub^.Dest_terminal_type := byDestTerminalType;
pMsgSub^.Msg_Length := byUDLen;
if pMsgSub^.Msg_Length > 160 then
pMsgSub^.Msg_Length := 160;
StrLCopy(@pMsgSub^.Msg_Content, @sUserData, pMsgSub^.Msg_Length);
StrLCopy(Pchar(Integer(@pMsgSub^.Msg_Content) + pMsgSub^.Msg_Length), @sLinkID, 20);
Len := sizeof(TCMPPMsgBody_SubmitHead) + DestUsr_tl * 32 + 22 +
pMsgSub^.Msg_Length;
end;
CMPPMsg_SeTCMPPMsgHead(@(pMsg^.Head), CMD_SUBMIT, Len);
SwquenceID := ntohl(pMsg.Head.SwquenceID);
//添加到队列
csSendMsg.Enter;
SendList.Add(pMsg);
//激活等待发送线程
if MsgSend.Suspended then
begin
MsgSend.Suspended := False;
end;
csSendMsg.Leave;
//在等待队列中等待返回 sMsgID, nErrorCode,
{ DONE : 在等待队列中等待返回 sMsgID, nErrorCode, }
//创建等待对象,
MsgWait := TCMPPMsgWait.Create(SwquenceID);
csWaitMsg.Enter;
WaitList.Add(MsgWait);
csWaitMsg.Leave;
//等待返回消息
case MsgWait.WaitEvent.WaitFor(3000) of //
wrSignaled:
begin
//结果赋值
Result := 0;
end;
wrTimeout:
begin
Result := ICP_ERR_SUBMITTIMEOUT;
end;
wrAbandoned:
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -