C 实现 中国移动 CMPP v3.0 ISMG SP 收发短信的 SP 客户端 (CMPP SP Client)

更新时间:2023-06-08 23:34:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

.Net/C# 实现 中国移动 CMPP v3.0 ISMG SP 收发短信 的 SP 客户端 (CMPP SP Client)分类 C# (Csharp) 2006-8-30 5:38:52 浏览 1006 回复 0 删除 隐藏侧边栏 转自 playyuer .复制 保存编辑 删除静态/* .Net/C# 实现 中国移动 CMPP v3.0 ISMG <-> SP 收发短信的 SP 客户端 (CMPP SP Client) 本程序严格按 《中国移动通信企业标准》之《中国移动通信互联网短信网关接口协议(China Mobile Point to Point)》(版本号: 3.0.0) 即: CMPP v3.0.0 /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》进行测试: 下载于: 《北京风起水流软件工作室》 /download/cmpp3pro.rar

本程序以熟悉理解 CMPP 3.0 协议为主要目的,只将 "消息定义" 对象化,其相 关协议级交互并未作更深层次的 OO! 也暂无任何错误处理程序! 消息定义的所有字段名称及其数据类型均与上述之 CMPP v3.0.0 文档完全一 致! 其间参阅过 shanhe@CSDN or yexiong@cnBlogs 大作(在此鸣谢): /shanhe/archive/2004/07/19/45383.aspx /yexiong/articles/115330.aspx 但其中有些消息定义字节错位,因此不能正常交互?!且对象化层次较高,不利于 理解协议本身! 遂自己动手,丰衣足食,实现部分主要协议(SP 收发短信): playyuer$at$ Invent. */ //CMPP 消息定义 namespace Microshaoft.CMPP.Messages { using System; using System.Security.Cryptography; using System.Text; public class CMPP_Request { } public class CMPP_Response { } public enum CMPP_Command_Id : uint { CMPP_CONNECT = 0x00000001 //请求连接 , CMPP_CONNECT_RESP = 0x80000001 //请求连接应答 , CMPP_TERMINATE = 0x00000002 //终止连接 , CMPP_TERMINATE_RESP = 0x80000002 //终止连接应答 , CMPP_SUBMIT = 0x00000004 //提交短信 ,

CMPP_SUBMIT_RESP = 0x80000004 //提交短信应答 , CMPP_DELIVER = 0x00000005 //短信下发 , CMPP_DELIVER_RESP = 0x80000005 //下发短信应答 , CMPP_QUERY = 0x00000006 //发送短信状态查询 , CMPP_QUERY_RESP = 0x80000006 //发送短信状态查询应答 , CMPP_CANCEL = 0x00000007 //删除短信 , CMPP_CANCEL_RESP = 0x80000007 //删除短信应答 , CMPP_ACTIVE_TEST = 0x00000008 //激活测试 , CMPP_ACTIVE_TEST_RESP = 0x80000008 //激活测试应答 , CMPP_FWD = 0x00000009 //消息前转 , CMPP_FWD_RESP = 0x80000009 //消息前转应答 , CMPP_MT_ROUTE = 0x00000010 //MT 路由请求 , CMPP_MT_ROUTE_RESP = 0x80000010 //MT 路由请求应答 , CMPP_MO_ROUTE = 0x00000011 //MO 路由请求 , CMPP_MO_ROUTE_RESP = 0x80000011 //MO 路由请求应答 , CMPP_GET_MT_ROUTE = 0x00000012 //获取 MT 路由请求 , CMPP_GET_MT_ROUTE_RESP = 0x80000012 //获取 MT 路由请求应答 , CMPP_MT_ROUTE_UPDATE = 0x00000013 //MT 路由更新 , CMPP_MT_ROUTE_UPDATE_RESP = 0x80000013 //MT 路由更新应答 , CMPP_MO_ROUTE_UPDATE = 0x00000014 //MO 路由更新 , CMPP_MO_ROUTE_UPDATE_RESP = 0x80000014 //MO 路由更新应答 , CMPP_PUSH_MT_ROUTE_UPDATE = 0x00000015 //MT 路由更新 ,

