中国移动短信网关CMPP3.0 C#源代码:数据包定义

关于联合
CMPP定义的各种数据包采用C语言中的联合(Union)来处理是最有效率的,因为接收和发送的是一个字节数组,使用联合可以方便地在字节数组和数据包结构之间转换。C#本身并不支持联合,但可以使用P/Invoke(平台封送调用)机制实现类似于联合的结构。
在定义CMPP数据包时,我为每个数据包结构定义了Init函数(用于将字节数组转换为数据包结构)和GetBuffer函数(用于将数据包结构转换为字节数组),主要是因为当时对P/Invoke机制不太熟悉。
使用Init和GetBuffer函数的结果是效率要比使用联合低很多,不过压力测试的时候系统表现还是相当稳定的。有兴趣的朋友可以试试用联合实现CMPP的数据包。

using System;
using System.Runtime.InteropServices;

namespace Tiray.SMS
{
 public struct DATA_PACKAGE
 {
  public UInt32 Command;
  public UInt32 SequenceID;//流水号
  public object Data;//数据
  public DateTime SendTime; //数据包发送时间
  public int SendCount;//发送次数
  public int Status;//数据包状态 0--空,1--待发送,2--已发送
 }
 
 #region Enums
 public enum SMS_STATE
 {
  SP_CONNECT,ACTIVE_TEST,ACTIVE_TEST_RESPONSE,SUBMIT,SUBMIT_RESPONSE,DELIVER,DELIVER_RESPONSE,REPORT,SP_DISCONNECT,
  SP_CONNECT_ERROR,ACTIVE_TEST_ERROR,ACTIVE_TEST_RESPONSE_ERROR,SUBMIT_ERROR,SUBMIT_RESPONSE_ERROR,DELIVER_ERROR,DELIVER_RESPONSE_ERROR,SP_DISCONNECT_ERROR,UNKNOW_ERROR

 }

 public enum CODING
 {
  ASCII=0,BINARY=4,UCS2=8,GBK=15
 }
 #endregion

