您的位置:首页 > 编程语言 > C#

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

2005-03-18 11:58 701 查看
 /*

.Net/C# 实现 中国移动 CMPP v3.0 ISMG <-> SP 收发短信的 SP 客户端 (CMPP SP 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

可采用《中国移动通信 CMPP v3.0 短消息网关模拟器 v1.10》进行测试:

下载于: 《北京风起水流软件工作室》
http://www.zealware.com/download/cmpp3pro.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 收发短信):

playyuer$at$microshaoft.com Invent.

*/

//CMPP 消息定义

namespace Microshaoft.CMPP.Messages

{

 using System;

 using System.Security.Cryptography;

 using System.Text;

 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 GetTimestampString(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 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 //: ICMPP_Message

 {

  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.GetTimestampString(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 //: ICMPP_Message

 {

  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

 {

  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) this._Fee_terminal_type; //[67,67]

   bytes[i++] = (byte) this._TP_pId; //[68,68]

   bytes[i++] = (byte) this._TP_udhi; //[69,69]

   bytes[i++] = (byte) 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;

   }

  }

  public string Msg_Content

  {

   get

   {

    return this._Msg_Content;

   }

   set

   {

    this._Msg_Content = value;

   }

  }

  public string LinkId

  {

   get

   {

    return this._LinkID;

   }

   set

   {

    this._LinkID = value;

   }

  }

 }

 public class CMPP_SUBMIT_RESP

 {

  MessageHeader _Header;

  private uint _Msg_Id;

  private uint _Result;

  public const int BodyLength = 8 + 4;

  public uint Msg_Id

  {

   get

   {

    return this._Msg_Id;

   }

  }

  public uint Result

  {

   get

   {

    return this._Result;

   }

  }

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public CMPP_SUBMIT_RESP(byte[] bytes)

  {

   int i = 0;

   byte[] buffer = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);

   this._Header = new MessageHeader(buffer);

   //Msg_Id

   i += MessageHeader.Length;

   buffer = new byte[8];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Msg_Id = BitConverter.ToUInt32(buffer, 0);

   //Result

   i += 8;

   buffer = new byte[4];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Result = BitConverter.ToUInt32(buffer, 0);

  }

 }

 public class CMPP_DELIVER

 {

  public ulong Msg_Id

  {

   get

   {

    return _Msg_Id;

   }

  }

  public string Dest_Id

  {

   get

   {

    return _Dest_Id;

   }

  }

  public string Service_Id

  {

   get

   {

    return _Service_Id;

   }

  }

  public uint TP_pid

  {

   get

   {

    return _TP_pid;

   }

  }

  public uint TP_udhi

  {

   get

   {

    return _TP_udhi;

   }

  }

  public uint Msg_Fmt

  {

   get

   {

    return _Msg_Fmt;

   }

  }

  public string Src_terminal_Id

  {

   get

   {

    return _Src_terminal_Id;

   }

  }

  public uint Src_terminal_type

  {

   get

   {

    return _Src_terminal_type;

   }

  }

  public uint Registered_Delivery

  {

   get

   {

    return _Registered_Delivery;

   }

  }

  public uint Msg_Length

  {

   get

   {

    return _Msg_Length;

   }

  }

  public string Msg_Content

  {

   get

   {

    return _Msg_Content;

   }

  }

  public string LinkId

  {

   get

   {

    return _LinkID;

   }

  }

  ulong _Msg_Id; // 8 Unsigned Integer 信息标识。

  //   生成算法如下:

  //   采用64位(8字节)的整数:

  //   (1)????????? 时间(格式为MMDDHHMMSS,即月日时分秒):bit64~bit39,其中

  //   bit64~bit61:月份的二进制表示;

  //   bit60~bit56:日的二进制表示;

  //   bit55~bit51:小时的二进制表示;

  //   bit50~bit45:分的二进制表示;

  //   bit44~bit39:秒的二进制表示;

  //   (2)????????? 短信网关代码:bit38~bit17,把短信网关的代码转换为整数填写到该字段中;

  //   (3)????????? 序列号:bit16~bit1,顺序增加,步长为1,循环使用。

