中国移动CMPP接口

下载参考程序 :http://download.csdn.net/detail/adama119/4189313 

 

短信行业已经很成熟了,到处可以找到资料。本人在这个行业干过几年,做过3套短信平台都在省级单位省用,做的最复杂的自然是SP的应用,曾经在广电集团工作时做的内容确实非常复杂自己都觉得头疼,当然也和水平有限有关。

 

2010年底给江苏某国企做了一套行业应用的短信系统,做短信平台大量工作还是围绕业务开发WEB方面内容。这次网关客户端的是用C#开发的,目标为50条/秒,性能上应该没什么问题,支持普通短信和wappush但是长短信对方没要就没写,需要的朋友可以自行修改开发。以下贴出CMPP2.0源代码给各位需要的朋友做个参考,运行到现在没有发现任何问题。这里只贴出cmpp接口,至于程序就自己做吧,如果需要也可以联系我。

邮箱 spf193@gmail.com

 

//------------------------------------------------------------------------------

//文件Client.cs

//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Collections;


namespace AsiaINFO.SMS.CMPP2
{

    /// <summary>
    /// @Description:CMPP2 短消息移动网关客户端
    /// @Author:Adama SUN
    /// @Mail:spf193@gmail.com

    /// @Copyright (C) 2010 AsiaINFO. All rights reserved.
    /// </summary>
    public class CMPPClient
    {
        public delegate void MsgEventDelegate(string msg);
        /// <summary>
        /// 线程状态通知
        /// </summary>
        /// <param name="sender">线程</param>
        /// <param name="state">线程状态</param>
        public delegate void ThreadStateDelegate(object sender, ThreadState state);

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="queue">CMPP接口 接收数据队列</param>
        /// <param name="cmppSyncEvents">CMPP接口信号:检查是否需要退出线程,CMPP接口新数据到达(通知)</param>
        public CMPPClient(Queue<byte[]> queue, SyncEvents cmppSyncEvents)
        {
            if (queue == null || cmppSyncEvents == null)
                throw new Exception("参数不能为空!");
            _receiveQueue = queue;
            _syncEvents = cmppSyncEvents;
        }

        #region private field

        private Queue<byte[]> _receiveQueue;//接收队列
        private SyncEvents _syncEvents;//信号


      //  private string _Host;           //主机
      //  private int _Port;              //端口
        private string _Source_Addr;   
      //  private string _Password;       //密码
        private bool _IsConnected=false;      //连接状态
        private static object _SyncLockObject = new object();   //锁
        private TcpClient tc;              
        private NetworkStream _NetworkStream;
        private Thread _ReadResponseThread;

        private object _syncIsConnectedObject = new object();

 


        #endregion


        #region public property

        /// <summary>
        /// 连接状态
        /// </summary>
        public bool IsConnected
        {
            get
            {
                lock (_syncIsConnectedObject)
                {
                    return this._IsConnected;
                }
            }
            set
            {
                lock (_syncIsConnectedObject)
                {
                    this._IsConnected = value;
                }
            }
        }

        #endregion

 

        #region public event

        /// <summary>
        /// 信息事件
        /// </summary>
        public event MsgEventDelegate MsgEvent;
        /// <summary>
        /// 错误事件
        /// </summary>
        public event MsgEventDelegate ErrorEvent;

        /// <summary>
        /// 退出事件
        /// </summary>
        public event ThreadStateDelegate ThreadStateEvent;

 

        #endregion

 


        #region public methos


        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="Host">主机地址</param>
        /// <param name="Port">端口</param>
        /// <param name="UserID">用户名</param>
        /// <param name="Password">密码</param>
        /// <param name="SequenceId">序列好</param>
        /// <returns></returns>
        public void Connect(string Host, int Port, string UserID, string Password, uint SequenceId)
        {
          //  this._Host = Host;
          //  this._Port = Port;
            this._Source_Addr = UserID;
          //  this._Password = Password;
          //  DateTime ts = DateTime.Now;
            //CMPP_CONNECT connect = new CMPP_CONNECT(this._Source_Addr, this._Password, ts, 1, SequenceId);
            CMPP_CONNECT connect = new CMPP_CONNECT(this._Source_Addr, Password, DateTime.Now, 0x20, SequenceId);

            tc = new TcpClient();
            tc.Connect(Host, Port);

            if (this._NetworkStream != null)
            {
                try
                {
                    this._NetworkStream.Close();
                    this._NetworkStream = null;
                }
                catch (Exception) { }
            }

            this._NetworkStream = tc.GetStream();
            this.WriteToStreamWithLock(connect.ToBytes(), this._NetworkStream);
            this.StartRun();
        }


        /// <summary>
        /// 中断
        /// </summary>
        /// <param name="SequenceId"></param>
        public void Terminate(uint SequenceId)
        {
            MessageHeader terminate = new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_TERMINATE, SequenceId);
           // OnMsg(terminate.ToString());
            this.WriteToStreamWithLock(terminate.ToBytes(), this._NetworkStream);
        }