 #region CMPP30 Data Packages
 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_HEAD
 {
  public UInt32   TotalLength;
  public UInt32   CommandID;
  public UInt32   SequenceID;
  public Byte[] GetBuffer()
  {
   Byte[] buffer=new Byte[Marshal.SizeOf(this)];//12;
   Byte[] temp=null;
   temp=BitConverter.GetBytes(TotalLength);
   buffer[3]=temp[0];
   buffer[2]=temp[1];
   buffer[1]=temp[2];
   buffer[0]=temp[3];
   temp=BitConverter.GetBytes(CommandID);
   buffer[7]=temp[0];
   buffer[6]=temp[1];
   buffer[5]=temp[2];
   buffer[4]=temp[3];
   temp=BitConverter.GetBytes(SequenceID);
   buffer[11]=temp[0];
   buffer[10]=temp[1];
   buffer[9]=temp[2];
   buffer[8]=temp[3];
   return buffer;
  }
 }

 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_CONNECT
 {
  public CMPP_HEAD Head;
  
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=6)]
  public string SourceAddress;

  [ MarshalAs( UnmanagedType.ByValArray, SizeConst=16)]
  public Byte[] AuthenticatorSource;
  public Byte Version;
  public UInt32 TimeStamp;
  
  public Byte[] GetBuffer()
  {
   Byte[] temp=null;
   int iPos=0;
   Head.TotalLength=39;
   Byte[] buffer=new Byte[39];
   
   Byte[] HeadBuffer=this.Head.GetBuffer();
   Array.Copy(HeadBuffer,0,buffer,0,HeadBuffer.Length);
   iPos=iPos+HeadBuffer.Length;
   
   temp=Utility.Encode(SourceAddress,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+6;
   
   Array.Copy(AuthenticatorSource,0,buffer,iPos,AuthenticatorSource.Length);
   iPos=iPos+AuthenticatorSource.Length;
   
   buffer[iPos]=Version;
   iPos++;
   
   //temp=BitConverter.GetBytes(TimeStamp);
   temp=Utility.IntToNetBytes(TimeStamp);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+temp.Length;

   return buffer;
  }

 }
 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_CONNECT_RESP
 {
  public CMPP_HEAD Head;
  public UInt32 Status;
  [ MarshalAs( UnmanagedType.ByValArray, SizeConst=16)]
  public Byte[] AuthenticatorISMG;
  public Byte Version;

 }
 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_SUBMIT
 {
  public CMPP_HEAD Head;
  public UInt64 Msg_ID;
  public Byte Pk_Total;
  public Byte Pk_Number;
  public Byte Registered_Delivery;
  public Byte Msg_Level;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=10)]
  public string Service_Id;
  public Byte Fee_UserType;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=32)]
  public string Fee_Terminal_Id;
  public Byte Fee_Terminal_Type;
  public Byte TP_Pid;
  public Byte TP_Udhi;
  public Byte Msg_Fmt;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=6)]
  public string Msg_Src;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=2)]
  public string FeeType;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=6)]
  public string FeeCode;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=17)]
  public string Valid_Time; 
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=17)]
  public string At_Time; 
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=21)]
  public string Src_Id;
  public Byte DestUsr_Tl;
  public string[] Dest_Terminal_ID;
  public Byte Dest_Terminal_Type;
  public Byte Msg_Length;
  public string Msg_Content;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=20)]
  public String LinkID;

  public Byte[] GetBuffer()
  {
   
   int iPos=0;
   Msg_Length=(Byte)Utility.CountLength(Msg_Content.ToString(),(CODING)Msg_Fmt);
   Head.TotalLength=(UInt32)(163+32*DestUsr_Tl+Msg_Length);
   Byte[] buffer=new Byte[Head.TotalLength];
   Byte[] temp=null;
   
   Byte[] HeadBuffer=this.Head.GetBuffer();
   Array.Copy(HeadBuffer,0,buffer,0,HeadBuffer.Length);
   iPos=HeadBuffer.Length;
   
   temp=Utility.IntToNetBytes(Msg_ID);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+temp.Length;

   buffer[iPos]=Pk_Total;
   iPos++;

   buffer[iPos]=Pk_Number;
   iPos++;

   buffer[iPos]=Registered_Delivery;
   iPos++;

   buffer[iPos]=Msg_Level;
   iPos++;

   temp=Utility.Encode(Service_Id,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+10;

   buffer[iPos]=Fee_UserType;
   iPos++;

   temp=Utility.Encode(Fee_Terminal_Id,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+32;

   buffer[iPos]=Fee_Terminal_Type;
   iPos++;

   buffer[iPos]=TP_Pid;
   iPos++;
   
   buffer[iPos]=TP_Udhi;
   iPos++;

   buffer[iPos]=Msg_Fmt;
   iPos++;

   temp=Utility.Encode(Msg_Src,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+6;

   temp=Utility.Encode(FeeType,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+2;

   temp=Utility.Encode(FeeCode,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+6;

   temp=Utility.Encode(Valid_Time,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+17;

   temp=Utility.Encode(At_Time,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+17;
   
   temp=Utility.Encode(Src_Id,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+21;

   buffer[iPos]=DestUsr_Tl;
   iPos++;
   
   for(int i=0;i<DestUsr_Tl;i++)
   {
    temp=Utility.Encode(Dest_Terminal_ID[i],CODING.ASCII);
    Array.Copy(temp,0,buffer,iPos,temp.Length);
    iPos=iPos+32;
   }

   buffer[iPos]=Dest_Terminal_Type;
   iPos++;

   buffer[iPos]=Msg_Length;
   iPos++;

   temp=Utility.Encode(Msg_Content,(CODING)Msg_Fmt);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+temp.Length;

   temp=Utility.Encode(LinkID,CODING.ASCII);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+temp.Length;

   return buffer;

  }
 }


 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_SUBMIT_RESP
 {
  public CMPP_HEAD Head;
  public UInt64 Msg_ID;
  public UInt32 Result;

 }

 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_DELIVER
 {
  public CMPP_HEAD Head;
  public UInt64 Msg_ID;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=21)]
  public string Dest_Id;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=10)]
  public string Service_Id;
  public Byte TP_Pid;
  public Byte TP_Udhi;
  public Byte Msg_Fmt;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=10)]
  public string Src_Terminal_Id;
  public Byte Src_Terminal_Type;
  public Byte Registered_Delivery;
  public Byte Msg_Length;
  public string Msg_Content;
  [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=20)]
  public String LinkID;

  public bool Init(Byte[] buffer)
  {
   int iPos=0;
   bool bOK=true;
   try
   {
    Msg_ID=(UInt64)BitConverter.ToUInt64(buffer,0);
    iPos=iPos+8;

    Dest_Id=Utility.Decode(buffer,iPos,21,CODING.ASCII);
    iPos=iPos+21;

    Service_Id=Utility.Decode(buffer,iPos,10,CODING.ASCII);
    iPos=iPos+10;

    TP_Pid=buffer[iPos];
    iPos++;

    TP_Udhi=buffer[iPos];
    iPos++;

    Msg_Fmt=buffer[iPos];
    iPos++;

    Src_Terminal_Id=Utility.Decode(buffer,iPos,32,CODING.ASCII);
    iPos=iPos+32;

    Src_Terminal_Type=buffer[iPos];
    iPos++;

    Registered_Delivery=buffer[iPos];
    iPos++;

    Msg_Length=buffer[iPos];
    iPos++;

    if(Registered_Delivery==0)//是短消息
    {
     Msg_Content=Utility.Decode(buffer,iPos,Msg_Length,(CODING)Msg_Fmt);

    }
    else//是状态报告,先转为BASE64 String 存储
     Msg_Content=Convert.ToBase64String(buffer,iPos,Msg_Length);
    
    iPos=iPos+Msg_Length;
    LinkID=Utility.Decode(buffer,iPos,20,CODING.ASCII);
   }
   catch
   {
    bOK=false;
   }
   return bOK;

  }
  public CMPP_REPORT GetReport()
  {
   CMPP_REPORT Report=new CMPP_REPORT();
   if(Registered_Delivery==1)//是状态报告
   {
    Byte[] bytes=Convert.FromBase64String(Msg_Content);
    if((bytes!=null)&&(bytes.Length>0))
     Report.Init(bytes);
   }
   return Report;

  }

 }
 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_REPORT
 {
  public UInt64 Msg_Id;
  public string Stat;
  public string Submit_Time;
  public string Done_Time;
  public string Dest_Terminal_Id;
  public UInt32 SMSC_Sequence;

  public bool Init(Byte[] buffer)
  {
   int iPos=0;
   bool bOK=true;
   try
   {
    Msg_Id=(UInt64)Utility.NetBytesToInt(buffer,0,8);
    iPos+=8;

    Stat=Utility.Decode(buffer,iPos,7,CODING.ASCII);
    iPos+=7;

    Submit_Time=Utility.Decode(buffer,iPos,10,CODING.ASCII);
    iPos+=10;

    Done_Time=Utility.Decode(buffer,iPos,10,CODING.ASCII);
    iPos+=10;

    Dest_Terminal_Id=Utility.Decode(buffer,iPos,32,CODING.ASCII);
    iPos+=32;

    SMSC_Sequence=(UInt32)Utility.NetBytesToInt(buffer,iPos,4);
   }
   catch
   {
    bOK=false;
   }
   return bOK;

 

  }
 }
 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_DELIVER_RESP
 {
  public CMPP_HEAD Head;
  public UInt64 Msg_Id;
  public UInt32 Result;
  public Byte[] GetBuffer()
  {
   int iPos=0;
   Head.TotalLength=(UInt32)Marshal.SizeOf(this);
   Byte[] buffer=new Byte[Head.TotalLength];
   Byte[] temp=null;
   
   Byte[] HeadBuffer=this.Head.GetBuffer();
   Array.Copy(HeadBuffer,0,buffer,0,HeadBuffer.Length);
   iPos=HeadBuffer.Length;
   
   temp=BitConverter.GetBytes(Msg_Id);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+temp.Length;

   temp=Utility.IntToNetBytes(Result);
   Array.Copy(temp,0,buffer,iPos,temp.Length);
   iPos=iPos+temp.Length;

   return buffer;

  }
 }

 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_ACTIVE_TEST_RESP
 {
  public CMPP_HEAD Head;
  public Byte Reserved;
  public Byte[] GetBuffer()
  {
   int iPos=0;
   Head.TotalLength=(UInt32)Marshal.SizeOf(this);
   Byte[] buffer=new Byte[Head.TotalLength];
   
   Byte[] HeadBuffer=this.Head.GetBuffer();
   Array.Copy(HeadBuffer,0,buffer,0,HeadBuffer.Length);
   iPos=HeadBuffer.Length;

   buffer[iPos]=Reserved;

   return buffer;

  }
 }

 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_CANCEL
 {
  public CMPP_HEAD Head;
  public UInt64 MsgID;
  public Byte[] GetBuffer()
  {
   Byte[] buffer=new Byte[Marshal.SizeOf(this)];
   Byte[] HeadBuffer=this.Head.GetBuffer();
   int iPos=HeadBuffer.Length;
   Array.Copy(HeadBuffer,0,buffer,0,iPos);
   Byte[] temp=BitConverter.GetBytes(MsgID);
   buffer[iPos+7]=temp[0];
   buffer[iPos+6]=temp[1];
   buffer[iPos+5]=temp[2];
   buffer[iPos+4]=temp[3];
   buffer[iPos+3]=temp[4];
   buffer[iPos+2]=temp[5];
   buffer[iPos+1]=temp[6];
   buffer[iPos+0]=temp[7];

   return buffer;
  }
 }
 [ StructLayout( LayoutKind.Sequential, Pack=1,CharSet=CharSet.Ansi )]
 public struct CMPP_CANCEL_RESP
 {
  public CMPP_HEAD Head;
  public UInt32 SuccessID;
 }

 #endregion

}