  //   各部分如不能填满,左补零,右对齐。

  string _Dest_Id; // 21 Octet String 目的号码。

  //   SP的服务代码,一般4--6位,或者是前缀为服务代码的长号码;该号码是手机用户短消息的被叫号码。

  string _Service_Id; // 10 Octet String 业务标识,是数字、字母和符号的组合。

  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 _Src_terminal_Id; // 32 Octet String 源终端MSISDN号码(状态报告时填为CMPP_SUBMIT消息的目的终端号码)。

  uint _Src_terminal_type; // 1 Unsigned Integer 源终端号码类型,0:真实号码;1:伪码。

  uint _Registered_Delivery; // 1 Unsigned Integer 是否为状态报告:

  //   0:非状态报告;

  //   1:状态报告。

  uint _Msg_Length; // 1 Unsigned Integer 消息长度,取值大于或等于0。

  string _Msg_Content; // Msg_length Octet String 消息内容。

  string _LinkID; // 20 Octet String 点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。

  MessageHeader _Header;

  public MessageHeader Header

  {

   get

   {

    return this._Header;

   }

  }

  public const int FixedBodyLength = 8 // Msg_Id Unsigned Integer 信息标识。

   //   生成算法如下:

   //   采用64位(8字节)的整数:

   //   (1)????????? 时间(格式为MMDDHHMMSS,即月日时分秒):bit64~bit39,其中

   //   bit64~bit61:月份的二进制表示;

   //   bit60~bit56:日的二进制表示;

   //   bit55~bit51:小时的二进制表示;

   //   bit50~bit45:分的二进制表示;

   //   bit44~bit39:秒的二进制表示;

   //   (2)????????? 短信网关代码:bit38~bit17,把短信网关的代码转换为整数填写到该字段中;

   //   (3)????????? 序列号:bit16~bit1,顺序增加,步长为1,循环使用。

   //   各部分如不能填满,左补零,右对齐。

   + 21 // Dest_Id Octet String 目的号码。

   //   SP的服务代码,一般4--6位,或者是前缀为服务代码的长号码;该号码是手机用户短消息的被叫号码。

   + 10 // Service_Id Octet String 业务标识,是数字、字母和符号的组合。

   + 1 // TP_pid Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9。

   + 1 // TP_udhi Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。

   + 1 // Msg_Fmt Unsigned Integer 信息格式:

   //   0:ASCII串;

   //   3:短信写卡操作;

   //   4:二进制信息;

   //   8:UCS2编码;

   //   15:含GB汉字。

   + 32 // Src_terminal_Id Octet String 源终端MSISDN号码(状态报告时填为CMPP_SUBMIT消息的目的终端号码)。

   + 1 // Src_terminal_type Unsigned Integer 源终端号码类型,0:真实号码;1:伪码。

   + 1 // Registered_Delivery Unsigned Integer 是否为状态报告:

   //   0:非状态报告;

   //   1:状态报告。

   + 1 // Msg_Length Unsigned Integer 消息长度,取值大于或等于0。

   //Msg_length // Msg_Content Octet String 消息内容。

   + 20; // LinkID Octet String 点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。

  public int _BodyLength;

  public CMPP_DELIVER(byte[] bytes)