        /// <summary>
        /// CMPP_ACTIVE_TEST
        /// </summary>
        /// <param name="SequenceId"></param>
        public void ActiveTest(uint SequenceId)
        {
            MessageHeader activeTest = new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_ACTIVE_TEST, SequenceId);
            //byte[] activeTest = activeTest.ToBytes();
            //OnShowMsg(activeTest.ToString());
          //  Console.WriteLine("Request:/r/n{0}", activeTest.ToString());
            this.WriteToStreamWithLock(activeTest.ToBytes(), this._NetworkStream);
         //   this.StartRun();
        }

        /// <summary>
        /// CMPP_ACTIVE_TEST_RESP
        /// </summary>
        /// <param name="SequenceId"></param>
        public void ActiveResp(uint SequenceId)
        {
            CMPP_ACTIVE_TEST_RESP response = new CMPP_ACTIVE_TEST_RESP(SequenceId);
            this.WriteToStreamWithLock(response.ToBytes(), this._NetworkStream);
        }

        /// <summary>
        /// 发送CMPP_DELIVER_RESP
        /// </summary>
        /// <param name="Msg_Id"></param>
        /// <param name="Result"></param>
        public void DeliverResp(ulong Msg_Id, uint Result,uint SequenceId)
        {
            CMPP_DELIVER_RESP deliverResp = new CMPP_DELIVER_RESP(Msg_Id, Result, SequenceId);
            this.WriteToStreamWithLock(deliverResp.ToBytes(), this._NetworkStream);
        }

        /// <summary>
        /// 查询发送短信状态
        /// </summary>
        /// <param name="Time"></param>
        /// <param name="QueryType"></param>
        /// <param name="QueryCode"></param>
        /// <param name="Reserve"></param>
        /// <param name="SequenceId"></param>
        public void Query(DateTime Time, uint QueryType, string QueryCode, string Reserve, uint SequenceId)
        {
            CMPP_QUERY query = new CMPP_QUERY(Time, QueryType, QueryCode, Reserve, SequenceId);
            this.WriteToStreamWithLock(query.ToBytes(), this._NetworkStream);
        }

 

 

        /// <summary>
        /// 发送短信
        /// </summary>
        /// <param name="MsgId">信息标识</param>
        /// <param name="mobile">接收短信的号码与计费号码</param>
        /// <param name="MsgContent">短信内容</param>
        /// <param name="SequenceId">序列号</param>
        /// <param name="Service_Id">业务代码</param>
        /// <param name="FeeType">资费类别</param>
        /// <param name="FeeCode">资费代码(以分为单位)</param>
        /// <param name="Src_Id">源号码</param>
        /// <param name="LinkId"></param>
        public void Submit(ulong MsgId, string mobile, string MsgContent, uint SequenceId, string Service_Id, string FeeType, string FeeCode, string Src_Id, string WapURL)
        {
            if (mobile != null && mobile.Length == 11)
                mobile = "86" + mobile;
            Submit(MsgId, mobile, new string[] { mobile }, MsgContent, SequenceId, Service_Id, FeeType, FeeCode, Src_Id, WapURL);
        }


        /// <summary>
        /// 发送短信
        /// </summary>
        /// <param name="MsgId">信息标识</param>
        /// <param name="FeeTerminalId">被计费用户的号码</param>
        /// <param name="DestTerminalId">接收短信的MSISDN号码_多个号码</param>
        /// <param name="MsgContent">短信内容</param>
        /// <param name="SequenceId">序列号</param>
        /// <param name="Service_Id">业务代码</param>
        /// <param name="FeeType">资费类别</param>
        /// <param name="FeeCode">资费代码(以分为单位)</param>
        /// <param name="Src_Id">源号码</param>
        /// <param name="LinkId"></param>
        public void Submit(ulong MsgId, string FeeTerminalId, string[] DestTerminalId, string MsgContent, uint SequenceId, string Service_Id, string FeeType, string FeeCode, string Src_Id, string WapURL)
        {
            Submit(MsgId, 1, 0, FeeTerminalId, DestTerminalId, MsgContent, SequenceId, Service_Id, FeeType, FeeCode, Src_Id, WapURL);
        }


        /// <summary>
        /// 发送短信
        /// </summary>
        /// <param name="MsgId">信息标识</param>
        /// <param name="RegisteredDelivery">是否要返回状态确认报告</param>
        /// <param name="Fee_UserType">计费用户类型</param>
        /// <param name="FeeTerminalId">被计费用户的号码</param>
        /// <param name="DestTerminalId">接收短信的MSISDN号码_多个号码</param>
        /// <param name="MsgContent">短信内容</param>
        /// <param name="SequenceId">序列号</param>
        /// <param name="Service_Id">业务代码</param>
        /// <param name="FeeType">资费类别</param>
        /// <param name="FeeCode">资费代码(以分为单位)</param>
        /// <param name="Src_Id">源号码</param>
        /// <param name="LinkID"></param>

        public void Submit(ulong MsgId, uint RegisteredDelivery, uint Fee_UserType, string FeeTerminalId, string[] DestTerminalId, string MsgContent, uint SequenceId, string Service_Id, string FeeType, string FeeCode, string Src_Id, string WapURL)
        {
            //这里的字段根据需要设定
            CMPP_SUBMIT submit = new CMPP_SUBMIT(SequenceId);
            submit.WapURL = WapURL;
            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 = 1;                //      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 = Service_Id;             //      string _Service_Id;     // 10 Octet String 业务标识,是数字、字母和符号的组合。
            submit.Fee_UserType = Fee_UserType;               //      uint _Fee_UserType;     // 1 Unsigned Integer 计费用户类型字段:
            //      //   0:对目的终端MSISDN计费;
            //      //   1:对源终端MSISDN计费;
            //      //   2:对SP计费;
            //      //   3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。
            submit.Fee_terminal_Id = "";            //      string _Fee_terminal_Id;   // 21 Octet String 被计费用户的号码,当Fee_UserType为3时该值有效,当Fee_UserType为0、1、2时该值无意义。

            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 = this._Source_Addr;             //      string _Msg_src;     // 6 Octet String 信息内容来源(SP_Id)。
            submit.FeeType = FeeType;                //      string _FeeType;     // 2 Octet String 资费类别:
            //      //   01:对"计费用户号码"免费;
            //      //   02:对"计费用户号码"按条计信息费;
            //      //   03:对"计费用户号码"按包月收取信息费。
            submit.FeeCode = FeeCode;                //      string _FeeCode;     // 6 Octet String 资费代码(以分为单位)。

            submit.ValId_Time = "";// Util.Get_MMDDHHMMSS_String(DateTime.Now.AddHours(2)) + "032+"; //      string _ValId_Time;     // 17 Octet String 存活有效期,格式遵循SMPP3.3协议。
            submit.At_Time = "";// Util.Get_MMDDHHMMSS_String(DateTime.Now) + "032+";     //      string _At_Time;     // 17 Octet String 定时发送时间,格式遵循SMPP3.3协议。
            //spnum
            submit.Src_Id = 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.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.Reserve = "";                 //      string _LinkID;      // 20 Octet String 点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。
            this.WriteToStreamWithLock(submit.ToBytes(), this._NetworkStream);
        }


        public void StartRun()
        {

            try
            {
                if (this._ReadResponseThread == null)
                {
                    this._ReadResponseThread = new Thread(new ThreadStart(this.Run));
                }

                if (this._ReadResponseThread.ThreadState == ThreadState.Unstarted)
                {
                    OnThreadState(ThreadState.Running);
                    this._ReadResponseThread.Start();
                }
                else if (this._ReadResponseThread.ThreadState == ThreadState.Suspended)
                {
                    OnThreadState(ThreadState.Running);
                    this._ReadResponseThread.Resume();
                }
                else if (this._ReadResponseThread.ThreadState == ThreadState.Stopped)
                {
                    OnThreadState(ThreadState.Running);
                    this._ReadResponseThread = null;
                    this._ReadResponseThread = new Thread(new ThreadStart(this.Run));
                    this._ReadResponseThread.Start();
                }

            }
            catch (Exception ex) {
                OnError("CMPPClient启动错误:" + ex.Message);
            }
        }

 

        /// <summary>
        /// 暂停线程
        /// </summary>
        public void Suspend()
        {
            try
            {
                if (this._ReadResponseThread != null && _ReadResponseThread.ThreadState != ThreadState.Stopped && _ReadResponseThread.ThreadState != ThreadState.Suspended)
                {
                    OnThreadState(ThreadState.Suspended);
                    this._ReadResponseThread.Suspend();
                  
                }
            }
            catch (Exception) { }
        }


        /// <summary>
        /// 停止接收数据
        /// </summary>
        public void StopReceive()
        {
            _syncEvents.ExitThreadEvent.Set();
        }

        /// <summary>
        /// 退出
        /// </summary>
        public void Exit()
        {
            try
            {
                StopReceive();
                this._NetworkStream.Close();
                this._NetworkStream = null;
            }
            catch (Exception) { }
        }


        /// <summary>
        /// 是否已经停止
        /// </summary>
        /// <returns></returns>
        public bool IsStop()
        {
            if (_ReadResponseThread == null || _ReadResponseThread.ThreadState == ThreadState.Stopped || _ReadResponseThread.ThreadState == ThreadState.Aborted || _ReadResponseThread.ThreadState == ThreadState.AbortRequested)
                return true;
            return false;
        }

        /// <summary>
        /// 立刻停止
        /// </summary>
        /// <returns></returns>
        public void StopImmediately()
        {
            try
            {
                if (_ReadResponseThread != null)
                    _ReadResponseThread.Abort();
            }
            catch (ThreadAbortException) { }
            catch (Exception) { }
            finally
            {
                OnThreadState(ThreadState.Stopped);
            }

        }


        #endregion


        #region private method

        / <summary>
        / 发送数据通知
        / </summary>
        / <param name="data"></param>
        //private void OnCMPPSend(byte[] data)
        //{
        //    if (CMPPSendEvent != null)
        //    {
        //        CMPPSendEvent(this, new MessageEventArgs(data));
        //    }
        //}

        / <summary>
        / 接受数据通知
        / </summary>
        / <param name="data"></param>
        //private void OnCMPPReceive(byte[] data)
        //{
        //    if (CMPPReceiveEvent != null)
        //    {
        //        CMPPReceiveEvent(this, new MessageEventArgs(data));
        //    }
        //}

        /// <summary>
        /// 信息通知
        /// </summary>
        private void OnMsg(string msg)
        {
            if (MsgEvent != null)
            {
                MsgEvent(msg);
            }
        }

        /// <summary>
        /// 错误通知
        /// </summary>
        /// <param name="type"></param>
        /// <param name="err"></param>
        private void OnError(string err)
        {
            if (ErrorEvent != null)
            {
                ErrorEvent(err);
            }
        }
        /// <summary>
        /// 退出
        /// </summary>
        protected void OnThreadState(ThreadState state)
        {
            if (ThreadStateEvent != null)
            {
                ThreadStateEvent(this, state);
            }
        }

 


        /// <summary>
        /// 写入流
        /// </summary>
        /// <param name="data"></param>
        /// <param name="Stream"></param>
        private void WriteToStreamWithLock(byte[] data, NetworkStream Stream)
        {
           // this.OnCMPPSend(data);
            try
            {
                lock (_SyncLockObject)
                {
                    Util.WriteToStream(data, Stream);
                }
            }
            catch (Exception ex)
            {
                IsConnected = false;
                OnError(ex.Message);
            }
        }

        /// <summary>
        /// 读取流
        /// </summary>
        /// <param name="Length"></param>
        /// <param name="Stream"></param>
        /// <returns></returns>
        private byte[] ReadFromStreamWithLock(int Length, NetworkStream Stream)
        {
            try
            {
                lock (_SyncLockObject)
                {
                    return Util.ReadFromStream(Length, Stream);
                }
            }
            catch (Exception ex)
            {
                IsConnected = false;
                OnError(ex.Message);
            }
            return null;
        }


        /// <summary>
        ///
        /// </summary>
        /// <param name="BreakFlag"></param>
        private void Run()
        {
            try
            {
                while (!_syncEvents.ExitThreadEvent.WaitOne(2, false))
                {
                    if (this._NetworkStream.CanRead)
                    {
                        if (this._NetworkStream.DataAvailable)
                        {
                            byte[] buffer = new byte[MessageHeader.Length]; //Header
                            buffer = this.ReadFromStreamWithLock(MessageHeader.Length, this._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 = this.ReadFromStreamWithLock(l, this._NetworkStream);
                                Buffer.BlockCopy(buffer, 0, bytes, MessageHeader.Length, buffer.Length);
                            }
                            lock (((ICollection)_receiveQueue).SyncRoot)
                            {
                                _receiveQueue.Enqueue(bytes);
                            }
                            _syncEvents.NewItemEvent.Set();

                        }
                    }
                }
            }
            catch (Exception ex)
            {
                IsConnected = false;
                OnError("CMPPClient接收错误:"+ex.Message);
            }
            OnThreadState(ThreadState.Stopped);
           
        }
        #endregion

    }
}

 

 

 

 

 

 

 

 

 

 

 

 

