最近做一个企业群发短信的项目(联通的),要根据联通企信通系统企业接口协议(ESMP 2.0版)写程序,我在向网关发送登录请求的时候,总得不到服务器的响应,请高手帮忙分析!
协议标准我在下面贴出来:  企业用户接入企信通平台,以客户端的形式接入。企业作为通信客户端;企信通平台作为通信服务端。
客户端和服务端的通信过程可采用TCP或UDP连接,企信通系统作为连接的服务端,端口号都为9000。
如果采用TCP方式,客户端需要分别建立一条Submit连接和一条Deliver连接到服务端,不需要收Deliver和Report则可以不连Deliver连接。
在Submit连接上,发送C_SUBMIT包;在Deliver连接上,接收C_DELIVER包和S_REPORT包。
对于TCP Submit连接,客户端可采用短连接,也可采用长连接的方式;如果采用长连接则要发送C_NOOP包保持连接,对于TCP Deliver要采用长连接的方式,以便随时接收C_DELIVER和C_REPORT。
对于UDP连接方式,需要定时发送NOOP包以保持在线连接,否则每次发包前需要重新登录。如果多次发送未收到C_NOOP_RESP需要重新登录。
NOOP的发送间隔为20-30秒,可配置。
3. 消息定义
3.1.  数据类型
消息中使用的数据类型,如下表所示:
消息的数据类型
类型 说明
Integer   无符号整数
String 变长字符串,以\0结尾,协议规定最大长度,不包括’\0’ 
Octet 定长字符串,由前一字段指定长度,内容包含任意字符3.2.  消息结构
短信批发通讯协议中定义的消息由消息头和消息体组成。如下表所示:
消息构成 说明
Message Header 消息头(所有消息公共包头)
Message Body 消息体3.3.  消息头格式
消息头格式如下表所示:
消息头格式
字段名 字节数 类型 描述
Total_Length 2 Integer 消息总长度(含消息头及消息体)
Command_ID 2 Integer 命令或响应类型
Crypt 1 Integer 是否加密,缺省填0
SeqNum 4 Int 该消息序列号,可循环使用(短信生命周期内不能重复,24小时内不能重复)
UserNo 4 Int 系统分配的用户号(系统唯一内部号),登录时填0;登录成功后返回系统分配的用户号,以后所有包都需带这个用户号 3.4.  Command_ID定义
Command_ID定义如下表所示:Command_ID定义
命令字名称 Command_ID值 说明
C_LOGIN 0x0001 登录
C_LOGIN_RESP 0x1001 登录应答
C_LOGOFF 0x0003 断开连接
C_NOOP 0x0004 保持连接
C_NOOP_RESP 0x1004 保持连接应答