  {

   int i = 0;

   byte[] buffer = new byte[MessageHeader.Length];

   Buffer.BlockCopy(bytes, 0, buffer, 0, MessageHeader.Length);

   this._Header = new MessageHeader(buffer);

   //Msg_Id 8

   i += MessageHeader.Length;

   buffer = new byte[8];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   Array.Reverse(buffer);

   this._Msg_Id = BitConverter.ToUInt64(buffer, 0);

   //Dest_Id 21

   i += 8;

   buffer = new byte[21];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Dest_Id = Encoding.ASCII.GetString(buffer).Trim();

   //Service_Id 20

   i += 21;

   buffer = new byte[10];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Service_Id = Encoding.ASCII.GetString(buffer).Trim();

   //TP_pid 1

   i += 10;

   this._TP_pid = (uint) bytes[i++];

   this._TP_udhi = (uint) bytes[i++];

   this._Msg_Fmt = (uint) bytes[i++];

   //Src_terminal_Id 32

   buffer = new byte[32];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._Src_terminal_Id = Encoding.ASCII.GetString(buffer).Trim();

   //Src_terminal_type 1

   i += 32;

   this._Src_terminal_type = (uint) bytes[i++];

   this._Registered_Delivery = (uint) bytes[i++];

   this._Msg_Length = (uint) bytes[i++];

   //Msg_Content

   buffer = new byte[this._Msg_Length];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   switch (this._Msg_Fmt)

   {

    case 8:

     this._Msg_Content = Encoding.BigEndianUnicode.GetString(buffer).Trim();

     break;

    case 15: //gb2312

     this._Msg_Content = Encoding.GetEncoding("gb2312").GetString(buffer).Trim();

     break;

    case 0: //ascii

    case 3: //短信写卡操作

    case 4: //二进制信息

    default:

     this._Msg_Content = Encoding.ASCII.GetString(buffer).ToString();

     break;

   }

   //Linkid 20

   i += (int) this._Msg_Length;

   buffer = new byte[20];

   Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

   this._LinkID = Encoding.ASCII.GetString(buffer).Trim();

  }

  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 = FixedBodyLength + (int) this._Msg_Length;

   byte[] bytes = new byte[MessageHeader.Length + this._BodyLength];

   int i = 0;

   byte[] buffer = null;

   //header 12

   this._Header = new MessageHeader((uint) (MessageHeader.Length + this._BodyLength), CMPP_Command_Id.CMPP_DELIVER, 0);

   //Msg_Id 8

   i += MessageHeader.Length;

   buffer = new Byte[8];

   buffer = BitConverter.GetBytes(this._Msg_Id);

   Array.Reverse(buffer);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //Dest_Id 21

   i += 8;

   buffer = new byte[21];

   buffer = Encoding.ASCII.GetBytes(this._Dest_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //Service_Id 10

   i += 21;

   buffer = new byte[10];

   buffer = Encoding.ASCII.GetBytes(this._Service_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //TP_pid 1

   i += 10;

   bytes[i++] = (byte) this._TP_pid;

   bytes[i++] = (byte) this._TP_udhi;

   bytes[i++] = (byte) this._Msg_Fmt;

   //Src_terminal_Id 32

   buffer = new byte[32];

   buffer = Encoding.ASCII.GetBytes(this._Src_terminal_Id);

   Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

   //Src_terminal_type 1

   i += 32;

   bytes[i++] = (byte) this._Src_terminal_type;

   bytes[i++] = (byte) this._Registered_Delivery;

   bytes[i++] = (byte) this._Msg_Length;

   //Msg_Content

   Buffer.BlockCopy(buf, 0, bytes, i, buf.Length);

   //LinkID

   i += (int) this._Msg_Length;

   return bytes;

  }

 }

 class CMPP_DELIVER_RESP

 {

  private MessageHeader _Header;

  private ulong _Msg_Id;

  private uint _Result;

  public const int Bodylength = 8 + 4;

  public CMPP_DELIVER_RESP(ulong Msg_Id, uint Result)

  {

   this._Msg_Id = Msg_Id;

   this._Result = Result;

  }

  public byte[] ToBytes()

  {

   int i = 0;

   byte[] bytes = new byte[MessageHeader.Length + Bodylength];

   byte[] buffer = new byte[MessageHeader.Length];

   //header

   this._Header = new MessageHeader(MessageHeader.Length + Bodylength, CMPP_Command_Id.CMPP_DELIVER_RESP, 0);

   buffer = this._Header.ToBytes();

   Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);

   i += MessageHeader.Length;

   //msg_id 8

   buffer = BitConverter.GetBytes(this._Msg_Id);

   Array.Reverse(buffer);

   buffer.CopyTo(bytes, i);

   //result 4

   i += 8;

   buffer = BitConverter.GetBytes(this._Result);

   Array.Reverse(buffer);

   buffer.CopyTo(bytes, i);

   return bytes;

  }

 }