//------------------------------------------------------------------------------

文件 CMPPMessages.cs

//------------------------------------------------------------------------------

 

using System;
using System.Text;
using System.Security.Cryptography;

namespace AsiaINFO.SMS.CMPP2
{
    //CMPP 消息定义
    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路由请求应答
    }

    /// <summary>
    /// 消息头
    /// </summary>
    public class MessageHeader
    {
        public const int Length = 4 + 4 + 4;

        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 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
         ) //发送前
        {
            this._Total_Length = Total_Length;
            this._Command_Id = Command_Id;
            this._Sequence_Id = Sequence_Id;
        }

        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 override string ToString()
        {
            return string.Format("MessageHeader: tCommand_Id={0}    tSequence_Id={1}    tTotal_Length={2}"
              , this._Command_Id
              , this._Sequence_Id
              , this._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 this._Header;
            }
        }

        public byte[] AuthenticatorSource
        {
            get
            {
                return this._AuthenticatorSource;
            }
        }

        public CMPP_CONNECT
         (
          string Source_Addr
          , string Password
          , DateTime Timestamp
          , uint Version
          , uint Sequence_Id
         )
        {
            this._Header = new MessageHeader(MessageHeader.Length + BodyLength, CMPP_Command_Id.CMPP_CONNECT, Sequence_Id);

            this._Source_Addr = Source_Addr;
            this._Password = Password;

            string s = Util.Get_MMDDHHMMSS_String(Timestamp);
            this._Timestamp = UInt32.Parse(s);

            //byte[] buffer = new byte[6 + 9 + this._Password.Length + 10];
            //Encoding.ASCII.GetBytes(this._Source_Addr).CopyTo(buffer, 0);
            //Encoding.ASCII.GetBytes(this._Password).CopyTo(buffer, 6 + 9);
            //Encoding.ASCII.GetBytes(s).CopyTo(buffer, 6 + 9 + this._Password.Length);
            //this._AuthenticatorSource = new MD5CryptoServiceProvider().ComputeHash(buffer, 0, buffer.Length);

            byte[] clientid = System.Text.Encoding.ASCII.GetBytes(Source_Addr);
            byte[] password = System.Text.Encoding.ASCII.GetBytes(Password);
            byte[] timestamp = System.Text.Encoding.ASCII.GetBytes(s);
            byte[] data = new byte[clientid.Length + 9 + password.Length + timestamp.Length];
            Array.Copy(clientid, data, clientid.Length);
            Array.Copy(password, 0, data, clientid.Length + 9, password.Length);
            Array.Copy(timestamp, 0, data, clientid.Length + 9 + password.Length, timestamp.Length);
            System.Security.Cryptography.MD5 MD5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            _AuthenticatorSource = MD5.ComputeHash(data);


            this._Version = Version;
        }

        public byte[] ToBytes()
        {
            int i = 0;
            byte[] bytes = new byte[MessageHeader.Length + BodyLength];

            //header 12
            byte[] buffer = this._Header.ToBytes();
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

            //Source_Addr 6
            i += MessageHeader.Length;
            buffer = Encoding.ASCII.GetBytes(this._Source_Addr);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

            //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 override string ToString()
        {
            return string.Format("Header={0}    AuthenticatorSource={1}    Password={2}    Source_Addr={3}    Timestamp={4}    Version={5}"
                , this._Header.ToString()
                , this._AuthenticatorSource
                , this._Password
                , this._Source_Addr
                , this._Timestamp
                , this._Version);
        }
    }

    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 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;
            this._Status = bytes[i];

            //AuthenticatorISMG 16
            i += 1;
            this._AuthenticatorISMG = new byte[16];
            Buffer.BlockCopy(bytes, MessageHeader.Length + 1, this._AuthenticatorISMG, 0, this._AuthenticatorISMG.Length);

            //version
            i += 16;
            this._Version = bytes[i];

        }

        public override string ToString()
        {

            return string.Format("Header={0}    AuthenticatorISMG={1}    BodyLength={2}    Status={3}    Version={4}"
                , this._Header.ToString()
                , this._AuthenticatorISMG
                , CMPP_CONNECT_RESP.BodyLength
                , this._Status
                , this._Version);

        }


    }

    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
                 + 21
                 + 1
                 + 1
                 + 1
                 + 6
                 + 2
                 + 6
                 + 17
                 + 17
                 + 21
                 + 1
            //+ 21*DestUsr_tl
                 + 1
            //+ Msg_length
                 + 8;

        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; // 21 Octet String 被计费用户的号码,当Fee_UserType为3时该值有效,当Fee_UserType为0、1、2时该值无意义。
        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 _Msg_Length;   // 1 Unsigned Integer 信息长度(Msg_Fmt值为0时:<160个字节;其它<=140个字节),取值大于或等于0。
        private string _Msg_Content;  // Msg_length Octet String 信息内容。
        private string _Reserve;    // 8 Octet String 保留


        private string _WapURL = ""; //WAPPUSH
        public string WapURL
        {
            get { return _WapURL; }
            set { _WapURL = value; }
        }


        public MessageHeader Header
        {
            get
            {
                return _Header;
            }
            set
            {
                _Header = value;
            }
        }
        private MessageHeader _Header;

        private uint _Sequence_Id;

        public CMPP_SUBMIT(uint Sequence_Id)
        {
            this._Sequence_Id = Sequence_Id;
        }


        private byte[] _Msg_Content_Bytes;
        private void SetHeader()
        {
            if (string.IsNullOrEmpty(_WapURL))
            {
                //byte[] buf;
                switch (this._Msg_Fmt)
                {
                    case 8:
                        _Msg_Content_Bytes = Encoding.BigEndianUnicode.GetBytes(this._Msg_Content);
                        break;
                    case 15: //gb2312
                        _Msg_Content_Bytes = Encoding.GetEncoding("gb2312").GetBytes(this._Msg_Content);
                        break;
                    case 0: //ascii
                    case 3: //短信写卡操作
                    case 4: //二进制信息
                    default:
                        _Msg_Content_Bytes = Encoding.ASCII.GetBytes(this._Msg_Content);
                        break;
                }
            }
            else
            {

                _Msg_Content_Bytes = WapPush.GetInstance().toBytes(this._Msg_Content, this._WapURL);
                this._Msg_Fmt = 0x04;
                this.TP_pId = 1;
                this.TP_udhi = 1;
            }


            this._Msg_Length = (uint)_Msg_Content_Bytes.Length;
            this._BodyLength = (int)(FixedBodyLength + 21 * this._Dest_terminal_Id.Length + this._Msg_Length);
            this._Header = new MessageHeader((uint)(MessageHeader.Length + this._BodyLength), CMPP_Command_Id.CMPP_SUBMIT, this._Sequence_Id);
        }

        public byte[] ToBytes()
        {
            //Msg_Length Msg_Content

            int i = 0;
            byte[] bytes = new byte[MessageHeader.Length + this._BodyLength];
            byte[] buffer = this._Header.ToBytes();
            Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);
            i += MessageHeader.Length;

            //Msg_Id //8
            buffer = new byte[8];
            buffer = BitConverter.GetBytes(this._Msg_Id);
            Array.Reverse(buffer);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10

            //_Pk_total
            i += 8;
            bytes[i++] = (byte)this._Pk_total;
            bytes[i++] = (byte)this._Pk_number;
            bytes[i++] = (byte)this._Registered_Delivery;
            bytes[i++] = (byte)this._Msg_level;

            //Service_Id
            buffer = Encoding.ASCII.GetBytes(this._Service_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10

            //Fee_UserType
            i += 10;
            bytes[i++] = (byte)this._Fee_UserType;

            //Fee_terminal_Id
            buffer = Encoding.ASCII.GetBytes(this._Fee_terminal_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //21

            //Fee_terminal_type
            i += 21;
            bytes[i++] = (byte)this._TP_pId;
            bytes[i++] = (byte)this._TP_udhi;
            bytes[i++] = (byte)this._Msg_Fmt;

            //Msg_src
            buffer = Encoding.ASCII.GetBytes(this._Msg_src);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6

            //FeeType
            i += 6;
            buffer = Encoding.ASCII.GetBytes(this._FeeType);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //2

            //FeeCode
            i += 2;
            buffer = Encoding.ASCII.GetBytes(this._FeeCode);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 

            //ValId_Time
            i += 6;
            buffer = Encoding.ASCII.GetBytes(this._ValId_Time);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //17

            //At_Time
            i += 17;
            buffer = Encoding.ASCII.GetBytes(this._At_Time);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //17

            //Src_Id
            i += 17;
            buffer = Encoding.ASCII.GetBytes(this._Src_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //21

            //DestUsr_tl
            i += 21;
            this._DestUsr_tl = (uint)this._Dest_terminal_Id.Length;
            bytes[i++] = (byte)this._DestUsr_tl;

            //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 += 21;
            }

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

            //Msg_Content
            //buffer = Encoding.
            Buffer.BlockCopy(this._Msg_Content_Bytes, 0, bytes, i, this._Msg_Content_Bytes.Length);

            //Reserve 8
            i += (int)this._Msg_Length;
            buffer = Encoding.ASCII.GetBytes(this._Reserve);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);
            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 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;
                if (this._Msg_Content != null)
                {
                    this.SetHeader();
                }
            }
        }

        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 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;
                this.SetHeader();
            }
        }

        public string Reserve
        {
            get
            {
                return this._Reserve;
            }
            set
            {
                this._Reserve = value;
            }
        }
        public override string ToString()
        {
            return "[/r/n"
               + this._Header.ToString() + "/r/n"
               + string.Format
               (
                "/tMessageBody:"
                + "/r/n/t/tAt_Time: {0}"
                + "/r/n/t/tBodyLength: {1}"
                + "/r/n/t/tDest_terminal_Id: {2}"
                + "/r/n/t/tDestUsr_tl: {3}"
                + "/r/n/t/tFee_terminal_Id: {4}"
                + "/r/n/t/tFee_UserType: {5}"
                + "/r/n/t/tFeeCode: {6}"
                + "/r/n/t/tFeeType: {7}"
                + "/r/n/t/tReserve: {8}"
                + "/r/n/t/tMsg_Content: {9}"
                + "/r/n/t/tMsg_Fmt: {10}"
                + "/r/n/t/tMsg_Id: {11}"
                + "/r/n/t/tMsg_Length: {12}"
                + "/r/n/t/tMsg_level: {13}"
                + "/r/n/t/tMsg_src: {14}"
                + "/r/n/t/tPk_number: {15}"
                + "/r/n/t/tPk_total: {16}"
                + "/r/n/t/tRegistered_Delivery: {17}"
                + "/r/n/t/tSequence_Id: {18}"
                + "/r/n/t/tService_Id: {19}"
                + "/r/n/t/tSrc_Id: {20}"
                + "/r/n/t/tTP_pId: {21}"
                + "/r/n/t/tTP_udhi: {22}"
                + "/r/n/t/tValId_Time: {23}"
                , this._At_Time
                , this._BodyLength
                , String.Join(",", this._Dest_terminal_Id)
                , this._DestUsr_tl
                , this._Fee_terminal_Id
                , this._Fee_UserType
                , this._FeeCode
                , this._FeeType
                , this._Reserve
                , this._Msg_Content
                , this._Msg_Fmt
                , this._Msg_Id
                , this._Msg_Length
                , this._Msg_level
                , this._Msg_src
                , this._Pk_number
                , this._Pk_total
                , this._Registered_Delivery
                , this._Sequence_Id
                , this._Service_Id
                , this._Src_Id
                , this._TP_pId
                , this._TP_udhi
                , this._ValId_Time
               )
             + "/r/n]";
        }

    }

    public class CMPP_SUBMIT_RESP //: CMPP_Response
    {
        private MessageHeader _Header;
        //  private ulong _Msg_Id;
        private string _Msg_Id;
        private uint _Result;

        public const int BodyLength = 8 + 1;

        public string 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);

            this._Msg_Id = System.BitConverter.ToString(buffer);
            //string test = System.BitConverter.ToString(buffer);
            //System.Console.WriteLine("CMPP_SUBMIT_RESP Msg_Id=" + test);

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

            //Result
            i += 8;
            this._Result = (uint)bytes[i++];

            //buffer = new byte[1];
            //Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            //Array.Reverse(buffer);
            //this._Result = BitConverter.ToUInt32(buffer, 0);
        }
        public override string ToString()
        {
            return "[/r/n"
             + this._Header.ToString() + "/r/n"
             + string.Format
              (
               "/tMessageBody:"
               + "/r/n/t/tMsg_Id: {0}"
               + "/r/n/t/tResult: {1}"

               , this._Msg_Id
               , this._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 Registered_Delivery
        {
            get
            {
                return _Registered_Delivery;
            }
        }

        public uint Msg_Length
        {
            get
            {
                return _Msg_Length;
            }
        }

        public string Msg_Content
        {
            get
            {
                return _Msg_Content;
            }
        }

        public string Reserved
        {
            get
            {
                return _Reserved;
            }
        }

        /// <summary>
        /// 状态报告
        /// </summary>
        public byte[] Report
        {
            get { return _Report; }

        }


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

        private byte[] _Report;

 

        private 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流程不使用该字段。
        private int _BodyLength;

        public int BodyLength
        {
            get
            {
                return this._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);

            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();
            if(s.IndexOf('/0')>0)
                s = s.Substring(0, s.IndexOf('/0'));
            this._Dest_Id = s;

            //Service_Id 10

            i += 21;
            buffer = new byte[10];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            s = Encoding.ASCII.GetString(buffer).Trim();
            if(s.IndexOf('/0')>0)
                s = s.Substring(0, s.IndexOf('/0'));
            this._Service_Id = s;

            //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 21
            buffer = new byte[21];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            s = Encoding.ASCII.GetString(buffer).Trim();
            if(s.IndexOf('/0')>0)
                s = s.Substring(0, s.IndexOf('/0'));
            if (s != null && s.Length > 11 && s.Substring(0, 2) == "86")
                s = s.Substring(2, s.Length - 2);
            this._Src_terminal_Id = s;

            //Src_terminal_type 1
            i += 21;
            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);

            if (this._Registered_Delivery == 1)
            {   ///状态报告 保存至Report
                this._Msg_Content = "";
                this._Report = new byte[_Msg_Length];
                Buffer.BlockCopy(buffer, 0, _Report, 0, _Report.Length);
            }
            else
            {
                ///短信 保存至Msg_Content
                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;
                }
            }

            //Reserved 8
            i += (int)this._Msg_Length;
            buffer = new byte[8];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            s = Encoding.ASCII.GetString(buffer).Trim();
            if(s.IndexOf('/0')>0)
                s = s.Substring(0, s.IndexOf('/0'));
            this._Reserved = s;

        }

        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 21
            buffer = new byte[21];
            buffer = Encoding.ASCII.GetBytes(this._Src_terminal_Id);
            Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

            //Src_terminal_type 1
            i += 21;
            bytes[i++] = (byte)this._Registered_Delivery;
            bytes[i++] = (byte)this._Msg_Length;

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

            //Reserved
            i += (int)this._Msg_Length;

            return bytes;
        }
        public override string ToString()
        {
            return "[/r/n"
             + this._Header.ToString() + "/r/n"
             + string.Format
              (
               "/tMessageBody:"
               + "/r/n/t/tBodyLength: {0}"
               + "/r/n/t/tDest_Id: {1}"
               + "/r/n/t/tReserved: {2}"
               + "/r/n/t/tMsg_Content: {3}"
               + "/r/n/t/tMsg_Fmt: {4}"
               + "/r/n/t/tMsg_Id: {5}"
               + "/r/n/t/tMsg_Length: {6}"
               + "/r/n/t/tRegistered_Delivery: {7}"
               + "/r/n/t/tService_Id: {8}"
               + "/r/n/t/tSrc_terminal_Id: {9}"
               + "/r/n/t/tTP_pid: {10}"
               + "/r/n/t/tTP_udhi: {11}"
               , this._BodyLength
               , this._Dest_Id
               , this._Reserved
               , this._Msg_Content
               , this._Msg_Fmt
               , this._Msg_Id
               , this._Msg_Length
               , this._Registered_Delivery
               , this._Service_Id
               , this._Src_terminal_Id
               , this._TP_pid
               , this._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 + 1;
        private uint _Sequence_Id;
        public CMPP_DELIVER_RESP(ulong Msg_Id, uint Result, uint Sequence_Id)
        {
            this._Msg_Id = Msg_Id;
            this._Result = Result;
            this._Sequence_Id = Sequence_Id;
        }

        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, _Sequence_Id);
            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 1
            i += 8;
            bytes[i] = (byte)this._Result;
            //buffer = BitConverter.GetBytes(this._Result);
            //Array.Reverse(buffer);
            //buffer.CopyTo(bytes, i);
            return bytes;

        }
        public override string ToString()
        {
            return this._Header.ToString() + "/r/n"
             + string.Format
              (
               "[/r/nMessageBody:"
               + "/r/n/tMsg_Id: {0}"
               + "/r/n/tResult: {1}"
               + "/r/n]"
               , this._Msg_Id
               , this._Result
              );
        }

    }

    public class CMPP_Msg_Content //状态报告
    {
        public const int BodyLength = 8 + 7 + 10 + 10 + 21 + 4;
        private string _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)
            if (bytes.Length >=60)
            {
                int i = 0;
                //_Msg_Id 8
                byte[] buffer = new byte[8];
                Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
                this._Msg_Id = System.BitConverter.ToString(buffer);
                //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 21
                i += 10;
                buffer = new byte[bytes.Length-i-4];
                Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
                //this._Dest_terminal_Id = Encoding.ASCII.GetString(buffer);

                string s = Encoding.ASCII.GetString(buffer).Trim();
                if (s.IndexOf('/0') > 0)
                    s = s.Substring(0, s.IndexOf('/0'));
                if (s != null && s.Length > 11 && s.Substring(0, 2) == "86")
                    s = s.Substring(2, s.Length - 2);
                this._Dest_terminal_Id = s;


                //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 += 21;
                i += buffer.Length;
                buffer = new byte[4];
                Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
                Array.Reverse(buffer);
                this._SMSC_sequence = BitConverter.ToUInt32(buffer, 0);
            }
        }

        public string Msg_Id
        {
            get
            {
                return this._Msg_Id;
            }
        }

        public string Stat
        {
            get
            {
                return this._Stat;
            }
        }

        public string Submit_time
        {
            get
            {
                return this._Submit_time;
            }
        }

        public string Done_time
        {
            get
            {
                return this._Done_time;
            }
        }

        public string Dest_terminal_Id
        {
            get
            {
                return this._Dest_terminal_Id;
            }
        }

        public uint SMSC_sequence
        {
            get
            {
                return this._SMSC_sequence;
            }
        }

        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
               , this._Dest_terminal_Id
               , this._Done_time
               , this._Msg_Id
               , this._SMSC_sequence
               , this._Stat
               , this._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 this._Header;
            }
        }

        public string Time
        {
            get
            {
                return this._Time;
            }
        }

        public uint Query_Type
        {
            get
            {
                return this._Query_Type;
            }
        }

        public string Query_Code
        {
            get
            {
                return this._Query_Code;
            }
        }

        public string Reserve
        {
            get
            {
                return this._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
         )
        {
            this._Time = Util.Get_YYYYMMDD_String(Time);
            this._Query_Type = Query_Type;
            this._Query_Code = Query_Code;
            this._Reserve = Reserve;
            this._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 = this._Header.ToBytes();
            buffer.CopyTo(bytes, 0);

            //Time 8
            i += MessageHeader.Length;
            buffer = new byte[10];
            buffer = Encoding.ASCII.GetBytes(this._Time);
            buffer.CopyTo(bytes, i);

            //Query_Type 1
            i += 8;
            bytes[i++] = (byte)this._Query_Type;

            //Query_Code 10
            buffer = new byte[10];
            buffer = Encoding.ASCII.GetBytes(this._Query_Code);
            buffer.CopyTo(bytes, i);

            //Reserve 8
            i += 10;
            buffer = new byte[8];
            buffer = Encoding.ASCII.GetBytes(this._Reserve);
            buffer.CopyTo(bytes, i);

            return bytes;
        }
        public override string ToString()
        {
            return "[/r/n"
             + this._Header.ToString() + "/r/n"
             + string.Format
              (
               "/tMessageBody:"
               + "/r/n/t/tQuery_Code: {0}"
               + "/r/n/t/tQuery_Type: {1}"
               + "/r/n/t/tReserve: {2}"
               + "/r/n/t/tTime: {3}"
               + "/r/n]"
               , this._Query_Code
               , this._Query_Type
               , this._Reserve
               , this._Time
              )
             + "/r/n]";
        }
    }

    public class CMPP_QUERY_RESP
    {
        public MessageHeader Header
        {
            get
            {
                return this._Header;
            }
        }

        public string Time
        {
            get
            {
                return this._Time;
            }
        }

        public uint Query_Type
        {
            get
            {
                return this._Query_Type;
            }
        }

        public string Query_Code
        {
            get
            {
                return this._Query_Code;
            }
        }

        public uint Mt_TlMsg
        {
            get
            {
                return this._MT_TLMsg;
            }
        }

        public uint Mt_Tlusr
        {
            get
            {
                return this._MT_Tlusr;
            }
        }

        public uint Mt_Scs
        {
            get
            {
                return this._MT_Scs;
            }
        }

        public uint MT_WT
        {
            get
            {
                return this._MT_WT;
            }
        }

        public uint MT_FL
        {
            get
            {
                return this._MT_FL;
            }
        }

        public uint MO_Scs
        {
            get
            {
                return this._MO_Scs;
            }
        }

        public uint MO_WT
        {
            get
            {
                return this._MO_WT;
            }
        }

        public uint MO_FL
        {
            get
            {
                return this._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);
            this._Header = new MessageHeader(buffer);

            //Time 8
            i += MessageHeader.Length;
            buffer = new byte[8];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            this._Time = Encoding.ASCII.GetString(buffer);

            //Query_Type 1
            i += 8;
            this._Query_Type = (uint)bytes[i++];

            //Query_Code 10
            buffer = new byte[10];
            Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);
            this._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);
            this._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);
            this._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);
            this._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);
            this._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);
            this._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);
            this._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);
            this._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);
            this._MO_FL = BitConverter.ToUInt32(buffer, 0);
        }

        public override string ToString()
        {
            return "[/r/n"
             + this._Header.ToString() + "/r/n"
             + string.Format
              (
               "/tMessageBody:"
               + "/r/n/t/tBodyLength: {0}"
               + "/r/n/t/tMO_FL: {1}"
               + "/r/n/t/tMO_Scs: {2}"
               + "/r/n/t/tMO_WT: {3}"
               + "/r/n/t/tMT_FL: {4}"
               + "/r/n/t/tMT_Scs: {5}"
               + "/r/n/t/tMT_TLMsg: {6}"
               + "/r/n/t/tMT_Tlusr: {7}"
               + "/r/n/t/tMT_WT: {8}"
               + "/r/n/t/tQuery_Code: {9}"
               + "/r/n/t/tQuery_Type: {10}"
               + "/r/n/t/tTime: {11}"

               , CMPP_QUERY_RESP.BodyLength
               , this._MO_FL
               , this._MO_Scs
               , this._MO_WT
               , this._MT_FL
               , this._MT_Scs
               , this._MT_TLMsg
               , this._MT_Tlusr
               , this._MT_WT
               , this._Query_Code
               , this._Query_Type
               , this._Time
              )
                  + "/r/n]";
        }
    }

    public class CMPP_ACTIVE_TEST
    {
        private MessageHeader _Header;

        public MessageHeader Header
        {
            get
            {
                return this._Header;
            }
        }

        public CMPP_ACTIVE_TEST(uint Sequence_Id)
        {
            this._Header = new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_ACTIVE_TEST, Sequence_Id);
        }

        public byte[] ToBytes()
        {
            return this._Header.ToBytes();
        }

        public override string ToString()
        {
            return this._Header.ToString();

        }
    }

    public class CMPP_ACTIVE_TEST_RESP
    {
        private MessageHeader _Header;
        private uint _Reserved;

        public uint Reserved
        {
            get
            {
                return this._Reserved;
            }
        }

        public MessageHeader Header
        {
            get
            {
                return this._Header;
            }
        }

        public const int Bodylength = 1;

        public CMPP_ACTIVE_TEST_RESP(uint Sequence_Id)
        {
            this._Header = new MessageHeader(MessageHeader.Length + Bodylength, CMPP_Command_Id.CMPP_ACTIVE_TEST_RESP, Sequence_Id);
         //   this._Header = new MessageHeader((uint)(MessageHeader.Length + BodyLength), CMPP_Command_Id.CMPP_ACTIVE_TEST_RESP, Sequence_Id);
            this._Reserved = 0;
           
        }

        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);
            this._Header = new MessageHeader(buffer);

            //Reserved 1
            i += MessageHeader.Length;
            this._Reserved = bytes[i];
        }

 

        public byte[] ToBytes()
        {
            int i = 0;
            byte[] bytes = new byte[MessageHeader.Length + Bodylength];

            byte[] buffer = new byte[MessageHeader.Length];
            buffer = this._Header.ToBytes();
            Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);
            i += MessageHeader.Length;
            //Reserved
            bytes[i++] = (byte)this.Reserved;

            return bytes;


        }
        public override string ToString()
        {
            return this._Header.ToString();
        }

    }

}

 

 

 

 

 