C_SUBMIT 0xa001 发送短信
C_SUBMIT_RESP 0xb001 发送短信应答
S_DELIVER 0xa002 接收短信
S_DELIVER_RESP 0xb002 接收短信应答
S_REPORT 0xa003 接收短信的report
S_REPORT_RESP 0xb003 接收短信的report应答3.5.  SessionId和SessionKey
客户端登录后服务器会为每一个登录客户端分配一个SessionId和一个SessionKey,SessionId用于服务器端校验以后发的包的合法性,客户端的各个包要正确地填写服务端分配的SessionId。SessionKey为客户端和服务器端的公用密钥,如果不加密,则SessionKey没有生效。3.6.  企业和企信通平台间的消息定义
3.6.1.  登录:C_LOGIN
字段名 字节数 属性 描述
ConnectType 1 Int 连接类型 0:UDP连接,1:TCP的Submit连接, 2:TCP的Deliver连接
LoginType 1 Int 登录类型,企业用户登录填0;其他值保留未定义
CorpNo 4 Integer 企业接入号
UserID 10 String 用户登录名
Password 10 String 用户登录密码3.6.2.  登录应答:C_LOGIN_RESP
字段名 字节数 属性 描述
Result 1 Int 登录类型0:正确>0:错误
ConnectType 1 Int 连接类型 0:UDP连接,1:TCP的Submit连接, 2:TCP的Deliver连接
LoginType 1 Int 登录类型,企业用户登录填0;其他值保留未定义
Reserved1 20 String 保留1 
UserNo 4 Int 返回系统分配的用户号(由服务器端分配)
SessionID 16 String 会话ID,当Result>0时为空
SessionKey 16 String 加密串,当Result>0时为空
说明:UserNo,SessionID,SessionKey这三个值,在系统登录的时候,由企信通服务端分配,一旦分配后,在本次登录后的后续所有包中,按照已经分配的值的填写(在包头中)即可。3.6.3.  退出:C_LOGOFF
字段名 字节数 属性 描述
SessionId 16 String 会话ID 
说明:客户端发送C_LOGOFF后,直接关闭连接。3.6.4.  保持连接:C_NOOP
字段名 字节数 属性 描述
SessionId 16 String 会话ID 3.6.5.  :保持连接应答:C_NOOP_RESP
字段名 字节数 属性 描述
Result 1 Int 0:正确非0(>0):错误
SessionId 16 String 会话ID 3.6.6.  SUBMIT:C_SUBMIT
字段名 字节数 属性 描述
SessionID 16 String 同上定义
ClientSeq1 4 Int 客户端序列号1,填写发送的时间
ClientSeq2 4 Int 客户端序列号2,同一时间发送的流水号
SendType 1 Int 发送类型0:普通1:定时发送
ScheduleTime 12 String 定时发送时间,SendType 为0时填空
Type 1 Int 0:短信;其他值保留未定义
UserType 1 Int 1:企业用户
Caller 21 String 主叫手机号
Called 21 String 被叫手机号
ChargeNumber 21 String 付费手机号
ReportFlag 1 Int 是否需要Report
Priority 1 Int 优先级0-3
TP_pid 1 Int GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9;普通短信统一填0
TP_udhi 1 Int GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐;普通消息填0
MsgCoding 1 Int 编码格式: 0:纯ASCII字符串3:写卡操作4:二进制编码8:UCS2编码15: GBK编码
MsgLen 1 Int 消息长度,MsgCoding 值为0时:<160个字节;其它<=140个字节)
MsgContent 160 Octet 消息内容3.6.7.  :C_SUBMIT_RESP
字段名 字节数 属性 描述
Result 1 Int 0:被服务器接收>0:其他错误3.6.8.  :S_DELIVER
字段名 字节数 属性 描述
Caller 21 String 主叫手机号
Called 21 String 被叫手机号
TP_pid 1 Int GSM协议;同前定义
TP_udhi 1 Int GSM协议;同前定义
MsgCoding 1 Int 编码格式
MsgLen 1 Int 消息长度,MsgCoding 值为0时:<160个字节;其它<=140个字节)
MsgContent 160 Octet 消息内容3.6.9.  :S_DELIVER_RESP
字段名 字节数 属性 描述
Result 1 Int 0:成功 其它:失败3.6.10.  :S_REPORT
字段名 字节数 属性 描述
ClientSeq1 4 Int 客户端序列号;同C_SUBMIT定义
ClientSeq2 4 Int 客户端序列号;同C_SUBMIT定义
UserNumber 21 String 接收手机号
State 1 Int 状态
ErrCode 1 Int 错误代码3.6.11.  :S_REPORT_RESP
字段名 字节数 属性 描述
Result 1 Int 0:成功 其他:失败
3.7.  错误码定义
错误码 描述
0 成功
1 错误协议格式
2 版本错误
3 解密错误
4 非法登陆
5 系统保留
6 系统保留
7 无此账户
8 用户不在线
9 无此用户
10 系统内部错误
11 密码错
12 无此记录
13 权限不匹配
14 系统保留
15 系统保留
16 系统忙 
17 操作不允许
18 参数错误
19 账号重复
82 密码错误 
附加命令字  Command ID值
命令字名称 Command_ID值 消息体 说明
C_LOGIN 0x0001 00,25,(消息总长)00,01(Command ID)00,(CRYPT)00,00,00,01,(SeqNum)00,00,00,00,(UserNo)00(ConnectType UDP),01(LOGIN TYPE  ),00,00,00,00,35,31,34(企业接入号),2E 61 64 6D 69 6E 00(用户名admin) 63-6D 31 72 30 30 74 00 (密码cm1r00t) 登录
C_LOGIN2 0x0002 00,23,(消息总长)00,02,(Command ID)00,(CRYPT)00,00,00,02,(SeqNum)00,00,01,5b,(UserNo) 01,69,6f,33,50,66,56,65,35,61,6c,66,52,78,42,66,(Session ID)63-00,00,00,00,02 登录2
C_LOGIN_RESP 0x1001 登录应答
C_LOGOFF 0x0003 断开连接
C_NOOP 0x0004 保持连接
C_NOOP_RESP 0x1004 保持连接应答