 class CMPP_Msg_Content //状态报告

 {

  public const int BodyLength = 8 + 7 + 10 + 10 + 32 + 4;

  private uint _Msg_Id; // 8 Unsigned Integer 信息标识。SP提交短信(CMPP_SUBMIT)操作时,与SP相连的ISMG产生的Msg_Id。

  private string _Stat; // 7 Octet String 发送短信的应答结果,含义详见表一。SP根据该字段确定CMPP_SUBMIT消息的处理状态。

  private string _Submit_time; // 10 Octet String YYMMDDHHMM(YY为年的后两位00-99,MM:01-12,DD:01-31,HH:00-23,MM:00-59)。

  private string _Done_time; // 10 Octet String YYMMDDHHMM。

  public CMPP_Msg_Content(byte[] bytes)

  {

   if (bytes.Length == BodyLength)

   {

    int i = 0;

    //_Msg_Id 8

    byte[] buffer = new byte[8];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    Array.Reverse(buffer);

    this._Msg_Id = BitConverter.ToUInt32(buffer, 0);

    //_Stat 7

    i += 8;

    buffer = new byte[7];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Stat = Encoding.ASCII.GetString(buffer);

    //_Submit_time 10

    i += 7;

    buffer = new byte[10];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Submit_time = Encoding.ASCII.GetString(buffer);

    //_Done_time 10

    i += 10;

    buffer = new byte[10];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Submit_time = Encoding.ASCII.GetString(buffer);

    //Dest_terminal_Id 32

    i += 10;

    buffer = new byte[32];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    this._Dest_terminal_Id = Encoding.ASCII.GetString(buffer);

    //SMSC_sequence 4

    i += 32;

    buffer = new byte[4];

    Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);

    Array.Reverse(buffer);

    this._SMSC_sequence = BitConverter.ToUInt32(buffer,0);

   }

  }

  public uint Msg_Id

  {

   get

   {

    return this._Msg_Id;

   }

   set

   {

    this._Msg_Id = value;

   }

  }

  public string Stat

  {

   get

   {

    return this._Stat;

   }

   set

   {

    this._Stat = value;

   }

  }

  public string Submit_time

  {

   get

   {

    return this._Submit_time;

   }

   set

   {

    this._Submit_time = value;

   }

  }

  public string Done_time

  {

   get

   {

    return this._Done_time;

   }

   set

   {

    this._Done_time = value;

   }

  }

  public string Dest_terminal_Id

  {

   get

   {

    return this._Dest_terminal_Id;

   }

   set

   {

    this._Dest_terminal_Id = value;

   }

  }

  public uint SMSC_sequence

  {

   get

   {

    return this._SMSC_sequence;

   }

   set

   {

    this._SMSC_sequence = value;

   }

  }

  private string _Dest_terminal_Id; // 32 Octet String 目的终端MSISDN号码(SP发送CMPP_SUBMIT消息的目标终端)。

  private uint _SMSC_sequence; // 4 Unsigned Integer 取自SMSC发送状态报告的消息体中的消息标识。

 }

}

//测试程序

namespace Test

{

 using System;

 using System.Text;

 using System.Net.Sockets;

 using System.Threading;

 using Microshaoft.CMPP.Messages;

 public class ConsoleApplication

 {

  static void Main()