//------------------------------------------------------------------------------

文件名MessageEventArgs.cs

//------------------------------------------------------------------------------

 

using System;
using System.Collections.Generic;
using System.Text;

 

namespace AsiaINFO.SMS.CMPP2
{
 
    /// <summary>
    /// 消息包
    /// </summary>
    public class MessageEventArgs : EventArgs
    {
        private byte[] _HeaderData;
        private MessageHeader _Header;
        private byte[] _BodyData;

        public byte[] BodyData
        {
            get
            {
                return this._BodyData;
            }
        }

        public MessageHeader Header
        {
            get
            {
                return this._Header;
            }
        }

        public byte[] HeaderData
        {
            get
            {
                return this._HeaderData;
            }
        }

        public MessageEventArgs(byte[] bytes)
        {
            this._HeaderData = new byte[MessageHeader.Length];
            Buffer.BlockCopy(bytes, 0, this._HeaderData, 0, MessageHeader.Length);
            this._Header = new MessageHeader(this._HeaderData);
            this._BodyData = new byte[this._Header.Total_Length - MessageHeader.Length];
            Buffer.BlockCopy(bytes, MessageHeader.Length, this._BodyData, 0, this._BodyData.Length);
        }

    }
}

 

 

 

 

 

 

 

 


//------------------------------------------------------------------------------