C_SUBMIT 0xa001 发送短信
C_SUBMIT_RESP 0xb001 发送短信应答
S_DELIVER 0xa002 接收短信
S_DELIVER_RESP 0xb002 接收短信应答
S_REPORT 0xa003 接收短信的report
S_REPORT_RESP 0xb003 接收短信的report应答

解决方案 »

  1.   

    这是我写的代码:
      TMessageHeader=Packed Record
        Total_Length:Word;
        CommandID:Word;
        Crypt:byte;
        SeqNum:LongWord;
        UserNo:LongWord;
      end;  TLogin=Packed Record
       ConnectType:byte;
       LoginType:byte;
       CorpNo:LongWord;
       UserId: string;
       Password:string;
      end;  TLogin_RESP=Packed Record
        Result:byte;
        ConnectType:byte;
        LoginType:byte;
        Reserved1:string;
        UserNo:LongWord;
        SessionId:string;
        SessionKey:string;
      end;  TLogOff=Packed Record
       SessionId:Packed array[0..15] of char;
      end;  const
       C_Login=$0001;  
       C_Login_Resp=$1001; 
       C_LogOff=$0003;procedure TForm1.btLoginClick(Sender: TObject);
    Var MessageHeader,RespMsgHeader:TMessageHeader;
        Login:TLogin;
        Login_RESP:TLogin_RESP;
        WinSocketStream:TWinSocketStream;
    begin
     if not ClientSocket1.Active then
     begin
      showmessage('联接未打开');
      exit;
     end;
     memo1.Lines.Add('--------向服务端发送Login请求------------ ');
     fillchar(MessageHeader,sizeof(TMessageHeader),0);
     fillchar(Login,sizeof(TLogin),0);
     With Login do
     begin
       ConnectType:=1;
       LoginType:=0;
       CorpNo:=140050;
       UserId:='admin'+#0;
       Password:='7064'+#0;
     end;
     With MessageHeader do
     begin
      Total_Length:=sizeof(MessageHeader)+sizeof(Login);
      CommandId:=C_Login;
      Crypt:=0;
      SeqNum:=strtoint(formatdatetime('hhnnssz',now));
      UserNo:=0;
     end;
     WinSocketStream:=TWinSocketStream.Create(ClientSocket1.Socket,30000);
     WinSocketStream.Write(MessageHeader,sizeof(MessageHeader));
     WinSocketStream.Write(Login,sizeof(Login));
     memo1.Lines.Add('MessageLength:'+inttostr(MessageHeader.Total_Length));
     memo1.Lines.Add('CommandID:'+inttostr(MessageHeader.CommandID));
     memo1.Lines.Add('SeqNum:'+inttostr(MessageHeader.SeqNum));
     memo1.Lines.Add('UserNo:'+inttostr(MessageHeader.UserNo));
     memo1.Lines.Add('Corp:'+Inttostr(Login.CorpNo));
     memo1.Lines.Add('LoginName:'+Login.UserId);
     memo1.Lines.Add('LoginPassword:'+Login.Password); memo1.Lines.Add('--------返回服务器Login_Resp响应------------ ');
     if WinSocketStream.WaitForData(5000)  then
     begin
      fillchar(RespMsgHeader,sizeof(RespMsgHeader),0);
      fillchar(Login_RESP,sizeof(Login_RESP),0);
      WinSocketStream.Read(RespMsgHeader,sizeof(RespMsgHeader));
      WinSocketStream.Read(Login_RESP,sizeof(Login_RESP)) ;
      memo1.Lines.Add('MessageLength:'+inttostr(RespMsgHeader.Total_Length));
      memo1.Lines.Add('CommandID:'+inttohex(RespMsgHeader.CommandID,2));
      memo1.Lines.Add('SeqNum:'+inttostr(RespMsgHeader.SeqNum));
      memo1.Lines.Add('UserNo:'+inttostr(RespMsgHeader.UserNo));
      memo1.Lines.Add('Result:'+Inttostr(Login_Resp.Result));
      memo1.Lines.Add('ConnectType:'+Inttostr(Login_Resp.ConnectType));
      memo1.Lines.Add('UserNo:'+Inttostr(Login_Resp.UserNo));
      memo1.Lines.Add('SessionId:'+Login_Resp.SessionId);
      memo1.Lines.Add('SessionKey:'+Login_Resp.SessionKey);
     End;
     WinSocketStream.Free;
    end;得不到服务器的回应消息,请高手帮忙分析!