【待续】

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
.Net/C# 实现 中国移动 CMPP v3.0 ISMG SP 收发短信的 SP 客户端 (第2版)(CMPP SP Client) 增加了 CMPP Client 类本程序严格按 《中国移动通信企业标准》之《中国移动通信互联网短信网关接口协议(China Mobile Point to Point)》(版本号: 3.0.0) 即: CMPP v3.0.0 http://www.spzone.net/protocol/CMPPV3.0.rar 文档,实现了下面消息的定义及其相关协议级交互: 8.4 业务提供商 (SP) 与互联网短信网关 (ISMG) 间的消息定义 8 8.4.1 SP 请求连接到 ISMG(CMPP_CONNECT) 操作 8 8.4.1.1 CMPP_CONNECT 消息定义 (SP -> ISMG) 8 8.4.1.2 CMPP_CONNECT_RESP消息定义 (ISMG -> SP) 9 8.4.2 SP 或 ISMG 请求拆除连接 (CMPP_TERMINATE)操作 9 8.4.2.1 CMPP_TERMINATE 消息定义 (SP -> ISMG 或 ISMG -> SP) 9 8.4.2.2 CMPP_TERMINATE_RESP 消息定义 (SP -> ISMG 或 ISMG -> SP) 10 8.4.3 SP 向 ISMG提交短信 (CMPP_SUBMIT) 操作 10 8.4.3.1 CMPP_SUBMIT 消息定义 (SP -> ISMG) 10 8.4.3.2 CMPP_SUBMIT_RESP 消息定义 (ISMG -> SP) 11 8.4.5 ISMG 向 SP 送交短信 (CMPP_DELIVER) 操作 13 8.4.5.1 CMPP_DELIVER 消息定义 (ISMG -> SP) 13 8.4.5.2 CMPP_DELIVER_RESP 消息定义 (SP -> ISMG) 16 8.4.7 链路检测 (CMPP_ACTIVE_TEST) 操作 17 8.4.7.1 CMPP_ACTIVE_TEST定义 (SP -> ISMG 或 ISMG <- SP) 17 8.4.7.2 CMPP_ACTIVE_TEST_RESP定义 (SP -> ISMG 或 ISMG <- SP) 17 可采用《中国移动通信 CMPP v3.0 短消息网关模拟器 v1.10》进行测试: 下载于: 《北京风起水流软件工作室》 http://www.zealware.com/download/cmpp3smg.rar本程序以熟悉理解 CMPP 3.0 协议为主要目的,只将 "消息定义" 对象化,其相关协议级交互并未作更深层次的 OO! 也暂无任何错误处理程序! 消息定义的所有字段名称及其数据类型均与上述之 CMPP v3.0.0 文档完全一致! 其间参阅过 shanhe@CSDN or yexiong@cnBlogs 大作(在此鸣谢): http://blog.csdn.net/shanhe/archive/2004/07/19/45383.aspx http://cnblogs.com/yexiong/articles/115330.aspx 但其中有些消息定义字节错位,因此不能正常交互?!且对象化层次较高,不利于理解协议本身! 遂自己动手,丰衣足食,实现部分主要协议(SP 收发短信):

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值