文件名StateDictionary.cs

//------------------------------------------------------------------------------

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsiaINFO.SMS.CMPP2
{

    /// <summary>
    /// 状态字典
    /// </summary>
    public class StateDictionary
    {
       
        /// <summary>
        /// 连接状态字典
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public static string ConnResDictionary(uint state)
        {
            string result = "连接结果:";
            switch (state)
            {
                case 0: result += "成功!"; break;
                case 1: result += "错误!  原因:消息结构错"; break;
                case 2: result += "错误!  原因:非法源地址"; break;
                case 3: result += "错误!  原因:认证错误"; break;
                case 4: result += "错误!  原因:版本太高"; break;

                case 997: result += "错误!  原因:连接超时"; break;
                case 998: result += "错误!  原因:远程服务器主动断开"; break;
                case 999: result += "错误!  原因:未知错误"; break;
                default: result = "错误!  原因:其他错误" + state.ToString(); break;
            }
            return result;
        }


    }
}

 

 

//------------------------------------------------------------------------------

文件名SyncEvents.cs

//------------------------------------------------------------------------------

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace AsiaINFO.SMS.CMPP2
{
    /// <summary>
    /// 同步信号量
    /// </summary>
    public class SyncEvents
    {
        public SyncEvents()
        {
            _newItemEvent = new AutoResetEvent(false);
            _exitThreadEvent = new ManualResetEvent(false);
            _eventArray = new WaitHandle[2];
            _eventArray[0] = _newItemEvent;
            _eventArray[1] = _exitThreadEvent;
        }

        /// <summary>
        /// 退出信号
        /// </summary>
        public EventWaitHandle ExitThreadEvent
        {
            get { return _exitThreadEvent; }
        }

        /// <summary>
        /// 收到数据信号
        /// </summary>
        public EventWaitHandle NewItemEvent
        {
            get { return _newItemEvent; }
        }

        public WaitHandle[] EventArray
        {
            get { return _eventArray; }
        }

        private EventWaitHandle _newItemEvent;

        private EventWaitHandle _exitThreadEvent;
        private WaitHandle[] _eventArray;
    }
}

 

 

 

 


