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


/*
.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 v3.0 短消息网关模拟器 v1.10》
http://tech.spforum.net/uploadfile/2006426181749702.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㊣Microshaoft.com Invent.
*/
namespace Microshaoft
{
    using System;
    using System.Net.Sockets;
    public class Utility
    {
        public static string BytesArrayToHexString(byte[] data)
        {
            return BitConverter.ToString(data).Replace("-", "");
        }
        public static byte[] HexStringToBytesArray(string text)
        {
            text = text.Replace(" ", "");
            int l = text.Length;
            byte[] buffer = new byte[l / 2];
            for (int i = 0; i < l; i += 2)
            {
                buffer[i / 2] = Convert.ToByte(text.Substring(i, 2), 16);
            }
            return buffer;
        }
        //private static object _SyncLockObject = new object();
        public static string Get_MMDDHHMMSS_String(DateTime dt)
        {
            return DateTime.Now.ToString("MMddhhmmss");
        }
        public static string Get_YYYYMMDD_String(DateTime dt)
        {
            return DateTime.Now.ToString("yyyyMMdd");
        }
        internal static void WriteToStream(byte[] bytes, NetworkStream Stream)
        {
            if (Stream.CanWrite)
            {
                //lock (_SyncLockObject)
                {
                    Stream.Write(bytes, 0, bytes.Length);
                }
            }
        }
        internal static byte[] ReadStreamToBytes(int Length, NetworkStream Stream)
        {
            byte[] bytes = null;
            if (Stream.CanRead)
            {
                if (Stream.DataAvailable)
                {
                    bytes = new byte[Length];
                    int l = 0;
                    //lock (_SyncLockObject)
                    {
                        while (l < Length)
                        {
                            int r;
                            r = Stream.Read(bytes, l, Length - l);
                            l += r;
                        }
                    }
                }
            }
            return bytes;
        }
    }
}
//CMPP 消息定义
namespace Microshaoft.CMPP.Messages
{
    using System;
    using System.Text;
    using System.Security.Cryptography;
    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 MessageHeader //消息头
    {
        public const int Length = 4 + 4 + 4;
        public CMPP_Command_Id Command_Id
        {
            get
            {
                return _Command_Id;
            }
        }
        public uint Sequence_Id
        {
            get
            {
                return _Sequence_Id;
            }
        }
        public uint Total_Length
        {
            get
            {
                return _Total_Length;
            }
        }
        private uint _Total_Length;        // 4 Unsigned Integer 消息总长度(含消息头及消息体)
        private CMPP_Command_Id _Command_Id;     // 4 Unsigned Integer 命令或响应类型
        private uint _Sequence_Id;        // 4 Unsigned Integer 消息流水号,顺序累加,步长为1,循环使用(一对请求和应答消息的流水号必须相同)
        public MessageHeader
          (
           uint Total_Length
           , CMPP_Command_Id Command_Id
           , uint Sequence_Id
          ) //发送前
        {
            _Total_Length = Total_Length;
            _Command_Id = Command_Id;
            _Sequence_Id = Sequence_Id;
        }
        public MessageHeader(byte[] bytes)
        {
            byte[] buffer = new byte[4];
            Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _Total_Length = BitConverter.ToUInt32(buffer, 0);
            Buffer.BlockCopy(bytes, 4, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _Command_Id = (CMPP_Command_Id)BitConverter.ToUInt32(buffer, 0);
            Buffer.BlockCopy(bytes, 8, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _Sequence_Id = BitConverter.ToUInt32(buffer, 0);
        }
        public byte[] ToBytes()
        {
            byte[] bytes = new byte[MessageHeader.Length];
            byte[] buffer = BitConverter.GetBytes(_Total_Length);
            Array.Reverse(buffer);
            Buffer.BlockCopy(buffer, 0, bytes, 0, 4);
            buffer = BitConverter.GetBytes((uint)_Command_Id);
            Array.Reverse(buffer);
            Buffer.BlockCopy(buffer, 0, bytes, 4, 4);
            buffer = BitConverter.GetBytes(_Sequence_Id);
            Array.Reverse(buffer);
            Buffer.BlockCopy(buffer, 0, bytes, 8, 4);
            return bytes;
        }
        public override string ToString()
        {
            return string.Format
              (
               "\tMessageHeader:{0}Command_Id: {1}{0}Sequence_Id: {2}{0}Total_Length: {2}"
               , "\r\n\t\t"
               , _Command_Id
               , _Sequence_Id
               , _Total_Length
              );
        }
    }
    public class CMPP_CONNECT         //: CMPP_Request
    {
        public const int BodyLength = 6 + 16 + 1 + 4;
        private string _Source_Addr;       // 6 Octet String 源地址,此处为SP_Id,即SP的企业代码。
        private string _Password;
        private byte[] _AuthenticatorSource;     // 16 Octet String 用于鉴别源地址。其值通过单向MD5 hash计算得出,表示如下:
        //   AuthenticatorSource =
        //   MD5(Source_Addr+9 字节的0 +shared secret+timestamp)
        //   Shared secret 由中国移动与源地址实体事先商定,timestamp格式为:MMDDHHMMSS,即月日时分秒,10位。
        private uint _Version;         // 1 Unsigned Integer 双方协商的版本号(高位4bit表示主版本号,低位4bit表示次版本号),对于3.0的版本,高4bit为3,低4位为0
        private uint _Timestamp;        // 4 Unsigned Integer 时间戳的明文,由客户端产生,格式为MMDDHHMMSS,即月日时分秒,10位数字的整型,右对齐 。
        private MessageHeader _Header;
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
        }
        public byte[] AuthenticatorSource
        {
            get
            {
                return _AuthenticatorSource;
            }
        }
        public CMPP_CONNECT
         (
          string Source_Addr
          , string Password
          , DateTime Timestamp
          , uint Version
          , uint Sequence_Id
         )
        {
            _Header = new MessageHeader
                (
                 MessageHeader.Length + BodyLength
                 , CMPP_Command_Id.CMPP_CONNECT
                 , Sequence_Id
                );
            _Source_Addr = Source_Addr;
            _Password = Password;
            string s = Utility.Get_MMDDHHMMSS_String(Timestamp);
            _Timestamp = UInt32.Parse(s);
            byte[] buffer = new byte[6 + 9 + _Password.Length + 10];
            Encoding.ASCII.GetBytes(_Source_Addr).CopyTo(buffer, 0);
            Encoding.ASCII.GetBytes(_Password).CopyTo(buffer, 6 + 9);
            Encoding.ASCII.GetBytes(s).CopyTo(buffer, 6 + 9 + _Password.Length);
            _AuthenticatorSource = new MD5CryptoServiceProvider().ComputeHash(buffer, 0, buffer.Length);
            _Version = Version;
        }
        public byte[] ToBytes()
        {
            int i = 0;
            byte[] bytes = new byte[MessageHeader.Length + BodyLength];
            //header 12
            byte[] buffer = _Header.ToBytes();
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);
            //Source_Addr 6
            i += MessageHeader.Length;
            buffer = Encoding.ASCII.GetBytes(_Source_Addr);
            Buffer.BlockCopy(buffer, 0, bytes, i, 6);
            //AuthenticatorSource 16
            i += 6;
            buffer = _AuthenticatorSource;
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //16
            //version 1
            i += 16;
            bytes[i++] = (byte)_Version; //版本
            //Timestamp
            buffer = BitConverter.GetBytes(_Timestamp);
            Array.Reverse(buffer);
            buffer.CopyTo(bytes, i);
            return (bytes);
        }
        public override string ToString()
        {
            return "[\r\n"
               + _Header.ToString() + "\r\n"
               + "\t"
               + string.Format
                 (
                  "MessageBody:"
                  + "{0}AuthenticatorSource: {1}"
                  + "{0}Password: {2}"
                  + "{0}Source_Addr: {3}"
                  + "{0}Version: {4}"
                  , "\r\n\t\t"
                  , Utility.BytesArrayToHexString(_AuthenticatorSource)
                  , _Password
                  , _Source_Addr
                  , _Timestamp
                  , _Version
                 )
               + "\r\n]";
        }
    }
    public class CMPP_CONNECT_RESP //: CMPP_Response
    {
        private MessageHeader _Header;
        public const int BodyLength = 4 + 16 + 1;
        private uint _Status;         // 4 Unsigned Integer 状态
        //   0:正确
        //   1:消息结构错
        //   2:非法源地址
        //   3:认证错
        //   4:版本太高
        //   5~:其他错误
        private byte[] _AuthenticatorISMG;      // 16 Octet String ISMG认证码,用于鉴别ISMG。
        //   其值通过单向MD5 hash计算得出,表示如下:
        //   AuthenticatorISMG =MD5(Status+AuthenticatorSource+shared secret),Shared secret 由中国移动与源地址实体事先商定,AuthenticatorSource为源地址实体发送给ISMG的对应消息CMPP_Connect中的值。
        // 认证出错时,此项为空。
        private uint _Version;         // 1 Unsigned Integer 服务器支持的最高版本号,对于3.0的版本,高4bit为3,低4位为0
        public byte[] AuthenticatorISMG
        {
            get
            {
                return _AuthenticatorISMG;
            }
        }
        public uint Status
        {
            get
            {
                return _Status;
            }
        }
        public uint Version
        {
            get
            {
                return _Version;
            }
        }
        public MessageHeader Header
        {
            get
            {
                return _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);
            _Header = new MessageHeader(buffer);
            //status 4
            i += MessageHeader.Length;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _Status = BitConverter.ToUInt32(buffer, 0);
            //AuthenticatorISMG 16
            i += 4;
            _AuthenticatorISMG = new byte[16];
            Buffer.BlockCopy
               (
                bytes
                , MessageHeader.Length + 4
                , _AuthenticatorISMG
                , 0
                , _AuthenticatorISMG.Length
               );
            //version
            i += 16;
            _Version = bytes[i];
        }
        public override string ToString()
        {
            return "[\r\n"
              + _Header.ToString() + "\r\n"
              + "\t"
              + string.Format
               (
                "MessageBody:"
                + "{0}AuthenticatorISMG: {1}"
                + "{0}BodyLength: {2}"
                + "{0}Status: {3}"
                + "{0}Version: {4}"
                , "\r\n\t\t"
                , Utility.BytesArrayToHexString(_AuthenticatorISMG)
                , CMPP_CONNECT_RESP.BodyLength
                , _Status
                , _Version
               )
              + "\r\n]";
        }
    }
    public class CMPP_SUBMIT //: CMPP_Request
    {
        private 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;
        private ulong _Msg_Id;         // 8 Unsigned Integer 信息标识。
        private uint _Pk_total;         // 1 Unsigned Integer 相同Msg_Id的信息总条数,从1开始。
        private uint _Pk_number;        // 1 Unsigned Integer 相同Msg_Id的信息序号,从1开始。
        private uint _Registered_Delivery;      // 1 Unsigned Integer 是否要求返回状态确认报告:
        //   0:不需要;
        //   1:需要。
        private uint _Msg_level;        // 1 Unsigned Integer 信息级别。
        private string _Service_Id;        // 10 Octet String 业务标识,是数字、字母和符号的组合。
        private uint _Fee_UserType;        // 1 Unsigned Integer 计费用户类型字段:
        //   0:对目的终端MSISDN计费;
        //   1:对源终端MSISDN计费;
        //   2:对SP计费;
        //   3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。
        private string _Fee_terminal_Id;      // 32 Octet String 被计费用户的号码,当Fee_UserType为3时该值有效,当Fee_UserType为0、1、2时该值无意义。
        private uint _Fee_terminal_type;      // 1 Unsigned Integer 被计费用户的号码类型,0:真实号码;1:伪码。
        private uint _TP_pId;         // 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9。
        private uint _TP_udhi;         // 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。
        private uint _Msg_Fmt;         // 1 Unsigned Integer 信息格式:
        //   0:ASCII串;
        //   3:短信写卡操作;
        //   4:二进制信息;
        //   8:UCS2编码;
        //   15:含GB汉字......
        private string _Msg_src;        // 6 Octet String 信息内容来源(SP_Id)。
        private string _FeeType;        // 2 Octet String 资费类别:
        //   01:对"计费用户号码"免费;
        //   02:对"计费用户号码"按条计信息费;
        //   03:对"计费用户号码"按包月收取信息费。
        private string _FeeCode;        // 6 Octet String 资费代码(以分为单位)。
        private string _ValId_Time;        // 17 Octet String 存活有效期,格式遵循SMPP3.3协议。
        private string _At_Time;        // 17 Octet String 定时发送时间,格式遵循SMPP3.3协议。
        private string _Src_Id;         // 21 Octet String 源号码。SP的服务代码或前缀为服务代码的长号码, 网关将该号码完整的填到SMPP协议Submit_SM消息相应的source_addr字段,该号码最终在用户手机上显示为短消息的主叫号码。
        private uint _DestUsr_tl;        // 1 Unsigned Integer 接收信息的用户数量(小于100个用户)。
        private string[] _Dest_terminal_Id;      // 32*DestUsr_tl Octet String 接收短信的MSISDN号码。
        private uint _Dest_terminal_type;      // 1 Unsigned Integer 接收短信的用户的号码类型,0:真实号码;1:伪码。
        private uint _Msg_Length;        // 1 Unsigned Integer 信息长度(Msg_Fmt值为0时:<160个字节;其它<=140个字节),取值大于或等于0。
        private string _Msg_Content;       // Msg_length Octet String 信息内容。
        private string _LinkID;         // 20 Octet String 点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
            set
            {
                _Header = value;
            }
        }
        private MessageHeader _Header;
        private uint _Sequence_Id;
        public CMPP_SUBMIT(uint Sequence_Id)
        {
            _Sequence_Id = Sequence_Id;
        }
        private byte[] _Msg_Content_Bytes;
        private void SetHeader()
        {
            //byte[] buf;
            switch (_Msg_Fmt)
            {
                case 8:
                    _Msg_Content_Bytes = Encoding.BigEndianUnicode.GetBytes(_Msg_Content);
                    break;
                case 15: //gb2312
                    _Msg_Content_Bytes = Encoding.GetEncoding("gb2312").GetBytes(_Msg_Content);
                    break;
                case 0: //ascii
                case 3: //短信写卡操作
                case 4: //二进制信息
                default:
                    _Msg_Content_Bytes = Encoding.ASCII.GetBytes(_Msg_Content);
                    break;
            }
            _Msg_Length = (uint)_Msg_Content_Bytes.Length;
            _BodyLength = (int)(FixedBodyLength + 32 * _Dest_terminal_Id.Length + _Msg_Length);
            _Header = new MessageHeader
                (
                 (uint)(MessageHeader.Length + _BodyLength)
                 , CMPP_Command_Id.CMPP_SUBMIT
                 , _Sequence_Id
                );
        }
        public byte[] ToBytes()
        {
            //Msg_Length Msg_Content
            int i = 0;
            byte[] bytes = new byte[MessageHeader.Length + _BodyLength];
            byte[] buffer = _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(_Msg_Id);
            Array.Reverse(buffer);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33]
            //_Pk_total
            i += 8;
            bytes[i++] = (byte)_Pk_total; //[20,20]
            bytes[i++] = (byte)_Pk_number; //[21,21]
            bytes[i++] = (byte)_Registered_Delivery; //[22,22]
            bytes[i++] = (byte)_Msg_level; //[23,23]
            //Service_Id
            buffer = Encoding.ASCII.GetBytes(_Service_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33]
            //Fee_UserType
            i += 10;
            bytes[i++] = (byte)_Fee_UserType; //[34,34]
            //Fee_terminal_Id
            buffer = Encoding.ASCII.GetBytes(_Fee_terminal_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //32 //[35,66]
            //Fee_terminal_type
            i += 32;
            bytes[i++] = (byte)_Fee_terminal_type; //[67,67]
            bytes[i++] = (byte)_TP_pId; //[68,68]
            bytes[i++] = (byte)_TP_udhi; //[69,69]
            bytes[i++] = (byte)_Msg_Fmt; //[70,70]
            //Msg_src
            buffer = Encoding.ASCII.GetBytes(_Msg_src);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[71,76]
            //FeeType
            i += 6;
            buffer = Encoding.ASCII.GetBytes(_FeeType);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //2 //[77,78]
            //FeeCode
            i += 2;
            buffer = Encoding.ASCII.GetBytes(_FeeCode);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[79,84]
            //ValId_Time
            i += 6;
            buffer = Encoding.ASCII.GetBytes(_ValId_Time);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //17 //[85,101]
            //At_Time
            i += 17;
            buffer = Encoding.ASCII.GetBytes(_At_Time);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //17 //[102,118]
            //Src_Id
            i += 17;
            buffer = Encoding.ASCII.GetBytes(_Src_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //21 //[119,139]
            //DestUsr_tl
            i += 21;
            _DestUsr_tl = (uint)_Dest_terminal_Id.Length;
            bytes[i++] = (byte)_DestUsr_tl; //[140,140]
            //Dest_terminal_Id
            foreach (string s in _Dest_terminal_Id)
            {
                buffer = Encoding.ASCII.GetBytes(s);
                Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);
                i += 32;
            }
            //Dest_terminal_type
            bytes[i++] = (byte)_Dest_terminal_type;
            //Msg_Length
            bytes[i++] = (byte)_Msg_Length;
            //Msg_Content
            //buffer = Encoding.
            Buffer.BlockCopy
               (
                _Msg_Content_Bytes
                , 0
                , bytes
                , i, _Msg_Content_Bytes.Length
               );
            //LinkID
            i += (int)_Msg_Length;
            buffer = Encoding.ASCII.GetBytes(_LinkID);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //20
            return bytes;
        }
        public ulong Msg_Id
        {
            get
            {
                return _Msg_Id;
            }
            set
            {
                _Msg_Id = value;
            }
        }
        public uint Pk_total
        {
            get
            {
                return _Pk_total;
            }
            set
            {
                _Pk_total = value;
            }
        }
        public uint Pk_number
        {
            get
            {
                return _Pk_number;
            }
            set
            {
                _Pk_number = value;
            }
        }
        public uint Registered_Delivery
        {
            get
            {
                return _Registered_Delivery;
            }
            set
            {
                _Registered_Delivery = value;
            }
        }
        public uint Msg_level
        {
            get
            {
                return _Msg_level;
            }
            set
            {
                _Msg_level = value;
            }
        }
        public string Service_Id
        {
            get
            {
                return _Service_Id;
            }
            set
            {
                _Service_Id = value;
            }
        }
        public uint Fee_UserType
        {
            get
            {
                return _Fee_UserType;
            }
            set
            {
                _Fee_UserType = value;
            }
        }
        public string Fee_terminal_Id
        {
            get
            {
                return _Fee_terminal_Id;
            }
            set
            {
                _Fee_terminal_Id = value;
            }
        }
        public uint Fee_terminal_type
        {
            get
            {
                return _Fee_terminal_type;
            }
            set
            {
                _Fee_terminal_type = value;
            }
        }
        public uint TP_pId
        {
            get
            {
                return _TP_pId;
            }
            set
            {
                _TP_pId = value;
            }
        }
        public uint TP_udhi
        {
            get
            {
                return _TP_udhi;
            }
            set
            {
                _TP_udhi = value;
            }
        }
        public uint Msg_Fmt
        {
            get
            {
                return _Msg_Fmt;
            }
            set
            {
                _Msg_Fmt = value;
                if (_Msg_Content != null)
                {
                    SetHeader();
                }
            }
        }
        public string Msg_src
        {
            get
            {
                return _Msg_src;
            }
            set
            {
                _Msg_src = value;
            }
        }
        public string FeeType
        {
            get
            {
                return _FeeType;
            }
            set
            {
                _FeeType = value;
            }
        }
        public string FeeCode
        {
            get
            {
                return _FeeCode;
            }
            set
            {
                _FeeCode = value;
            }
        }
        public string ValId_Time
        {
            get
            {
                return _ValId_Time;
            }
            set
            {
                _ValId_Time = value;
            }
        }
        public string At_Time
        {
            get
            {
                return _At_Time;
            }
            set
            {
                _At_Time = value;
            }
        }
        public string Src_Id
        {
            get
            {
                return _Src_Id;
            }
            set
            {
                _Src_Id = value;
            }
        }
        public uint DestUsr_tl
        {
            get
            {
                return _DestUsr_tl;
            }
            set
            {
                _DestUsr_tl = value;
            }
        }
        public string[] Dest_terminal_Id
        {
            get
            {
                return _Dest_terminal_Id;
            }
            set
            {
                _Dest_terminal_Id = value;
            }
        }
        public uint Dest_terminal_type
        {
            get
            {
                return _Dest_terminal_type;
            }
            set
            {
                _Dest_terminal_type = value;
            }
        }
        public uint Msg_Length
        {
            get
            {
                return _Msg_Length;
            }
            set
            {
                _Msg_Length = value;
            }
        }
        public string Msg_Content
        {
            get
            {
                return _Msg_Content;
            }
            set
            {
                _Msg_Content = value;
                SetHeader();
            }
        }
        public string LinkId
        {
            get
            {
                return _LinkID;
            }
            set
            {
                _LinkID = value;
            }
        }
        public override string ToString()
        {
            return "[\r\n"
              + _Header.ToString() + "\r\n"
              + "\t"
              + string.Format
              (
               "MessageBody:"
               + "{0}At_Time: {1}"
               + "{0}BodyLength: {2}"
               + "{0}Dest_terminal_Id: {3}"
               + "{0}Dest_terminal_type: {4}"
               + "{0}DestUsr_tl: {5}"
               + "{0}Fee_terminal_Id: {6}"
               + "{0}Fee_terminal_type: {7}"
               + "{0}Fee_UserType: {8}"
               + "{0}FeeCode: {9}"
               + "{0}FeeType: {10}"
               + "{0}LinkID: {11}"
               + "{0}Msg_Content: {12}"
               + "{0}Msg_Fmt: {13}"
               + "{0}Msg_Id: {14}"
               + "{0}Msg_Length: {15}"
               + "{0}Msg_level: {16}"
               + "{0}Msg_src: {17}"
               + "{0}Pk_number: {18}"
               + "{0}Pk_total: {19}"
               + "{0}Registered_Delivery: {20}"
               + "{0}Sequence_Id: {21}"
               + "{0}Service_Id: {22}"
               + "{0}Src_Id: {23}"
               + "{0}TP_pId: {24}"
               + "{0}TP_udhi: {25}"
               + "{0}ValId_Time: {26}"
               , "\r\n\t\t"
               , _At_Time
               , _BodyLength
               , String.Join(",", _Dest_terminal_Id)
               , _Dest_terminal_type
               , _DestUsr_tl
               , _Fee_terminal_Id
               , _Fee_terminal_type
               , _Fee_UserType
               , _FeeCode
               , _FeeType
               , _LinkID
               , _Msg_Content
               , _Msg_Fmt
               , _Msg_Id
               , _Msg_Length
               , _Msg_level
               , _Msg_src
               , _Pk_number
               , _Pk_total
               , _Registered_Delivery
               , _Sequence_Id
               , _Service_Id
               , _Src_Id
               , _TP_pId
               , _TP_udhi
               , _ValId_Time
              )
              + "\r\n]";
        }
    }
    public class CMPP_SUBMIT_RESP //: CMPP_Response
    {
        private MessageHeader _Header;
        private uint _Msg_Id;
        private uint _Result;
        public const int BodyLength = 8 + 4;
        public uint Msg_Id
        {
            get
            {
                return _Msg_Id;
            }
        }
        public uint Result
        {
            get
            {
                return _Result;
            }
        }
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
        }
        public CMPP_SUBMIT_RESP(byte[] bytes)
        {
            int i = 0;
            byte[] buffer = new byte[MessageHeader.Length];
            Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);
            _Header = new MessageHeader(buffer);
            //Msg_Id
            i += MessageHeader.Length;
            buffer = new byte[8];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _Msg_Id = BitConverter.ToUInt32(buffer, 0);
            //Result
            i += 8;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _Result = BitConverter.ToUInt32(buffer, 0);
        }
        public override string ToString()
        {
            return "[\r\n"
              + _Header.ToString() + "\r\n"
              + "\t"
              + string.Format
               (
                "MessageBody:"
                + "{0}Msg_Id: {1}"
                + "{0}Result: {2}"
                , "\r\n\t\t"
                , _Msg_Id
                , _Result
               )
              + "\r\n]";
        }
    }
    public class CMPP_DELIVER //: CMPP_Request
    {
        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;
            }
        }
        private 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,循环使用。
        //   各部分如不能填满,左补零,右对齐。
        private string _Dest_Id;       // 21 Octet String 目的号码。
        //   SP的服务代码,一般4--6位,或者是前缀为服务代码的长号码;该号码是手机用户短消息的被叫号码。
        private string _Service_Id;       // 10 Octet String 业务标识,是数字、字母和符号的组合。
        private uint _TP_pid;        // 1 Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9。
        private uint _TP_udhi;        // 1 Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。
        private uint _Msg_Fmt;        // 1 Unsigned Integer 信息格式:
        //   0:ASCII串;
        //   3:短信写卡操作;
        //   4:二进制信息;
        //   8:UCS2编码;
        //   15:含GB汉字。
        private string _Src_terminal_Id;     // 32 Octet String 源终端MSISDN号码(状态报告时填为CMPP_SUBMIT消息的目的终端号码)。
        private uint _Src_terminal_type;     // 1 Unsigned Integer 源终端号码类型,0:真实号码;1:伪码。
        private uint _Registered_Delivery;     // 1 Unsigned Integer 是否为状态报告:
        //   0:非状态报告;
        //   1:状态报告。
        private uint _Msg_Length;       // 1 Unsigned Integer 消息长度,取值大于或等于0。
        private string _Msg_Content;      // Msg_length Octet String 消息内容。
        private string _LinkID;        // 20 Octet String 点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。
        private MessageHeader _Header;
        public MessageHeader Header
        {
            get
            {
                return _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流程不使用该字段。
        private int _BodyLength;
        public int BodyLength
        {
            get
            {
                return _BodyLength;
            }
        }
        public CMPP_DELIVER(byte[] bytes)
        {
            int i = 0;
            byte[] buffer = new byte[MessageHeader.Length];
            Buffer.BlockCopy(bytes, 0, buffer, 0, MessageHeader.Length);
            _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);
            _Msg_Id = BitConverter.ToUInt64(buffer, 0);
            string s = null;
            //Dest_Id 21
            i += 8;
            buffer = new byte[21];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            s = Encoding.ASCII.GetString(buffer).Trim();
            s = s.Substring(0, s.IndexOf('\0'));
            _Dest_Id = s;
            //Service_Id 20
            i += 21;
            buffer = new byte[10];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            s = Encoding.ASCII.GetString(buffer).Trim();
            s = s.Substring(0, s.IndexOf('\0'));
            _Service_Id = s;
            //TP_pid 1
            i += 10;
            _TP_pid = (uint)bytes[i++];
            _TP_udhi = (uint)bytes[i++];
            _Msg_Fmt = (uint)bytes[i++];
            //Src_terminal_Id 32
            buffer = new byte[32];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            s = Encoding.ASCII.GetString(buffer).Trim();
            s = s.Substring(0, s.IndexOf('\0'));
            _Src_terminal_Id = s;
            //Src_terminal_type 1
            i += 32;
            _Src_terminal_type = (uint)bytes[i++];
            _Registered_Delivery = (uint)bytes[i++];
            _Msg_Length = (uint)bytes[i++];
            //Msg_Content
            buffer = new byte[_Msg_Length];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            switch (_Msg_Fmt)
            {
                case 8:
                    _Msg_Content = Encoding.BigEndianUnicode.GetString(buffer).Trim();
                    break;
                case 15: //gb2312
                    _Msg_Content = Encoding.GetEncoding("gb2312").GetString(buffer).Trim();
                    break;
                case 0: //ascii
                case 3: //短信写卡操作
                case 4: //二进制信息
                default:
                    _Msg_Content = Encoding.ASCII.GetString(buffer).ToString();
                    break;
            }
            //Linkid 20
            i += (int)_Msg_Length;
            buffer = new byte[20];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            s = Encoding.ASCII.GetString(buffer).Trim();
            s = s.Substring(0, s.IndexOf('\0'));
            _LinkID = s;
        }
        public byte[] ToBytes()
        {
            //Msg_Length Msg_Content
            byte[] buf;
            switch (_Msg_Fmt)
            {
                case 8:
                    buf = Encoding.BigEndianUnicode.GetBytes(_Msg_Content);
                    break;
                case 15: //gb2312
                    buf = Encoding.GetEncoding("gb2312").GetBytes(_Msg_Content);
                    break;
                case 0: //ascii
                case 3: //短信写卡操作
                case 4: //二进制信息
                default:
                    buf = Encoding.ASCII.GetBytes(_Msg_Content);
                    break;
            }
            _Msg_Length = (uint)buf.Length;
            _BodyLength = FixedBodyLength + (int)_Msg_Length;
            byte[] bytes = new byte[MessageHeader.Length + _BodyLength];
            int i = 0;
            byte[] buffer = null;
            //header 12
            _Header = new MessageHeader
                 (
                  (uint)(MessageHeader.Length + _BodyLength)
                  , CMPP_Command_Id.CMPP_DELIVER
                  , 0
                 );
            //Msg_Id 8
            i += MessageHeader.Length;
            buffer = new Byte[8];
            buffer = BitConverter.GetBytes(_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(_Dest_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);
            //Service_Id 10
            i += 21;
            buffer = new byte[10];
            buffer = Encoding.ASCII.GetBytes(_Service_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);
            //TP_pid 1
            i += 10;
            bytes[i++] = (byte)_TP_pid;
            bytes[i++] = (byte)_TP_udhi;
            bytes[i++] = (byte)_Msg_Fmt;
            //Src_terminal_Id 32
            buffer = new byte[32];
            buffer = Encoding.ASCII.GetBytes(_Src_terminal_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);
            //Src_terminal_type 1
            i += 32;
            bytes[i++] = (byte)_Src_terminal_type;
            bytes[i++] = (byte)_Registered_Delivery;
            bytes[i++] = (byte)_Msg_Length;
            //Msg_Content
            Buffer.BlockCopy(buf, 0, bytes, i, buf.Length);
            //LinkID
            i += (int)_Msg_Length;
            return bytes;
        }
        public override string ToString()
        {
            return "[\r\n"
              + _Header.ToString() + "\r\n"
              + "\t"
              + string.Format
                 (
                  "MessageBody:"
                  + "{0}BodyLength: {1}"
                  + "{0}Dest_Id: {2}"
                  + "{0}LinkID: {3}"
                  + "{0}Msg_Content: {4}"
                  + "{0}Msg_Fmt: {5}"
                  + "{0}Msg_Id: {6}"
                  + "{0}Msg_Length: {7}"
                  + "{0}Registered_Delivery: {8}"
                  + "{0}Service_Id: {9}"
                  + "{0}Src_terminal_Id: {10}"
                  + "{0}Src_terminal_type: {11}"
                  + "{0}TP_pid: {12}"
                  + "{0}TP_udhi: {13}"
                  , "\r\n\t\t"
                  , _BodyLength
                  , _Dest_Id
                  , _LinkID
                  , _Msg_Content
                  , _Msg_Fmt
                  , _Msg_Id
                  , _Msg_Length
                  , _Registered_Delivery
                  , _Service_Id
                  , _Src_terminal_Id
                  , _Src_terminal_type
                  , _TP_pid
                  , _TP_udhi
                 )
              + "\r\n]";
        }
    }
    public class CMPP_DELIVER_RESP //: CMPP_Response
    {
        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)
        {
            _Msg_Id = Msg_Id;
            _Result = Result;
        }
        public byte[] ToBytes()
        {
            int i = 0;
            byte[] bytes = new byte[MessageHeader.Length + Bodylength];
            byte[] buffer = new byte[MessageHeader.Length];
            //header
            _Header = new MessageHeader
                 (
                  MessageHeader.Length + Bodylength
                  , CMPP_Command_Id.CMPP_DELIVER_RESP
                  , 0
                 );
            buffer = _Header.ToBytes();
            Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);
            i += MessageHeader.Length;
            //msg_id 8
            buffer = BitConverter.GetBytes(_Msg_Id);
            Array.Reverse(buffer);
            buffer.CopyTo(bytes, i);
            //result 4
            i += 8;
            buffer = BitConverter.GetBytes(_Result);
            Array.Reverse(buffer);
            buffer.CopyTo(bytes, i);
            return bytes;
        }
        public override string ToString()
        {
            return _Header.ToString() + "\r\n"
              + string.Format
                 (
                  "[\r\nMessageBody:"
                  + "\r\n\tMsg_Id: {0}"
                  + "\r\n\tResult: {1}"
                  + "\r\n]"
                  , _Msg_Id
                  , _Result
                 );
        }
    }
    public 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);
                _Msg_Id = BitConverter.ToUInt32(buffer, 0);
                //_Stat 7
                i += 8;
                buffer = new byte[7];
                Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
                _Stat = Encoding.ASCII.GetString(buffer);
                //_Submit_time 10
                i += 7;
                buffer = new byte[10];
                Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
                _Submit_time = Encoding.ASCII.GetString(buffer);
                //_Done_time 10
                i += 10;
                buffer = new byte[10];
                Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
                _Submit_time = Encoding.ASCII.GetString(buffer);
                //Dest_terminal_Id 32
                i += 10;
                buffer = new byte[32];
                Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
                _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);
                _SMSC_sequence = BitConverter.ToUInt32(buffer, 0);
            }
        }
        public uint Msg_Id
        {
            get
            {
                return _Msg_Id;
            }
            set
            {
                _Msg_Id = value;
            }
        }
        public string Stat
        {
            get
            {
                return _Stat;
            }
            set
            {
                _Stat = value;
            }
        }
        public string Submit_time
        {
            get
            {
                return _Submit_time;
            }
            set
            {
                _Submit_time = value;
            }
        }
        public string Done_time
        {
            get
            {
                return _Done_time;
            }
            set
            {
                _Done_time = value;
            }
        }
        public string Dest_terminal_Id
        {
            get
            {
                return _Dest_terminal_Id;
            }
            set
            {
                _Dest_terminal_Id = value;
            }
        }
        public uint SMSC_sequence
        {
            get
            {
                return _SMSC_sequence;
            }
            set
            {
                _SMSC_sequence = value;
            }
        }
        private string _Dest_terminal_Id;      // 32 Octet String 目的终端MSISDN号码(SP发送CMPP_SUBMIT消息的目标终端)。
        private uint _SMSC_sequence;       // 4 Unsigned Integer 取自SMSC发送状态报告的消息体中的消息标识。
        public override string ToString()
        {
            return string.Format
                (
                 "[\r\nMessageBody:"
                 + "\r\n\tBodyLength: {0}"
                 + "\r\n\tDest_terminal_Id: {1}"
                 + "\r\n\tDone_time: {2}"
                 + "\r\n\tMsg_Id: {3}"
                 + "\r\n\tSMSC_sequence: {4}"
                 + "\r\n\tStat: {5}"
                 + "\r\n\tSubmit_time: {6}"
                 + "\r\n]"
                 , CMPP_Msg_Content.BodyLength
                 , _Dest_terminal_Id
                 , _Done_time
                 , _Msg_Id
                 , _SMSC_sequence
                 , _Stat
                 , _Submit_time
                );
        }
    }
    public class CMPP_QUERY //: CMPP_Request
    {
        private MessageHeader _Header;
        private string _Time;         // 8 Octet String 时间YYYYMMDD(精确至日)。
        private uint _Query_Type;        // 1 Unsigned Integer 查询类别:
        //   0:总数查询;
        //   1:按业务类型查询。
        private string _Query_Code;        // 10 Octet String 查询码。
        //   当Query_Type为0时,此项无效;当Query_Type为1时,此项填写业务类型Service_Id.。
        private string _Reserve;        // 8 Octet String 保留。
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
        }
        public string Time
        {
            get
            {
                return _Time;
            }
        }
        public uint Query_Type
        {
            get
            {
                return _Query_Type;
            }
        }
        public string Query_Code
        {
            get
            {
                return _Query_Code;
            }
        }
        public string Reserve
        {
            get
            {
                return _Reserve;
            }
        }
        public const int BodyLength = 8 + 1 + 10 + 8;
        public CMPP_QUERY
         (
           DateTime Time
           , uint Query_Type
           , string Query_Code
           , string Reserve
           , uint Sequence_Id
         )
        {
            _Time = Utility.Get_YYYYMMDD_String(Time);
            _Query_Type = Query_Type;
            _Query_Code = Query_Code;
            _Reserve = Reserve;
            _Header = new MessageHeader
                 (
                  (uint)(MessageHeader.Length + BodyLength)
                  , CMPP_Command_Id.CMPP_QUERY
                  , Sequence_Id
                 );
        }
        public byte[] ToBytes()
        {
            int i = 0;
            byte[] bytes = new byte[MessageHeader.Length + BodyLength];
            //header
            byte[] buffer = new byte[MessageHeader.Length];
            buffer = _Header.ToBytes();
            buffer.CopyTo(bytes, 0);
            //Time 8
            i += MessageHeader.Length;
            buffer = new byte[10];
            buffer = Encoding.ASCII.GetBytes(_Time);
            buffer.CopyTo(bytes, i);
            //Query_Type 1
            i += 8;
            bytes[i++] = (byte)_Query_Type;
            //Query_Code 10
            buffer = new byte[10];
            buffer = Encoding.ASCII.GetBytes(_Query_Code);
            buffer.CopyTo(bytes, i);
            //Reserve 8
            i += 10;
            buffer = new byte[8];
            buffer = Encoding.ASCII.GetBytes(_Reserve);
            buffer.CopyTo(bytes, i);
            return bytes;
        }
        public override string ToString()
        {
            return "[\r\n"
              + _Header.ToString() + "\r\n"
              + "\t"
              + string.Format
                 (
                  "MessageBody:"
                  + "{0}Query_Code: {1}"
                  + "{0}Query_Type: {2}"
                  + "{0}Reserve: {3}"
                  + "{0}Time: {4}"
                  , "\r\n\t\t"
                  , _Query_Code
                  , _Query_Type
                  , _Reserve
                  , _Time
                 )
              + "\r\n]";
        }
    }
    public class CMPP_QUERY_RESP
    {
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
        }
        public string Time
        {
            get
            {
                return _Time;
            }
        }
        public uint Query_Type
        {
            get
            {
                return _Query_Type;
            }
        }
        public string Query_Code
        {
            get
            {
                return _Query_Code;
            }
        }
        public uint Mt_TlMsg
        {
            get
            {
                return _MT_TLMsg;
            }
        }
        public uint Mt_Tlusr
        {
            get
            {
                return _MT_Tlusr;
            }
        }
        public uint Mt_Scs
        {
            get
            {
                return _MT_Scs;
            }
        }
        public uint MT_WT
        {
            get
            {
                return _MT_WT;
            }
        }
        public uint MT_FL
        {
            get
            {
                return _MT_FL;
            }
        }
        public uint MO_Scs
        {
            get
            {
                return _MO_Scs;
            }
        }
        public uint MO_WT
        {
            get
            {
                return _MO_WT;
            }
        }
        public uint MO_FL
        {
            get
            {
                return _MO_FL;
            }
        }
        private MessageHeader _Header;
        private string _Time;         // 8 Octet String 时间(精确至日)。
        private uint _Query_Type;        // 1 Unsigned Integer 查询类别:
        //   0:总数查询;
        //   1:按业务类型查询。
        private string _Query_Code;        // 10 Octet String 查询码。
        private uint _MT_TLMsg;         // 4 Unsigned Integer 从SP接收信息总数。
        private uint _MT_Tlusr;         // 4 Unsigned Integer 从SP接收用户总数。
        private uint _MT_Scs;         // 4 Unsigned Integer 成功转发数量。
        private uint _MT_WT;         // 4 Unsigned Integer 待转发数量。
        private uint _MT_FL;         // 4 Unsigned Integer 转发失败数量。
        private uint _MO_Scs;         // 4 Unsigned Integer 向SP成功送达数量。
        private uint _MO_WT;         // 4 Unsigned Integer 向SP待送达数量。
        private uint _MO_FL;         // 4 Unsigned Integer 向SP送达失败数量。
        public const int BodyLength = 8       // Octet String 时间(精确至日)。
                + 1      // Unsigned Integer 查询类别:
            //  0:总数查询;
            //  1:按业务类型查询。
                + 10     // Octet String 查询码。
                + 4      // Unsigned Integer 从SP接收信息总数。
                + 4      // Unsigned Integer 从SP接收用户总数。
                + 4      // Unsigned Integer 成功转发数量。
                + 4      // Unsigned Integer 待转发数量。
                + 4      // Unsigned Integer 转发失败数量。
                + 4      // Unsigned Integer 向SP成功送达数量。
                + 4      // Unsigned Integer 向SP待送达数量。
                + 4;     // Unsigned Integer 向SP送达失败数量。
        public CMPP_QUERY_RESP(byte[] bytes)
        {
            int i = 0;
            //header 12
            byte[] buffer = new byte[MessageHeader.Length];
            Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);
            _Header = new MessageHeader(buffer);
            //Time 8
            i += MessageHeader.Length;
            buffer = new byte[8];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            _Time = Encoding.ASCII.GetString(buffer);
            //Query_Type 1
            i += 8;
            _Query_Type = (uint)bytes[i++];
            //Query_Code 10
            buffer = new byte[10];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            _Query_Code = Encoding.ASCII.GetString(buffer);
            //MT_TLMsg 4
            i += 10;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MT_TLMsg = BitConverter.ToUInt32(buffer, 0);
            //MT_Tlusr 4
            i += 4;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MT_Tlusr = BitConverter.ToUInt32(buffer, 0);
            //MT_Scs 4
            i += 4;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MT_Scs = BitConverter.ToUInt32(buffer, 0);
            //MT_WT 4
            i += 4;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MT_WT = BitConverter.ToUInt32(buffer, 0);
            //MT_FL 4
            i += 4;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MT_FL = BitConverter.ToUInt32(buffer, 0);
            //MO_Scs 4
            i += 4;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MO_Scs = BitConverter.ToUInt32(buffer, 0);
            //MO_WT 4
            i += 4;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MO_WT = BitConverter.ToUInt32(buffer, 0);
            //MO_FL 4
            i += 4;
            buffer = new byte[4];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            Array.Reverse(buffer);
            _MO_FL = BitConverter.ToUInt32(buffer, 0);
        }
        public override string ToString()
        {
            return "[\r\n"
              + _Header.ToString() + "\r\n"
              + "\t"
              + string.Format
                 (
                  "MessageBody:"
                  + "{0}BodyLength: {1}"
                  + "{0}MO_FL: {2}"
                  + "{0}MO_Scs: {3}"
                  + "{0}MO_WT: {4}"
                  + "{0}MT_FL: {5}"
                  + "{0}MT_Scs: {6}"
                  + "{0}MT_TLMsg: {7}"
                  + "{0}MT_Tlusr: {8}"
                  + "{0}MT_WT: {9}"
                  + "{0}Query_Code: {10}"
                  + "{0}Query_Type: {11}"
                  + "{0}Time: {12}"
                  , "\r\n\t\t"
                  , CMPP_QUERY_RESP.BodyLength
                  , _MO_FL
                  , _MO_Scs
                  , _MO_WT
                  , _MT_FL
                  , _MT_Scs
                  , _MT_TLMsg
                  , _MT_Tlusr
                  , _MT_WT
                  , _Query_Code
                  , _Query_Type
                  , _Time
                 )
              + "\r\n]";
        }
    }
    public class CMPP_ACTIVE_TEST
    {
        private MessageHeader _Header;
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
        }
        public CMPP_ACTIVE_TEST(uint Sequence_Id)
        {
            _Header = new MessageHeader
                 (
                  MessageHeader.Length
                  , CMPP_Command_Id.CMPP_ACTIVE_TEST
                  , Sequence_Id
                 );
        }
        public byte[] ToBytes()
        {
            return _Header.ToBytes();
        }
        public override string ToString()
        {
            return _Header.ToString();
        }
    }
    public class CMPP_ACTIVE_TEST_RESP
    {
        private MessageHeader _Header;
        private byte _Reserved;
        public byte Reserved
        {
            get
            {
                return _Reserved;
            }
        }
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
        }
        public CMPP_ACTIVE_TEST_RESP(byte[] bytes)
        {
            int i = 0;
            //header
            byte[] buffer = new byte[MessageHeader.Length];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            _Header = new MessageHeader(buffer);
            //Reserved 1
            i += MessageHeader.Length;
            _Reserved = bytes[i];
        }
        public byte[] ToBytes()
        {
            return _Header.ToBytes();
        }
        public override string ToString()
        {
            return "[\r\n"
              + _Header.ToString() + "\r\n"
              + "]";
        }
    }
}
//CMPP Client
namespace Microshaoft.CMPP
{
    using System;
    using System.Net.Sockets;
    using System.Threading;
    using Microshaoft.CMPP.Messages;
    public class MessageEventArgs : EventArgs
    {
        private byte[] _HeaderData;
        private MessageHeader _Header;
        private byte[] _BodyData;
        public byte[] MessageBodyData
        {
            get
            {
                return _BodyData;
            }
        }
        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
        }
        public byte[] MessageHeaderData
        {
            get
            {
                return _HeaderData;
            }
        }
        public MessageEventArgs(byte[] bytes)
        {
            _HeaderData = new byte[MessageHeader.Length];
            Buffer.BlockCopy(bytes, 0, _HeaderData, 0, MessageHeader.Length);
            _Header = new MessageHeader(_HeaderData);
            _BodyData = new byte[_Header.Total_Length - MessageHeader.Length];
            Buffer.BlockCopy(bytes, MessageHeader.Length, _BodyData, 0, _BodyData.Length);
        }
    }
    public class Client
    {
        private string _Host;
        private int _Port;
        private string _Source_Addr;
        private string _Password;
        private TcpClient tc;
        private bool _IsConnected;
        public bool IsConnected
        {
            get
            {
                return _IsConnected;
            }
        }
        private NetworkStream _NetworkStream;
        private static object _SyncLockObject = new object();
        public delegate void MessageEventHandler(Client Sender, MessageEventArgs e);
        //public delegate void RequestEventHandler(Client Sender, ResponseEventArgs e);
        public event MessageEventHandler ResponseMessageReceive;
        public event MessageEventHandler BeforeRequestMessageSend;
        public event MessageEventHandler AfterRequestMessageSended;
        private Thread _ReadResponseThread;
        private void OnBeforeRequestMessageSend(byte[] data)
        {
            if (BeforeRequestMessageSend != null)
            {
                BeforeRequestMessageSend(this, new MessageEventArgs(data));
            }
        }
        private void OnAfterRequestMessageSended(byte[] data)
        {
            if (AfterRequestMessageSended != null)
            {
                AfterRequestMessageSended(this, new MessageEventArgs(data));
            }
        }
        private void WriteToStreamWithLock(byte[] data, NetworkStream Stream)
        {
            OnBeforeRequestMessageSend(data);
            lock (_SyncLockObject)
            {
                Utility.WriteToStream(data, Stream);
            }
            OnAfterRequestMessageSended(data);
        }
        private byte[] ReadStreamToBytesWithLock(int Length, NetworkStream Stream)
        {
            lock (_SyncLockObject)
            {
                return Utility.ReadStreamToBytes(Length, Stream);
            }
        }
        public void Terminate(uint SequenceId)
        {
            MessageHeader terminate = new MessageHeader
                     (
                      MessageHeader.Length
                      , CMPP_Command_Id.CMPP_TERMINATE
                      , SequenceId
                     );
            Console.WriteLine("Request:\r\n{0}", terminate.ToString());
            WriteToStreamWithLock(terminate.ToBytes(), _NetworkStream);
            StartRun();
        }
        public void ActiveTest(uint SequenceId)
        {
            MessageHeader activeTest = new MessageHeader
                     (
                      MessageHeader.Length
                      , CMPP_Command_Id.CMPP_ACTIVE_TEST
                      , SequenceId
                     );
            //byte[] activeTest = activeTest.ToBytes();
            Console.WriteLine("Request:\r\n{0}", activeTest.ToString());
            WriteToStreamWithLock(activeTest.ToBytes(), _NetworkStream);
            StartRun();
        }
        public bool Connect
            (
             string Host
             , int Port
             , string UserID
             , string Password
             , uint SequenceId
            )
        {
            _Host = Host;
            _Port = Port;
            _Source_Addr = UserID;
            _Password = Password;
            DateTime ts = DateTime.Now;
            CMPP_CONNECT connect = new CMPP_CONNECT
                    (
                     _Source_Addr
                     , _Password
                     , ts
                     , 1
                     , SequenceId
                    );
            Console.WriteLine("Request:\r\n{0}", connect.ToString());
            tc = new TcpClient();
            tc.Connect(_Host, _Port);
            _NetworkStream = tc.GetStream();
            WriteToStreamWithLock(connect.ToBytes(), _NetworkStream);
            Run(ref _IsConnected);
            return _IsConnected;
        }
        public void Query
            (
             DateTime Time
             , uint QueryType
             , string QueryCode
             , string Reserve
             , uint SequenceId
            )
        {
            CMPP_QUERY query = new CMPP_QUERY
                   (
                    Time
                    , QueryType
                    , QueryCode
                    , Reserve
                    , SequenceId
                   );
            Console.WriteLine("Request:\r\n{0}", query.ToString());
            WriteToStreamWithLock(query.ToBytes(), _NetworkStream);
            StartRun();
        }
        public void Submit
            (
             ulong MsgId
             , uint RegisteredDelivery
             , string FeeTerminalId
             , string[] DestTerminalId
             , string MsgContent
             , uint SequenceId
            )
        {
            //这里的字段根据需要设定
            CMPP_SUBMIT submit = new CMPP_SUBMIT(SequenceId);
            submit.Msg_Id = MsgId;               // 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 = RegisteredDelivery;        // 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 = FeeTerminalId;           // 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 = _Source_Addr;             // 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 资费代码(以分为单位)。
            submit.ValId_Time = Utility.Get_MMDDHHMMSS_String(DateTime.Now.AddHours(2))
                 + "032+";             // string _ValId_Time;  // 17 Octet String 存活有效期,格式遵循SMPP3.3协议。
            submit.At_Time = Utility.Get_MMDDHHMMSS_String(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 = DestTerminalId;          //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 = MsgContent;            //"大家好!这是一个短信群发测试!"; // string _Msg_Content; // Msg_length Octet String 信息内容。
            submit.LinkId = "";                // string _LinkID; // 20 Octet String 点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。
            Console.WriteLine("Request:\r\n{0}", submit.ToString());
            WriteToStreamWithLock(submit.ToBytes(), _NetworkStream);
            StartRun();
        }
        bool _b = false;
        private bool _IsStarted = false;
        public void StartRun()
        {
            if (!_IsStarted)
            {
                _IsStarted = true;
                if (_ReadResponseThread == null)
                {
                    _ReadResponseThread = new Thread(new ThreadStart(Run));
                }
                if (_ReadResponseThread.ThreadState == ThreadState.Unstarted)
                {
                    _ReadResponseThread.Start();
                }
            }
        }
        private void Run()
        {
            Run(ref _b);
        }
        private void Run(ref bool BreakFlag)
        {
            while (!BreakFlag)
            {
                if (_NetworkStream.CanRead)
                {
                    if (_NetworkStream.DataAvailable)
                    {
                        byte[] buffer = new byte[MessageHeader.Length]; //Header
                        buffer = ReadStreamToBytesWithLock(MessageHeader.Length, _NetworkStream);
                        MessageHeader header = new MessageHeader(buffer);
                        byte[] bytes = new byte[header.Total_Length];
                        Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);
                        int l = (int)header.Total_Length - MessageHeader.Length;
                        if (l > 0)
                        {
                            buffer = ReadStreamToBytesWithLock(l, _NetworkStream);
                            Buffer.BlockCopy
                               (
                                buffer
                                , 0
                                , bytes
                                , MessageHeader.Length
                                , buffer.Length
                               );
                        }
                        if (header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP)
                        {
                            CMPP_CONNECT_RESP connect_resp = new CMPP_CONNECT_RESP(bytes);
                            _IsConnected = connect_resp.Status == 0;
                        }
                        else if (header.Command_Id == CMPP_Command_Id.CMPP_TERMINATE_RESP)
                        {
                            _b = true;
                        }
                        if (ResponseMessageReceive != null)
                        {
                            ResponseMessageReceive(this, new MessageEventArgs(bytes));
                        }
                    }
                }
                Thread.Sleep(100);
            }
            if (_b)
            {
                _NetworkStream.Close();
                _NetworkStream.Dispose();
                _NetworkStream = null;
            }
        }
    }
}
//测试程序
namespace Test
{
    using System;
    using System.Text;
    using Microshaoft.CMPP;
    using Microshaoft.CMPP.Messages;
    class ConsoleApplication
    {
        static void Main()
        {
            ConsoleApplication a = new ConsoleApplication();
            Client c = new Client();
            c.ResponseMessageReceive += new Client.MessageEventHandler(a.c_ResponseMessageReceive);
            c.AfterRequestMessageSended += new Client.MessageEventHandler(a.c_AfterRequestMessageSended);
            Console.WriteLine("press 'q' to exit this programe!");
            uint i = 0; //Sequence_Id header
            ulong l = 0; //Msg_Id body
            if (c.Connect("localhost", 7891, "901234", "1234", ++i))
            {
                c.Submit
                 (
                   ++l
                   , 1
                   , "1391xxx1138"
                   , new string[] { "13911234567", "13911234567" }
                     , "卧鼠藏虫 身披七彩祥云 脚踏金甲圣衣"
                   , ++i
                 );
                c.Query(DateTime.Parse("2005-1-1"), 1, "001", "", ++i);
                c.Query(DateTime.Parse("2005-1-1"), 1, "001", "", ++i);
                c.ActiveTest(++i);
                c.Submit
                 (
                   ++l
                   , 1
                   , "1391xxx1138"
                   , new string[] { "13911234567" }
                     , "欲穷千里目 粒粒皆辛苦"
                   , ++i
                 );
            }
            string s;
            while ((s = Console.ReadLine()) != "q")
            {
                if (c.IsConnected)
                {
                    if (s.Length > 0)
                    {
                        c.Submit
                         (
                           ++l
                           , 1
                           , "1391xxx1138"
                           , new string[] { "13911234567", "13911234567" }
                           , s
                           , ++i
                         );
                        //Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}, Content: \"{2}\"", i, l, s);
                    }
                    else
                    {
                        Console.WriteLine("you can submit your SMS at here,or press 'q' to exit this programe!");
                    }
                }
            }
            if (c.IsConnected)
            {
                c.Terminate(++i);
            }
            Console.ReadLine();
        }
        private void c_ResponseMessageReceive(Client Sender, MessageEventArgs e)
        {
            MessageHeader header = e.Header;
            //PrintHeader(header);
            byte[] bytes = new byte[header.Total_Length];
            header.ToBytes().CopyTo(bytes, 0);
            e.MessageBodyData.CopyTo(bytes, MessageHeader.Length);
            string s = "";
            if (header.Command_Id == CMPP_Command_Id.CMPP_ACTIVE_TEST_RESP)
            {
                CMPP_ACTIVE_TEST_RESP response = new CMPP_ACTIVE_TEST_RESP(bytes);
                //Console.WriteLine(response.Reserved);
                s = response.ToString();
            }
            else if (header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP)
            {
                CMPP_CONNECT_RESP response = new CMPP_CONNECT_RESP(bytes);
                s = response.ToString();
            }
            else if (header.Command_Id == CMPP_Command_Id.CMPP_QUERY_RESP)
            {
                CMPP_QUERY_RESP response = new CMPP_QUERY_RESP(bytes);
                s = response.ToString();
            }
            else if (header.Command_Id == CMPP_Command_Id.CMPP_SUBMIT_RESP)
            {
                CMPP_SUBMIT_RESP response = new CMPP_SUBMIT_RESP(bytes);
                s = response.ToString();
            }
            else if (header.Command_Id == CMPP_Command_Id.CMPP_TERMINATE_RESP)
            {
                s = String.Format("good bye");
            }
            //上行短信
            else if (header.Command_Id == CMPP_Command_Id.CMPP_DELIVER)
            {
                CMPP_DELIVER response = new CMPP_DELIVER(bytes);
                if (response.Registered_Delivery == 0) //普通短信
                {
                    s = String.Format("收到普通短信: \n{0}", response.ToString());
                }
                else
                //该模拟器不能自动生成状态报告再下发!请自行键入下面短信内容后,发送
                //状态报告短信: 00000001DELIVRD031213505003121350501391xxx11381391xxx11381391xx11380001
                {
                    CMPP_Msg_Content x = new CMPP_Msg_Content(Encoding.ASCII.GetBytes(response.Msg_Content));
                    s = x.ToString();
                }
            }
            Console.WriteLine("Response Received:\r\n" + s + "\n");
        }
        public void PrintHeader(MessageHeader Header)
        {
            Console.WriteLine("Response: Sequence_Id: {0}!", Header.Sequence_Id);
            Console.WriteLine("Total_Length: {0}!", Header.Total_Length);
            Console.WriteLine("Command_Id: {0}!", Header.Command_Id);
        }
        private void c_AfterRequestMessageSended(Client Sender, MessageEventArgs e)
        {
            Console.WriteLine("Sended {0} Request!", e.Header.Command_Id);
            //Console.ReadLine();
        }
    }
}

posted @ 2005-03-20 23:28  于斯人也  阅读(12349)  评论(18编辑  收藏  举报