CMPP_PUSH_MT_ROUTE_UPDATE_RESP = 0x80000015 //MT 路由更新应答 , CMPP_PUSH_MO_ROUTE_UPDATE = 0x00000016 //MO 路由更新 , CMPP_PUSH_MO_ROUTE_UPDATE_RESP = 0x80000016 //MO 路由更新应答 , CMPP_GET_MO_ROUTE = 0x00000017 //获取 MO 路由请求 , CMPP_GET_MO_ROUTE_RESP = 0x80000017 //获取 MO 路由请求应答 } public class Util { public static string Get_MMDDHHMMSS_String(DateTime dt) { string s = dt.Month.ToString().PadLeft(2, '0'); s += dt.Day.ToString().PadLeft(2, '0'); s += dt.Hour.ToString().PadLeft(2, '0'); s += dt.Minute.ToString().PadLeft(2, '0'); s += dt.Second.ToString().PadLeft(2, '0'); return (s); } public static string Get_YYYYMMDD_String(DateTime dt) { string s = dt.Year.ToString().PadLeft(4, '0'); s += dt.Month.ToString().PadLeft(2, '0'); s += dt.Day.ToString().PadLeft(2, '0'); return (s); } } public class MessageHeader //消息头 { public const int Length = 4 + 4 + 4; //private byte[] _bytes = new byte[MessageHeader.Length]; public CMPP_Command_Id Command_Id { get { return this._Command_Id; } } public uint Sequence_Id

{ get { return this._Sequence_Id; } } public uint Total_Length { get { return this._Total_Length; } } //private CMPP_Command_Id _Command_Id; //private uint _Sequence_Id; //private uint _Total_Length; uint _Total_Length; // 4 Unsigned Integer 消息总长度(含消息头 及消息体) CMPP_Command_Id _Command_Id; // 4 Unsigned Integer 命令或响应 类型 uint _Sequence_Id; // 4 Unsigned Integer 消息流水号,顺序累加, 步长为 1,循环使用(一对请求和应答消息的流水号必须相同) public MessageHeader(uint Total_Length, CMPP_Command_Id Command_Id, uint Sequence_Id) //发送前 { this._Command_Id = Command_Id; this._Sequence_Id = Sequence_Id; this._Total_Length = Total_Length; } public MessageHeader(byte[] bytes) { byte[] buffer = new byte[4]; Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length); Array.Reverse(buffer); this._Total_Length = BitConverter.ToUInt32(buffer, 0); Buffer.BlockCopy(bytes, 4, buffer, 0, buffer.Length); Array.Reverse(buffer);

