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

📄 utcmppcom.pas

📁 使用delphi编写的cmpp接口程序源代码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
  { 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 + -