//------------------------------------------------------------------------------

文件名Util.cs

//------------------------------------------------------------------------------

 

 

using System;
using System.Net.Sockets;

namespace AsiaINFO.SMS.CMPP2
{
    public class Util
    {
        //private static object _SyncLockObject = new object();

        public static string Get_MMDDHHMMSS_String(DateTime dt)
        {
            string s = dt.Month.ToString().PadLeft(2, '0');
            s += dt.Day.ToString().PadLeft(2, '0');
            s += dt.Hour.ToString().PadLeft(2, '0');
            s += dt.Minute.ToString().PadLeft(2, '0');
            s += dt.Second.ToString().PadLeft(2, '0');
            return s;
        }

        public static string Get_YYYYMMDD_String(DateTime dt)
        {
            string s = dt.Year.ToString().PadLeft(4, '0');
            s += dt.Month.ToString().PadLeft(2, '0');
            s += dt.Day.ToString().PadLeft(2, '0');
            return s;
        }

        internal static void WriteToStream(byte[] bytes, NetworkStream Stream)
        {
            if (Stream.CanWrite)
            {
                //lock (_SyncLockObject)
                //{
                    Stream.Write(bytes, 0, bytes.Length);
                //}
            }
        }

        internal static byte[] ReadFromStream(int Length, NetworkStream Stream)
        {
            byte[] bytes = null;
            if (Stream.CanRead)
            {
                if (Stream.DataAvailable)
                {
                    bytes = new byte[Length];
                    int r = 0;
                    int l = 0;
                    //lock (_SyncLockObject)
                    {
                        while (l < Length)
                        {
                            r = Stream.Read(bytes, l, Length - l);
                            l += r;
                        }
                    }
                }
            }
            return bytes;
        }
    }
}

 

 

 