this._Command_Id = (CMPP_Command_Id) (BitConverter.ToUInt32(buffer, 0)); Buffer.BlockCopy(bytes, 8, buffer, 0, buffer.Length); Array.Reverse(buffer); this._Sequence_Id = BitConverter.ToUInt32(buffer, 0); }public byte[] ToBytes() { byte[] bytes = new byte[MessageHeader.Length]; byte[] buffer = BitConverter.GetBytes(this._Total_Length); Array.Reverse(buffer); Buffer.BlockCopy(buffer, 0, bytes, 0, 4); buffer = BitConverter.GetBytes((uint) this._Command_Id); Array.Reverse(buffer); Buffer.BlockCopy(buffer, 0, bytes, 4, 4); buffer = BitConverter.GetBytes(this._Sequence_Id); Array.Reverse(buffer); Buffer.BlockCopy(buffer, 0, bytes, 8, 4); return bytes; } } public class CMPP_CONNECT : CMPP_Request { public const int BodyLength = 6 + 16 + 1 + 4; string _Source_Addr; // 6 Octet String 源地址,此处为 SP_Id,即 SP 的企业代码。 private string _Password; byte[] _AuthenticatorSource; // 16 Octet String 用于鉴别源地址。 其值通过单向 MD5 hash 计算得出,表示如下: // AuthenticatorSource = // MD5(Source_Addr+9 字节的 0 +shared secret+timestamp) // Shared secret 由中国移动与源地址实体事先商定,timestamp 格 式为:MMDDHHMMSS,即月日时分秒,10 位。

uint _Version; // 1 Unsigned Integer 双方协商的版本号(高位 4bit 表示主版本号,低位 4bit 表示次版本号),对于 3.0 的版本,高 4bit 为 3,低 4 位 为0 uint _Timestamp; // 4 Unsigned Integer 时间戳的明文,由客户端产 生,格式为 MMDDHHMMSS,即月日时分秒,10 位数字的整型,右对齐 。 private MessageHeader _Header; public MessageHeader Header { get { return this._Header; } } public byte[] AuthenticatorSource { get { return this._AuthenticatorSource; } } public CMPP_CONNECT(string Source_Addr, string Password, DateTime Timestamp, uint Version) { this._Header = new MessageHeader(MessageHeader.Length + BodyLength, CMPP_Command_Id.CMPP_CONNECT, 1); this._Source_Addr = Source_Addr; this._Password = Password; string s = Util.Get_MMDDHHMMSS_String(Timestamp); this._Timestamp = UInt32.Parse(s); byte[] buffer = new byte[6 + 9 + this._Password.Length + 10]; Encoding.ASCII.GetBytes(this._Source_Addr).CopyTo(buffer, 0); Encoding.ASCII.GetBytes(this._Password).CopyTo(buffer, 6 + 9); Encoding.ASCII.GetBytes(s).CopyTo(buffer, 6 + 9 + this._Password.Length);

this._AuthenticatorSource = new MD5CryptoServiceProvider().ComputeHash(buffer, 0, buffer.Length); this._Version = Version; } public byte[] ToBytes() { byte[] bytes = new byte[MessageHeader.Length + BodyLength]; int i = 0; //header 12 byte[] buffer = this._Header.ToBytes(); Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length); //Source_Addr 6 i += MessageHeader.Length; buffer = Encoding.ASCII.GetBytes(this._Source_Addr); Buffer.BlockCopy(buffer, 0, bytes, i, 6); //AuthenticatorSource 16 i += 6; buffer = this._AuthenticatorSource; Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //16 //version 1 i += 16; bytes[i++] = (byte) this._Version; //版本 //Timestamp buffer = BitConverter.GetBytes(this._Timestamp); Array.Reverse(buffer); buffer.CopyTo(bytes, i); return (bytes); } } public class CMPP_CONNECT_RESP : CMPP_Response { MessageHeader _Header; public const int _FixedBodyLength = 4 + 16 + 1; uint _Status; // 4 Unsigned Integer 状态 // 0:正确

// 1:消息结构错 // 2:非法源地址 // 3:认证错 // 4:版本太高 // 5~:其他错误 byte[] _AuthenticatorISMG; // 16 Octet String ISMG 认证码,用于 鉴别 ISMG。 // 其值通过单向 MD5 hash 计算得出,表示如下: // AuthenticatorISMG =MD5(Status+AuthenticatorSource+shared secret),Shared secret 由中国移动与源地址实体事先商 定,AuthenticatorSource 为源地址实体发送给 ISMG 的对应消息 CMPP_Connect 中的值。 // 认证出错时,此项为空。 uint _Version; // 1 Unsigned Integer 服务器支持的最高版本号, 对于 3.0 的版本,高 4bit 为 3,低 4 位为 0 public byte[] AuthenticatorISMG { get { return this._AuthenticatorISMG; } } public uint Status { get { return this._Status; } } public uint Version { get { return this._Version; } } public MessageHeader Header { get {

return this._Header; } } public CMPP_CONNECT_RESP(byte[] bytes) { //header 12 int i = 0; byte[] buffer = new byte[MessageHeader.Length]; Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length); this._Header = new MessageHeader(buffer); //status 4 i += MessageHeader.Length; buffer = new byte[4]; Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length); Array.Reverse(buffer); this._Status = BitConverter.ToUInt32(buffer, 0); //AuthenticatorISMG 16 i += 4; this._AuthenticatorISMG = new byte[16]; Buffer.BlockCopy(bytes, MessageHeader.Length + 4, this._AuthenticatorISMG, 0, this._AuthenticatorISMG.Length); //version i += 16; this._Version = bytes[i]; } } public class CMPP_SUBMIT : CMPP_Request { public int _BodyLength; //without _Dest_terminal_Id Msg_Content public const int FixedBodyLength = 8 + 1 + 1 + 1 + 1 + 10 + 1 + 32 + 1

+ + + + + + + + + +1 1 1 6 2 6 17 17 21 1 //+ 32*DestUsr_tl + 1 + 1 //+ Msg_length + 20; ulong _Msg_Id; // 8 Unsigned Integer 信息标识。 uint _Pk_total; // 1 Unsigned Integer 相同 Msg_Id 的信息总条数, 从 1 开始。 uint _Pk_number; // 1 Unsigned Integer 相同 Msg_Id 的信息序号, 从 1 开始。 uint _Registered_Delivery; // 1 Unsigned Integer 是否要求返回 状态确认报告: // 0:不需要; // 1:需要。 uint _Msg_level; // 1 Unsigned Integer 信息级别。 string _Service_Id; // 10 Octet String 业务标识,是数字、字母和 符号的组合。 uint _Fee_UserType; // 1 Unsigned Integer 计费用户类型字段: // 0:对目的终端 MSISDN 计费; // 1:对源终端 MSISDN 计费; // 2:对 SP 计费; // 3:表示本字段无效,对谁计费参见 Fee_terminal_Id 字段。 string _Fee_terminal_Id; // 32 Octet String 被计费用户的号码, 当 Fee_UserType 为 3 时该值有效,当 Fee_UserType 为 0、1、2 时该值无意义。 uint _Fee_terminal_type; // 1 Unsigned Integer 被计费用户的号 码类型,0:真实号码;1:伪码。 uint _TP_pId; // 1 Unsigned Integer GSM 协议类型。详细是解释请 参考 GSM03.40 中的 9.2.3.9。 uint _TP_udhi; // 1 Unsigned Integer GSM 协议类型。详细是解释 请参考 GSM03.40 中的 9.2.3.23,仅使用 1 位,右对齐。 uint _Msg_Fmt; // 1 Unsigned Integer 信息格式: // 0:ASCII 串; // 3:短信写卡操作;

// 4:二进制信息; // 8:UCS2 编码; // 15:含 GB 汉字。。。。。。 string _Msg_src; // 6 Octet String 信息内容来源(SP_Id)。 string _FeeType; // 2 Octet String 资费类别: // 01:对"计费用户号码"免费; // 02:对"计费用户号码"按条计信息费; // 03:对"计费用户号码"按包月收取信息费。 string _FeeCode; // 6 Octet String 资费代码(以分为单位)。 string _ValId_Time; // 17 Octet String 存活有效期,格式遵循 SMPP3.3 协议。 string _At_Time; // 17 Octet String 定时发送时间,格式遵循 SMPP3.3 协议。 string _Src_Id; // 21 Octet String 源号码。SP 的服务代码或前缀 为服务代码的长号码, 网关将该号码完整的填到 SMPP 协议 Submit_SM 消息相应 的 source_addr 字段,该号码最终在用户手机上显示为短消息的主叫号码。 uint _DestUsr_tl; // 1 Unsigned Integer 接收信息的用户数量(小 于 100 个用户)。 string[] _Dest_terminal_Id; // 32*DestUsr_tl Octet String 接收 短信的 MSISDN 号码。uint _Dest_terminal_type; // 1 Unsigned Integer 接收短信的用户 的号码类型,0:真实号码;1:伪码。 uint _Msg_Length; // 1 Unsigned Integer 信息长度(Msg_Fmt 值为 0 时:<160 个字节;其它<=140 个字节),取值大于或等于 0。 string _Msg_Content; // Msg_length Octet String 信息内容。 string _LinkID; // 20 Octet String 点播业务使用的 LinkID,非点 播类业务的 MT 流程不使用该字段。 MessageHeader _Header; public CMPP_SUBMIT() { //this._Header = new MessageHeader(MessageHeader._Length + _FixedBodyLength, CMPP_Command_Id.CMPP_SUBMIT, 1); } public byte[] ToBytes() { //Msg_Length Msg_Content byte[] buf; switch (this._Msg_Fmt) {

case 8: buf = Encoding.BigEndianUnicode.GetBytes(this._Msg_Content); break; case 15: //gb2312 buf = Encoding.GetEncoding("gb2312").GetBytes(this._Msg_Content); break; case 0: //ascii case 3: //短信写卡操作 case 4: //二进制信息 default: buf = Encoding.ASCII.GetBytes(this._Msg_Content); break; } this._Msg_Length = (uint) buf.Length; this._BodyLength = (int) (FixedBodyLength + 32 * this._Dest_terminal_Id.Length + this._Msg_Length); byte[] bytes = new byte[MessageHeader.Length + this._BodyLength]; int i = 0; byte[] buffer = new byte[MessageHeader.Length]; //header this._Header = new MessageHeader((uint) (MessageHeader.Length + this._BodyLength), CMPP_Command_Id.CMPP_SUBMIT, 0); buffer = this._Header.ToBytes(); Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length); i += MessageHeader.Length; //Msg_Id //8 [12,19] buffer = new byte[8]; buffer = BitConverter.GetBytes(this._Msg_Id); Array.Reverse(buffer); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33] //_Pk_total i += 8; bytes[i++] = (byte) this._Pk_total; //[20,20] bytes[i++] = (byte) this._Pk_number; //[21,21]

bytes[i++] = (byte) this._Registered_Delivery; //[22,22] bytes[i++] = (byte) this._Msg_level; //[23,23] //Service_Id buffer = Encoding.ASCII.GetBytes(this._Service_Id); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33] //Fee_UserType i += 10; bytes[i++] = (byte) this._Fee_UserType; //[34,34] //Fee_terminal_Id buffer = Encoding.ASCII.GetBytes(this._Fee_terminal_Id); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //32 //[35,66] //Fee_terminal_type i += 32; bytes[i++] = (byte) bytes[i++] = (byte) bytes[i++] = (byte) bytes[i++] = (byte)this._Fee_terminal_type; //[67,67] this._TP_pId; //[68,68] this._TP_udhi; //[69,69] this._Msg_Fmt; //[70,70]//Msg_src buffer = Encoding.ASCII.GetBytes(this._Msg_src); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[71,76] //FeeType i += 6; buffer = Encoding.ASCII.GetBytes(this._FeeType); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //2 //[77,78] //FeeCode i += 2; buffer = Encoding.ASCII.GetBytes(this._FeeCode); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[79,84] //ValId_Time i += 6; //buffer = Encoding.ASCII.GetBytes(this._ValId_Time);

//Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //17 //[85,101] //At_Time i += 17; //buffer = Encoding.ASCII.GetBytes(this._At_Time); //Buffer.BlockCopy(buffer , 0, bytes, i, buffer.Length); //17 //[102,118] //Src_Id i += 17; buffer = Encoding.ASCII.GetBytes(this._Src_Id); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //21 //[119,139] //DestUsr_tl i += 21; this._DestUsr_tl = (uint) this._Dest_terminal_Id.Length; bytes[i++] = (byte) this._DestUsr_tl; //[140,140] //Dest_terminal_Id foreach (string s in this._Dest_terminal_Id) { buffer = Encoding.ASCII.GetBytes(s); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); i += 32; } //Dest_terminal_type bytes[i++] = (byte) this._Dest_terminal_type; //Msg_Length bytes[i++] = (byte) this._Msg_Length; //Msg_Content //buffer = Encoding. Buffer.BlockCopy(buf, 0, bytes, i, buf.Length); //LinkID i += (int) this._Msg_Length; buffer = Encoding.ASCII.GetBytes(this._LinkID); Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //20 return bytes; }

public ulong Msg_Id { get { return this._Msg_Id; } set { this._Msg_Id = value; } } public uint Pk_total { get { return this._Pk_total; } set { this._Pk_total = value; } } public uint Pk_number { get { return this._Pk_number; } set { this._Pk_number = value; } } public uint Registered_Delivery { get { return this._Registered_Delivery; } set {

this._Registered_Delivery = value; } } public uint Msg_level { get { return this._Msg_level; } set { this._Msg_level = value; } } public string Service_Id { get { return this._Service_Id; } set { this._Service_Id = value; } } public uint Fee_UserType { get { return this._Fee_UserType; } set { this._Fee_UserType = value; } } public string Fee_terminal_Id { get {

return this._Fee_terminal_Id; } set { this._Fee_terminal_Id = value; } } public uint Fee_terminal_type { get { return this._Fee_terminal_type; } set { this._Fee_terminal_type = value; } } public uint Tp_pId { get { return this._TP_pId; } set { this._TP_pId = value; } } public uint Tp_udhi { get { return this._TP_udhi; } set { this._TP_udhi = value; } }

public uint Msg_Fmt { get { return this._Msg_Fmt; } set { this._Msg_Fmt = value; } } public string Msg_src { get { return this._Msg_src; } set { _Msg_src = value; } } public string FeeType { get { return this._FeeType; } set { this._FeeType = value; } } public string FeeCode { get { return this._FeeCode; } set {

this._FeeCode = value; } } public string ValId_Time { get { return this._ValId_Time; } set { this._ValId_Time = value; } } public string At_Time { get { return this._At_Time; } set { this._At_Time = value; } } public string Src_Id { get { return this._Src_Id; } set { this._Src_Id = value; } } public uint DestUsr_tl { get {

return this._DestUsr_tl; } set { this._DestUsr_tl = value; } } public string[] Dest_terminal_Id { get { return this._Dest_terminal_Id; } set { this._Dest_terminal_Id = value; } } public uint Dest_terminal_type { get { return this._Dest_terminal_type; } set { this._Dest_terminal_type = value; } } public uint Msg_Length { get { return this._Msg_Length; } set { this._Msg_Length = value; } }

本文来源:https://www.bwwdw.com/article/m921.html

Top