  {

   Console.WriteLine("请先运行并启动:\n《中国移动通信 CMPP v3.0 短消息网关模拟器 v1.10》进行测试:"

    + "\n下载于: 《北京风起水流软件工作室》"

    + "\nhttp://www.zealware.com/download/cmpp3pro.rar\n");

   Console.WriteLine("按任意键\n测试: SP 群发短信 -> ISMG");

   Console.ReadLine();

   Console.WriteLine("请注意观察《中国移动通信 CMPP v3.0 短消息网关模拟器》系统状态!");

   Submit(); //SP -> ISMG 群发短信

   Console.WriteLine("\n==============================================================");

   Console.WriteLine("\n按任意键\n测试: ISMG -> SP 接收短信");

   Console.ReadLine();

   Console.WriteLine("请在《中国移动通信 CMPP v3.0 短消息网关模拟器》下发消息!");

   Console.WriteLine("该模拟器不能自动生成\"状态报告\"!请在该模拟器中下发消息中自行键入下面短信内容后,\n并将 Registered_Delivery = 1 ,再发送:");

   Console.WriteLine("00000001DELIVRD031213505003121350501391xxx11381391xxx11381391xx11380001");

   //订阅短信到达事件 ISMG -> SP

   CMPP_Deliver += new CMPP_DeliverEventHandler(ConsoleApplication_CMPP_Deliver);

   new Thread(new ThreadStart(DoWait)).Start();

   

   //该模拟器不能自动生成状态报告再下发!请自行键入下面短信内容后,发送

   //状态报告短信: 00000001DELIVRD031213505003121350501391xxx11381391xxx11381391xx11380001

   Deliver(); //ISMG -> SP 接收短信

   Console.ReadLine();

  }

  //退出程序(死循环)标志

  static bool B = false;

  static void DoWait()

  {

   while (Console.ReadLine().ToLower() != "q")

   {

    Console.WriteLine("press 'q' to exit this programe!");

   }

   B = true;

   Console.WriteLine("bye!");

  }

  //声明短信到达处理事件

  public delegate void CMPP_DeliverEventHandler(CMPP_DELIVER cmpp_deliver);

  public static event CMPP_DeliverEventHandler CMPP_Deliver;

  static void Deliver()

  {

   NetworkStream S;

   int s = 10; //buffer size

   if (CMPP_CONNECT_RESP(out S))

   {

    byte[] bytes = new byte[400];

    while (!B)

    {

     if (S.CanRead)

     {

      if (S.DataAvailable)

      {

       byte[] buffer = null;

       buffer = ResponseAsBytes(S, bytes.Length, s);

       if (buffer.Length > 0)

       {

        CMPP_DELIVER deliver = new CMPP_DELIVER(buffer);

        PrintHeader(deliver.Header);

        if (CMPP_Deliver != null)

        {

         CMPP_Deliver(deliver);

        }

        if (S.CanWrite)

        {

         CMPP_DELIVER_RESP deliver_resp = new CMPP_DELIVER_RESP(deliver.Msg_Id, 0);

         buffer = deliver_resp.ToBytes();

         S.Write(buffer, 0, buffer.Length);

        }

       }

       

      }

     }

    }

    MessageHeader terminate = new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_TERMINATE, 1);

    if (S.CanWrite)

    {

     S.Write(terminate.ToBytes(), 0, MessageHeader.Length);

    }

    if (S.CanRead)

    {

     bytes = ResponseAsBytes(S, MessageHeader.Length, s);

     MessageHeader terminate_resp = new MessageHeader(bytes);

     PrintHeader(terminate_resp);

    }

    S.Close();

    S = null;

   }

  }

  static bool CMPP_CONNECT_RESP(out NetworkStream Stream)

  {

   bool b = false;

   TcpClient tc = new TcpClient();

   tc.Connect("127.0.0.1", 7890);

   string UserID = "901234";

   string Password = "1234";

   CMPP_CONNECT connect = new CMPP_CONNECT(UserID, Password, DateTime.Now, 1);

   PrintHeader(connect.Header);

   byte[] bytes = connect.ToBytes();

   Stream = tc.GetStream();

   if (Stream.CanWrite)

   {

    Stream.Write(bytes, 0, bytes.Length);

   }

   if (Stream.CanRead)

   {

    int s = 10; //buffer size

    bytes = ResponseAsBytes(Stream, MessageHeader.Length + CMPP_CONNECT.BodyLength, s);

    CMPP_CONNECT_RESP connect_resp = new CMPP_CONNECT_RESP(bytes);

    PrintHeader(connect_resp.Header);

    if (connect_resp.Header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP)

    {

     b = connect_resp.Status == 0;

    }

   }

   return b;

  }

  static void Submit()