//------------------------------------------------------------------------------

 文件名WapPush.cs

//------------------------------------------------------------------------------

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsiaINFO.SMS.CMPP2
{
   public  class WapPush
    {

       private static WapPush push = null;
        public static WapPush GetInstance()
        {
            if (null == push)
            {
                push = new WapPush();

            }
            return push;
        }


        //第一部分
        static private readonly byte[] WapPushHeader1 = new byte[]
        {
            0x0B, 0x05, 0x04, 0x0B, 0x84, 0x23, 0xF0, 0x00, 0x03, 0x03, 0x01, 0x01
        };
        //第二部分
        static private readonly byte[] WapPushHeader2 = new byte[]
        {
            0x29, 0x06, 0x06, 0x03, 0xAE, 0x81, 0xEA, 0x8D, 0xCA
        };

        //第三部分
        static private readonly byte[] WapPushIndicator = new byte[]
        {
            0x02, 0x05, 0x6A, 0x00, 0x45, 0xC6, 0x0C, 0x03
        };
        //第四部分:URL去掉http://后的UTF8编码
        //第五部分
        static private readonly byte[] WapPushDisplayTextHeader = new byte[]
        {
            0x00, 0x01, 0x03,
        };
        //第六部分:消息文字的UTF8编码
        //第七部分:
        static private readonly byte[] EndOfWapPush = new byte[]
        {
            0x00, 0x01, 0x01,
        };
        public  byte[] toBytes(string WAP_Msg, string WAP_URL)
        {
            byte[] submitData = new byte[400];
            int index = 0;
            WapPushHeader1.CopyTo(submitData, index);
            index += WapPushHeader1.Length;

            WapPushHeader2.CopyTo(submitData, index);
            index += WapPushHeader2.Length;
                          
            WapPushIndicator.CopyTo(submitData, index);
            index += WapPushIndicator.Length;

            byte[] url = Encoding.UTF8.GetBytes(WAP_URL);
            url.CopyTo(submitData, index);
            index += url.Length;

            WapPushDisplayTextHeader.CopyTo(submitData, index);
            index += WapPushDisplayTextHeader.Length;

            byte[] msg2 = Encoding.UTF8.GetBytes(WAP_Msg);
            msg2.CopyTo(submitData, index);
            index += msg2.Length;
                          
            EndOfWapPush.CopyTo(submitData, index);
            index += 3;

            byte[] reVal = new byte[index];
            for (int i = 0; i < reVal.Length; i++)
            {
                reVal = submitData;
            }

            return (reVal);
        }

    }
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值