  {

   TcpClient tc = new TcpClient();

   tc.Connect("127.0.0.1", 7890);

   string UserID = "901234";

   string Password = "1234";

   CMPP_CONNECT connect = new CMPP_CONNECT(UserID, Password, DateTime.Now, 1);

   PrintHeader(connect.Header);

   byte[] bytes = connect.ToBytes();

   NetworkStream ns = tc.GetStream();

   if (ns.CanWrite)

   {

    ns.Write(bytes, 0, bytes.Length);

   }

   if (ns.CanRead)

   {

    int s = 10; //buffer size

    bytes = ResponseAsBytes(ns, MessageHeader.Length + CMPP_CONNECT.BodyLength, s);

    CMPP_CONNECT_RESP connect_resp = new CMPP_CONNECT_RESP(bytes);

    PrintHeader(connect_resp.Header);

    if (connect_resp.Header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP)

    {

     if (connect_resp.Status == 0)

     {

      CMPP_SUBMIT submit = new CMPP_SUBMIT();

      //submit.Msg_Id = 0;        //      uint _Msg_Id;      // 8 Unsigned Integer 信息标识。

      submit.Pk_total = 1; //      uint _Pk_total;      // 1 Unsigned Integer 相同Msg_Id的信息总条数,从1开始。

      submit.Pk_number = 0; //      uint _Pk_number;     // 1 Unsigned Integer 相同Msg_Id的信息序号,从1开始。

      submit.Registered_Delivery = 1; //      uint _Registered_Delivery;   // 1 Unsigned Integer 是否要求返回状态确认报告:

      //      //   0:不需要;

      //      //   1:需要。

      submit.Msg_level = 1; //      uint _Msg_level;     // 1 Unsigned Integer 信息级别。

      submit.Service_Id = "abcdefghij"; //      string _Service_Id;     // 10 Octet String 业务标识,是数字、字母和符号的组合。

      submit.Fee_UserType = 3; //      uint _Fee_UserType;     // 1 Unsigned Integer 计费用户类型字段:

      //      //   0:对目的终端MSISDN计费;

      //      //   1:对源终端MSISDN计费;

      //      //   2:对SP计费;

      //      //   3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。

      submit.Fee_terminal_Id = "1391xxx1138"; //      string _Fee_terminal_Id;   // 32 Octet String 被计费用户的号码,当Fee_UserType为3时该值有效,当Fee_UserType为0、1、2时该值无意义。

      submit.Fee_terminal_type = 0; //      uint _Fee_terminal_type;   // 1 Unsigned Integer 被计费用户的号码类型,0:真实号码;1:伪码。

      submit.Tp_pId = 0; //      uint _TP_pId;      // 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9。

      submit.Tp_udhi = 0; //      uint _TP_udhi;      // 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。

      submit.Msg_Fmt = 15; //      uint _Msg_Fmt;      // 1 Unsigned Integer 信息格式:

      //      //   0:ASCII串;

      //      //   3:短信写卡操作;

      //      //   4:二进制信息;

      //      //   8:UCS2编码;

      //      //   15:含GB汉字。。。。。。

      submit.Msg_src = UserID; //      string _Msg_src;     // 6 Octet String 信息内容来源(SP_Id)。

      submit.FeeType = "02"; //      string _FeeType;     // 2 Octet String 资费类别:

      //      //   01:对"计费用户号码"免费;

      //      //   02:对"计费用户号码"按条计信息费;

      //      //   03:对"计费用户号码"按包月收取信息费。

      submit.FeeCode = "100"; //      string _FeeCode;     // 6 Octet String 资费代码(以分为单位)。

      //Why not 17?

      submit.ValId_Time = Util.GetTimestampString(DateTime.Now.AddHours(2)) + "032+"; //      string _ValId_Time;     // 17 Octet String 存活有效期,格式遵循SMPP3.3协议。

      submit.At_Time = Util.GetTimestampString(DateTime.Now) + "032+"; //      string _At_Time;     // 17 Octet String 定时发送时间,格式遵循SMPP3.3协议。

      //spnum

      submit.Src_Id = ""; //      string _Src_Id;      // 21 Octet String 源号码。SP的服务代码或前缀为服务代码的长号码, 网关将该号码完整的填到SMPP协议Submit_SM消息相应的source_addr字段,该号码最终在用户手机上显示为短消息的主叫号码。

      submit.Dest_terminal_Id = new string[] {"1391xxx1138", "1391xxx1137"}; //      string[] _Dest_terminal_Id;   // 32*DestUsr_tl Octet String 接收短信的MSISDN号码。

      submit.DestUsr_tl = (uint) submit.Dest_terminal_Id.Length; //      uint _DestUsr_tl;     // 1 Unsigned Integer 接收信息的用户数量(小于100个用户)。

      //

      //

      submit.Dest_terminal_type = 0; //      uint _Dest_terminal_type;   // 1 Unsigned Integer 接收短信的用户的号码类型,0:真实号码;1:伪码。

      submit.Msg_Fmt = 15; //      uint _Msg_Length;     // 1 Unsigned Integer 信息长度(Msg_Fmt值为0时:<160个字节;其它<=140个字节),取值大于或等于0。

      submit.Msg_Content = "大家好!这是一个短信群发测试!"; //      string _Msg_Content;    // Msg_length Octet String 信息内容。

      submit.LinkId = ""; //      string _LinkID;      // 20 Octet String 点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。

      bytes = submit.ToBytes();

      if (ns.CanWrite)

      {

       ns.Write(bytes, 0, bytes.Length);

      }

      if (ns.CanRead)

      {

       bytes = ResponseAsBytes(ns, MessageHeader.Length + CMPP_SUBMIT_RESP.BodyLength, s);

       CMPP_SUBMIT_RESP submit_resp = new CMPP_SUBMIT_RESP(bytes);

       Console.WriteLine(submit_resp.Msg_Id);

       Console.WriteLine(submit_resp.Result);

       PrintHeader(submit_resp.Header);

       MessageHeader terminate = new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_TERMINATE, 1);

       if (ns.CanWrite)

       {

        ns.Write(terminate.ToBytes(), 0, MessageHeader.Length);

       }

       if (ns.CanRead)

       {

        bytes = ResponseAsBytes(ns, MessageHeader.Length, s);

        MessageHeader terminate_resp = new MessageHeader(bytes);

        PrintHeader(terminate_resp);

       }

       ns.Close();

       ns = null;

      }

     }

    }

   }

  }

  private static byte[] ResponseAsBytes(NetworkStream Stream, int Length, int BufferSize)

  {

   int l;

   byte[] bytes = new byte[Length];

   l = 0;

   do

   {

    byte[] buffer = new byte[BufferSize];

    int r = Stream.Read(buffer, 0, buffer.Length);

    if (r > 0)

    {

     Buffer.BlockCopy(buffer, 0, bytes, l, r);

     l += r;

    }

   } while (Stream.DataAvailable);

   byte[] Bytes = new byte[l];

   Buffer.BlockCopy(bytes, 0, Bytes, 0, Bytes.Length);

   return Bytes;

  }

  public static void PrintHeader(MessageHeader Header)

  {

   Console.WriteLine(Header.Total_Length);

   Console.WriteLine(Header.Command_Id);

   Console.WriteLine(Header.Sequence_Id);

  }

  //短信到达事件

  private static void ConsoleApplication_CMPP_Deliver(CMPP_DELIVER deliver)

  {

   PrintHeader(deliver.Header);

   string s = "";

   if (deliver.Registered_Delivery == 0) //普通短信

   {

    s = String.Format("普通短信: {0}\n{1}",deliver.Src_terminal_Id, deliver.Msg_Content);

   }

   else

   //该模拟器不能自动生成状态报告再下发!请自行键入下面短信内容后,发送

   //状态报告短信: 00000001DELIVRD031213505003121350501391xxx11381391xxx11381391xx11380001

   {

    CMPP_Msg_Content x = new CMPP_Msg_Content(Encoding.ASCII.GetBytes(deliver.Msg_Content));

    s = String.Format("状态报告: {0}\n{1}",x.Stat, x.Dest_terminal_Id);

   }

   System.Console.WriteLine(s);

  }

 }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