天天看點

中國聯通SGIP接口

下載下傳參考程式 :http://download.csdn.net/detail/adama119/4189313 

短信行業已經很成熟了,到處可以找到資料。本人在這個行業幹過幾年,做過3套短信平台都在省級機關省用,做的最複雜的自然是SP的應用,曾經在廣電集團工作時做的内容确實非常複雜自己都覺得頭疼,當然也和水準有限有關。

2010年底給江蘇某國企做了一套行業應用的短信系統,做短信平台大量工作還是圍繞業務開發WEB方面内容。這次網關用戶端的是用C#開發的,目标為50條/秒,性能上應該沒什麼問題,支援普通短信但是長短信對方沒要就沒寫,需要的朋友可以自行修改開發。以下貼出SGIP1.2源代碼給各位需要的朋友做個參考,運作到現在沒有發現任何問題。這裡隻貼出sgip接口,至于程式就自己做吧,如果需要也可以聯系我。

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

//檔案Client.cs

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

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

using System.Net.Sockets;

using System.Collections;

namespace AsiaINFO.SMS.SGIP

{

    /// <summary>

    /// @Description:SGIP1.2 短消息聯通網關SP用戶端

    /// @Author:Adama SUN

    /// @Mail:[email protected]

    /// @Copyright (C) 2010 AsiaINFO. All rights reserved.

    /// </summary>

    public class SGIPClient : SGIPBase

    {

        public SGIPClient(Queue<byte[]> queue, SyncEvents syncEvents)

            : base(queue, syncEvents)

        {

        }

        #region private field

        private string _CorpId;           //企業代碼

        private static object _SyncLockObject = new object();   //鎖

        private TcpClient tc;              

        private NetworkStream _NetworkStream;

        #endregion

        #region public methos

        /// <summary>

        /// 連接配接

        /// </summary>

        /// <param name="Host">主機位址</param>

        /// <param name="Port">端口</param>

        /// <param name="UserID">使用者名</param>

        /// <param name="Password">密碼</param>

        /// <param name="CorpId">企業代碼</param>

        /// <param name="SequenceId">序列号</param>

        /// <returns></returns>

        public void Connect(string Host, int Port, string UserID, string Password,string CorpId, uint SequenceId)

        {

            this._CorpId = CorpId;

            SGIP_Bind connect = new SGIP_Bind((uint)LoginTypes.SpToSmg,UserID, Password, SequenceId);

            if (!IsConnected || tc == null || !tc.Connected)

            {

                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,SGIP_Command_Id.SGIP_UNBIND, SequenceId);

            this.WriteToStreamWithLock(terminate.ToBytes(), this._NetworkStream);

        }

        /// <summary>

        /// 發送短信

        /// </summary>

        /// <param name="SPNumber">SP号碼</param>

        /// <param name="feeMobile">計費手機号碼</param>

        /// <param name="mobile">手機号碼</param>

        /// <param name="MessageContent">短消息的内容</param>

        /// <param name="LinkID">LinkID</param>

        /// <param name="SequenceId">序列号</param>

        public void Submit(string SPNumber,string feeMobile, string mobile, string MessageContent, string LinkID, uint SequenceId)

        {

            Submit(SPNumber, feeMobile, mobile, "HELP", (uint)FeeTypes.Free, "0", (uint)SubmitMorelatetoMTFlags.NormalFirst, (uint)SubmitReportFlag.Always, MessageContent, LinkID, SequenceId);

        }

        /// <summary>

        /// 發送短信

        /// </summary>

        /// <param name="SPNumber">SP的接入号碼</param>

        /// <param name="ChargeNumber">付費号碼</param>

        /// <param name="UserNumber">接收該短消息的手機号</param>

        /// <param name="ServiceType">業務代碼</param>

        /// <param name="FeeType">計費類型</param>

        /// <param name="FeeValue">費率,機關分</param>

        /// <param name="MorelatetoMTFlag">引起MT消息的原因</param>

        /// <param name="ReportFlag">狀态報告标記</param>

        /// <param name="MessageContent">短消息的内容</param>

        /// <param name="LinkID">LinkID</param>

        /// <param name="SequenceId">序列号</param>

        public void Submit(string SPNumber, string ChargeNumber, string UserNumber, string ServiceType, uint FeeType, string FeeValue

            , uint MorelatetoMTFlag,uint ReportFlag, string MessageContent, string LinkID, uint SequenceId)

        {

            if (ChargeNumber != null && ChargeNumber.Length == 11)

                ChargeNumber = "86" + ChargeNumber;

            if (UserNumber != null && UserNumber.Length == 11)

                UserNumber = "86" + UserNumber;

            SGIP_SUBMIT submit = new SGIP_SUBMIT(SequenceId);

            submit.SPNumber = SPNumber;

            submit.ChargeNumber = ChargeNumber;

             // submit.ChargeNumber = "";

            submit.UserCount = 1;

            submit.UserNumber = UserNumber;

            submit.CorpId = this._CorpId;

            submit.ServiceType = ServiceType;

            submit.FeeType = FeeType;

            submit.FeeValue = FeeValue;

            submit.GivenValue = "0";

            submit.AgentFlag = (uint)SubmitAgentFlag.RealIncome;

            submit.MorelatetoMTFlag = MorelatetoMTFlag;

            submit.Priority = 0;

            submit.ExpireTime = "";

            submit.ScheduleTime = "";

            submit.ReportFlag = ReportFlag;

            submit.TP_pid = 0;

            submit.TP_udhi = 0;

            submit.MessageCoding = 15;

            submit.MessageType = 0;

            submit.MessageContent = MessageContent;

            submit.LinkID = LinkID;

            this.WriteToStreamWithLock(submit.ToBytes(), this._NetworkStream);

        }

        /// <summary>

        /// 斷開回複

        /// </summary>

        /// <param name="SrcNodeSequence"></param>

        /// <param name="DateSequence"></param>

        /// <param name="Sequence_Id"></param>

        public void UnbindResp(uint SrcNodeSequence, uint DateSequence, uint Sequence_Id)

        {

            SGIP_Unbind_Resp response = new SGIP_Unbind_Resp(SrcNodeSequence, DateSequence, Sequence_Id);

            this.WriteToStreamWithLock(response.ToBytes(), this._NetworkStream);

        }

        /// <summary>

        /// 退出

        /// </summary>

        public void Exit()

        {

            try

            {

                StopReceive();

                this._NetworkStream.Close();

                this._NetworkStream = null;

            }

            catch (Exception) { }

        }

        #endregion

        #region private method

        private void CloseClient()

        {

            try

            {

                try

                {

                    IsConnected = false;

                    this.tc.Client.Shutdown(SocketShutdown.Both);

                }

                catch

                {

                }

            }

            finally

            {

                this.tc.Close();

            }

        }

        /// <summary>

        /// 寫入流

        /// </summary>

        /// <param name="data"></param>

        /// <param name="Stream"></param>

        private void WriteToStreamWithLock(byte[] data, NetworkStream Stream)

        {

            try

            {

                lock (_SyncLockObject)

                {

                    Util.WriteToStream(data, Stream);

                }

            }

            catch (Exception ex)

            {

                CloseClient();

                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)

            {

                CloseClient();

                OnError(ex.Message);

            }

            return null;

        }

        protected override 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)

            {

                CloseClient();

                OnError("SGIPClient接收錯誤:"+ex.Message);

            }

            OnThreadState(ThreadState.Stopped);

        }

        #endregion

    }

}

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

//檔案MessageEventArgs.cs

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

using System;

using System.Collections.Generic;

using System.Text;

namespace AsiaINFO.SMS.SGIP

{

    /// <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);

        }

    }

}

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

//檔案Server.cs

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

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

using System.Net;

using System.Net.Sockets;

using System.Collections;

namespace AsiaINFO.SMS.SGIP

{

    /// <summary>

    /// @Description:SGIP1.2 短消息聯通網關SP服務端

    /// @Author:Adama SUN

    /// @Mail:[email protected]

    /// @Copyright (C) 2010 AsiaINFO. All rights reserved.

    /// </summary>

    public class SGIPServer : SGIPBase

    {

        //     private Socket _Server;

        private TcpListener _tcpListener;

        private string _LoginName;

        private string _LoginPassowrd;

        private string _Host;

        private int _Port;

        private byte[] _Buffer = new byte[0x10000];

        private ManualResetEvent _MySet = new ManualResetEvent(false);

        private BaseSortedList<string, ClientQueue> m_ClientInfo;

        private bool m_IsRun;

        /// <summary>

        /// 空閑間隔

        /// </summary>

        private int _TerminateFreeInterval;

        /// <summary>

        /// 源節點編号

        /// </summary>

        internal static uint _SrcNodeSequence = 3057199999;

        public event NetEventDelegate RecvDataEvent;

        public SGIPServer(Queue<byte[]> queue, SyncEvents syncEvents, string Host, int Port, string LoginName, string LoginPassowrd, uint SrcNodeSequence, int rerminateFreeInterval)

            : base(queue, syncEvents)

        {

            this._Host = Host;

            this._Port = Port;

            this._LoginName = LoginName;

            this._LoginPassowrd = LoginPassowrd;

            SGIPServer._SrcNodeSequence = SrcNodeSequence;

            this.m_IsRun = true;

            this._TerminateFreeInterval = rerminateFreeInterval;

        }

        protected override void Run()

        {

            try

            {

                OnMsg("正在啟動監聽...");

                this.m_ClientInfo = new BaseSortedList<string, ClientQueue>();

               // this._Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(this._Host), this._Port);

                if (this._Host == null || this._Host == "127.0.0.1" || this._Host=="")     

                    this._tcpListener = new TcpListener(_Port);

                else

                    this._tcpListener = new TcpListener(localEP);

                this._tcpListener.Start();

                //this._Server.Bind(localEP);

                //this._Server.Listen(50);

                this.IsConnected = true;

                OnMsg("啟動監聽成功");

                while (!_syncEvents.ExitThreadEvent.WaitOne(2, false))

                {

                    this._MySet.Reset();

                    this._tcpListener.BeginAcceptTcpClient(new AsyncCallback(this.AcceptCallBack), this._tcpListener);

                    this._MySet.WaitOne();

                }

            }

            catch (Exception ex)

            {

                OnError("SGIPServer監聽錯誤:" + ex.Message);

            }

            finally

            {

                Stop();

            }

        }

        public void Stop()

        {

            if (!this.IsConnected)

                return;

            try

            {

                try

                {

                    StopReceive();

                    this._tcpListener.Server.Shutdown(SocketShutdown.Both);

                }

                catch

                {

                }

            }

            finally

            {

                this._tcpListener.Server.Close();

                this.IsConnected = false;

            }

        }

        private void AcceptCallBack(IAsyncResult ia)

        {

            this._MySet.Set();

            try

            {

                TcpClient tc = ((TcpListener)ia.AsyncState).EndAcceptTcpClient(ia);

                ClientQueue queue = new ClientQueue(tc, DateTime.Now);

                this.m_ClientInfo.Add(this.GetSocketIP(tc), queue);

                int msgCount = tc.Client.Receive(this._Buffer);

                if (msgCount > 0)

                {

                    uint BindResult = 0;

                    if (Util.bytes2Uint(this._Buffer, 0) == msgCount)

                    {

                        if (Util.bytes2Uint(this._Buffer, 4) == 1)

                        {

                            SGIP_Bind bind = new SGIP_Bind(this._Buffer);

                            if (bind.LoginType == (uint)LoginTypes.SmgToSp || bind.LoginType == (uint)LoginTypes.SpToSmg)

                            {

                                if ((bind.LoginName == this._LoginName) && (bind.LoginPassword == this._LoginPassowrd))

                                {

                                    BindResult = 0;

                                }

                                else

                                {

                                    BindResult = 1;

                                }

                            }

                            else

                            {

                                BindResult = 4;

                            }

                            SGIP_Bind_Resp resp = new SGIP_Bind_Resp(BindResult, bind.Header.SrcNodeSequence, bind.Header.DateSequence, bind.Header.Sequence_Id);

                            this.SendMSG(resp.ToBytes(), tc);

                            if (BindResult == 0)

                            {

                                ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(this.Recv), tc);

                            }

                            else

                            {

                                string msg = string.Format("網關登入SP服務端失敗 Result={0} LoginType={1} LoginName={2} Passowrd={3} ", BindResult, bind.LoginType, bind.LoginName, bind.LoginPassword);

                                OnMsg(msg);

                            }

                        }

                    }

                    else

                    {

                        this.CloseClient(tc);

                    }

                }

            }

            catch (SocketException ex)

            {

                OnError("AcceptCallBack_SocketException錯誤:" + ex.Message);

            }

            catch { }

        }

        public void SendMSG(byte[] bs, TcpClient tc)

        {

            try

            {

                if (tc.Client.Send(bs) == 0)

                {

                    this.CloseClient(tc);

                }

            }

            catch (SocketException)

            {

                this.CloseClient(tc);

            }

            catch { }

        }

        protected void Recv(object client)

        {

            string msg = string.Format("網關登入SP服務端成功 ,監聽線程池配置設定線程ID={0}", AppDomain.GetCurrentThreadId());

            OnMsg(msg);

            TcpClient tc = null;

            NetworkStream networkStream = null;

            try

            {

                tc = (TcpClient)client;

                networkStream = tc.GetStream();

                object syncLockObject = new object();   //鎖

                DateTime startTime = DateTime.Now;

                while (!_syncEvents.ExitThreadEvent.WaitOne(2, false))

                {

                    if (networkStream.CanRead)

                    {

                        if (networkStream.DataAvailable)

                        {

                            startTime = DateTime.Now;

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

                            buffer = this.ReadFromStreamWithLock(syncLockObject, 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 = this.ReadFromStreamWithLock(syncLockObject, l, networkStream);

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

                            }

                            if (this.RecvDataEvent != null)

                            {

                                this.RecvDataEvent(bytes, 0, tc);

                            }

                        }

                        else

                        {

                            ///計算空閑時間

                            TimeSpan ts = DateTime.Now - startTime;

                            if (ts.TotalSeconds > this._TerminateFreeInterval)

                            {

                                Terminate(syncLockObject, 1, networkStream);

                                CloseClient(tc);

                                msg = string.Format("逾時:監聽線程池 線程ID={0}", AppDomain.GetCurrentThreadId());

                                OnMsg(msg);

                                break;

                            }

                        }

                    }

                    else

                        break;

                }

            }

            catch (Exception)

            {

                CloseClient(tc);

                msg = string.Format("接收錯誤:監聽線程池 線程ID={0}", AppDomain.GetCurrentThreadId());

                OnMsg(msg);

            }

            finally

            {

                msg = string.Format("退出:監聽線程池 線程ID={0}", AppDomain.GetCurrentThreadId());

                OnMsg(msg);

            }

        }

        /// <summary>

        /// 中斷

        /// </summary>

        /// <param name="SequenceId"></param>

        public void Terminate(object syncLockObject,uint SequenceId, NetworkStream stream)

        {

            MessageHeader terminate = new MessageHeader(MessageHeader.Length, SGIP_Command_Id.SGIP_UNBIND, SequenceId);

            this.WriteToStreamWithLock(syncLockObject,terminate.ToBytes(), stream);

        }

        /// <summary>

        /// 讀取流

        /// </summary>

        /// <param name="Length"></param>

        /// <param name="Stream"></param>

        /// <returns></returns>

        private byte[] ReadFromStreamWithLock(object syncLockObject,int Length, NetworkStream Stream)

        {

            try

            {

                lock (syncLockObject)

                {

                    return Util.ReadFromStream(Length, Stream);

                }

            }

            catch (Exception){}

            return null;

        }

        /// <summary>

        /// 寫入流

        /// </summary>

        /// <param name="data"></param>

        /// <param name="Stream"></param>

        private void WriteToStreamWithLock(object syncLockObject, byte[] data, NetworkStream Stream)

        {

            try

            {

                lock (syncLockObject)

                {

                    Util.WriteToStream(data, Stream);

                }

            }

            catch (Exception){}

        }

        private void CloseClient(TcpClient tc)

        {

            try

            {

                try

                {

                    tc.Client.Shutdown(SocketShutdown.Both);

                }

                catch

                {

                }

            }

            finally

            {

                tc.Close();

            }

        }

        private string GetSocketIP(TcpClient tc)

        {

            try

            {

                IPEndPoint remoteEndPoint = (IPEndPoint)tc.Client.RemoteEndPoint;

                return (remoteEndPoint.Address.ToString() + ":" + remoteEndPoint.Port.ToString());

            }

            catch

            {

                return "";

            }

        }

        private BaseSortedList<string, ClientQueue> ClientInfo

        {

            get

            {

                return this.m_ClientInfo;

            }

        }

        /// <summary>

        /// 發送SGIP_DELIVER_RESP

        /// </summary>

        /// <param name="Result"></param>

        /// <param name="SrcNodeSequence"></param>

        /// <param name="DateSequence"></param>

        /// <param name="SequenceId"></param>

        /// <param name="soc"></param>

        public void DeliverResp(uint Result, uint SrcNodeSequence, uint DateSequence, uint SequenceId, TcpClient tc)

        {

            SGIP_DELIVER_RESP deliverResp = new SGIP_DELIVER_RESP(Result, "", SrcNodeSequence, DateSequence, SequenceId);

            this.SendMSG(deliverResp.ToBytes(), tc);

        }

        /// <summary>

        /// 發送SGIP_Report_Resp

        /// </summary>

        /// <param name="Result"></param>

        /// <param name="SrcNodeSequence"></param>

        /// <param name="DateSequence"></param>

        /// <param name="SequenceId"></param>

        /// <param name="soc"></param>

        public void ReportResp(uint Result, uint SrcNodeSequence, uint DateSequence, uint SequenceId, TcpClient tc)

        {

            SGIP_Report_Resp reportResp = new SGIP_Report_Resp(Result, "", SrcNodeSequence, DateSequence, SequenceId);

            this.SendMSG(reportResp.ToBytes(), tc);

        }

        /// <summary>

        /// 發送SGIP_Unbind_Resp

        /// </summary>

        /// <param name="SrcNodeSequence"></param>

        /// <param name="DateSequence"></param>

        /// <param name="SequenceId"></param>

        /// <param name="soc"></param>

        public void UnbindResp(uint SrcNodeSequence, uint DateSequence, uint SequenceId, TcpClient tc)

        {

            SGIP_Unbind_Resp unbindResp = new SGIP_Unbind_Resp(SrcNodeSequence, DateSequence, SequenceId);

            this.SendMSG(unbindResp.ToBytes(), tc);

            CloseClient(tc);

        }

    }

    public delegate void NetEventDelegate(byte[] bs, int recvCount, TcpClient tc);

}

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

//檔案SGIPBase.cs

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

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

using System.Net.Sockets;

using System.Collections;

namespace AsiaINFO.SMS.SGIP

{

    public class SGIPBase

    {

        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">接收資料隊列</param>

        /// <param name="syncEvents">接口信号:檢查是否需要退出線程,接口新資料到達(通知)</param>

        public SGIPBase(Queue<byte[]> queue, SyncEvents syncEvents)

        {

            if (queue == null || syncEvents == null)

                throw new Exception("參數不能為空!");

            _receiveQueue = queue;

            _syncEvents = syncEvents;

        }

        #region public property

        /// <summary>

        /// 監聽或連接配接狀态

        /// </summary>

        public bool IsConnected

        {

            get

            {

                lock (_syncIsConnectedObject)

                {

                    return this._IsConnected;

                }

            }

            set

            {

                lock (_syncIsConnectedObject)

                {

                    this._IsConnected = value;

                }

            }

        }

        #endregion

        #region protected field

        protected Queue<byte[]> _receiveQueue;//接收隊列

        protected SyncEvents _syncEvents;//信号

        protected Thread _thread;

        private object _syncIsConnectedObject = new object();

        private bool _IsConnected = false;      //監聽或連接配接狀态

        #endregion

        #region public event

        /// <summary>

        /// 資訊事件

        /// </summary>

        public event MsgEventDelegate MsgEvent;

        /// <summary>

        /// 錯誤事件

        /// </summary>

        public event MsgEventDelegate ErrorEvent;

        /// <summary>

        /// 退出事件

        /// </summary>

        public event ThreadStateDelegate ThreadStateEvent;

        /// <summary>

        /// 資訊通知

        /// </summary>

        protected void OnMsg(string msg)

        {

            if (MsgEvent != null)

            {

                MsgEvent(msg);

            }

        }

        /// <summary>

        /// 錯誤通知

        /// </summary>

        /// <param name="type"></param>

        /// <param name="err"></param>

        protected void OnError(string err)

        {

            if (ErrorEvent != null)

            {

                ErrorEvent(err);

            }

        }

        /// <summary>

        /// 退出

        /// </summary>

        protected void OnThreadState(ThreadState state)

        {

            if (ThreadStateEvent != null)

            {

                ThreadStateEvent(this, state);

            }

        }

        #endregion

        #region public method

        public void StartRun()

        {

            try

            {

                if (this._thread == null)

                {

                    this._thread = new Thread(new ThreadStart(this.Run));

                }

                if (this._thread.ThreadState == ThreadState.Unstarted)

                {

                    OnThreadState(ThreadState.Running);

                    this._thread.Start();

                }

                else if (this._thread.ThreadState == ThreadState.Suspended)

                {

                    OnThreadState(ThreadState.Running);

                    this._thread.Resume();

                }

                else if (this._thread.ThreadState == ThreadState.Stopped)

                {

                    OnThreadState(ThreadState.Running);

                    this._thread = null;

                    this._thread = new Thread(new ThreadStart(this.Run));

                    this._thread.Start();

                }

            }

            catch (Exception ex)

            {

                OnError("SGIP啟動錯誤:" + ex.Message);

            }

        }

        /// <summary>

        /// 暫停線程

        /// </summary>

        public void Suspend()

        {

            try

            {

                if (this._thread != null && _thread.ThreadState != ThreadState.Stopped && _thread.ThreadState != ThreadState.Suspended)

                {

                    OnThreadState(ThreadState.Suspended);

                    this._thread.Suspend();

                }

            }

            catch (Exception) { }

        }

        /// <summary>

        /// 是否已經停止

        /// </summary>

        /// <returns></returns>

        public bool IsStop()

        {

            if (_thread == null || _thread.ThreadState == ThreadState.Stopped || _thread.ThreadState == ThreadState.Aborted || _thread.ThreadState == ThreadState.AbortRequested)

                return true;

            return false;

        }

        /// <summary>

        /// 立刻停止

        /// </summary>

        /// <returns></returns>

        public void StopImmediately()

        {

            try

            {

                if (_thread != null)

                    _thread.Abort();

            }

            catch (ThreadAbortException) { }

            catch (Exception) { }

            finally

            {

                OnThreadState(ThreadState.Stopped);

            }

        }

        /// <summary>

        /// 停止接收資料

        /// </summary>

        public void StopReceive()

        {

            _syncEvents.ExitThreadEvent.Set();

        }

        #endregion

        #region protected method

        protected virtual void Run()

        {

        }

        #endregion

    }

}

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

//檔案SGIPMessages.cs

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

using System;

using System.Text;

using System.Security.Cryptography;

namespace AsiaINFO.SMS.SGIP

{

    //SGIP 消息定義

    public enum SGIP_Command_Id : uint

    {

        SGIP_BIND = 0x1,

        SGIP_BIND_RESP = 0x80000001,

        SGIP_UNBIND = 0x2,

        SGIP_UNBIND_RESP = 0x80000002,

        SGIP_SUBMIT = 0x3,

        SGIP_SUBMIT_RESP = 0x80000003,

        SGIP_DELIVER = 0x4,

        SGIP_DELIVER_RESP = 0x80000004,

        SGIP_REPORT = 0x5,

        SGIP_REPORT_RESP = 0x80000005,

        //SGIP_ADDSP = 0x6,

        //SGIP_ADDSP_RESP = 0x80000006,

        //SGIP_MODIFYSP = 0x7,

        //SGIP_MODIFYSP_RESP = 0x80000007,

        //SGIP_DELETESP = 0x8,

        //SGIP_DELETESP_RESP = 0x80000008,

        //SGIP_QUERYROUTE = 0x9,

        //SGIP_QUERYROUTE_RESP = 0x80000009,

        //SGIP_ADDTELESEG = 0xa,

        //SGIP_ADDTELESEG_RESP = 0x8000000a,

        //SGIP_MODIFYTELESEG = 0xb,

        //SGIP_MODIFYTELESEG_RESP = 0x8000000b,

        //SGIP_DELETETELESEG = 0xc,

        //SGIP_DELETETELESEG_RESP = 0x8000000c,

        //SGIP_ADDSMG = 0xd,

        //SGIP_ADDSMG_RESP = 0x8000000d,

        //SGIP_MODIFYSMG = 0xe,

        //SGIP_MODIFYSMG_RESP = 0x0000000e,

        //SGIP_DELETESMG = 0xf,

        //SGIP_DELETESMG_RESP = 0x8000000f,

        //SGIP_CHECKUSER = 0x10,

        //SGIP_CHECKUSER_RESP = 0x80000010,

        //SGIP_USERRPT = 0x11,

        //SGIP_USERRPT_RESP = 0x80000011,

        //SGIP_TRACE = 0x1000,

        //SGIP_TRACE_RESP = 0x80001000,

    }

    /// <summary>

    /// 消息頭

    /// </summary>

    public class MessageHeader

    {

        public const int Length = 4 + 4 + 4 + 4 + 4;

        /// <summary>

        /// 擷取指令類型

        /// </summary>

        public SGIP_Command_Id Command_Id

        {

            get

            {

                return this._Command_Id;

            }

        }

        /// <summary>

        /// 擷取序列号

        /// </summary>

        public uint Sequence_Id

        {

            get

            {

                return this._Sequence_Id;

            }

        }

        /// <summary>

        /// 擷取原節點

        /// </summary>

        public uint SrcNodeSequence

        {

            get { return _SrcNodeSequence; }

        }

        /// <summary>

        /// 擷取指令産生的日期和時間

        /// </summary>

        public uint DateSequence

        {

            get { return _DateSequence; }

        }

        /// <summary>

        /// 擷取總長度

        /// </summary>

        public uint Total_Length

        {

            get

            {

                return this._Total_Length;

            }

        }

        private uint _Total_Length;    // 4 Unsigned Integer 消息總長度(含消息頭及消息體)

        private SGIP_Command_Id _Command_Id; // 4 Unsigned Integer 指令或響應類型

        private uint _SrcNodeSequence = 3057199999;  //4 Unsigned Integer 源節點的編号

        private uint _DateSequence = 0;     //4 Unsigned Integer 格式為十進制的mmddhhmmss

        private uint _Sequence_Id;    // 4 Unsigned Integer 消息流水号,順序累加,步長為1,循環使用(一對請求和應答消息的流水号必須相同)

        public MessageHeader

         (

          uint Total_Length

          , SGIP_Command_Id Command_Id

          , uint Sequence_Id

         ) //發送前

        {

            this._Total_Length = Total_Length;

            this._Command_Id = Command_Id;

            this._SrcNodeSequence = SGIPServer._SrcNodeSequence;

            this._DateSequence = uint.Parse(Util.Get_MMDDHHMMSS_String(DateTime.Now));

            this._Sequence_Id = Sequence_Id;

        }

        public MessageHeader

         (

          uint Total_Length

          , SGIP_Command_Id Command_Id

          , uint SrcNodeSequence

          , uint  DateSequence

          , uint Sequence_Id

         ) //發送前

        {

            this._Total_Length = Total_Length;

            this._Command_Id = Command_Id;

            this._SrcNodeSequence = SrcNodeSequence;

            this._DateSequence = DateSequence;

            this._Sequence_Id = Sequence_Id;

        }

        public MessageHeader(byte[] bytes)

        {

            int i = 0;

            byte[] buffer = new byte[4];

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

            Array.Reverse(buffer);

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

            i += 4;

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

            Array.Reverse(buffer);

            this._Command_Id = (SGIP_Command_Id)BitConverter.ToUInt32(buffer, 0);

            i += 4;

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

            Array.Reverse(buffer);

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

            i += 4;

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

            Array.Reverse(buffer);

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

            i += 4;

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

            Array.Reverse(buffer);

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

        }

        public byte[] ToBytes()

        {

            int i = 0;

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

            byte[] buffer = BitConverter.GetBytes(this._Total_Length);

            Array.Reverse(buffer);

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

            i += 4;

            buffer = BitConverter.GetBytes((uint)this._Command_Id);

            Array.Reverse(buffer);

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

            i += 4;

            buffer = BitConverter.GetBytes(this._SrcNodeSequence);

            Array.Reverse(buffer);

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

            i += 4;

            buffer = BitConverter.GetBytes(this._DateSequence);

            Array.Reverse(buffer);

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

            i += 4;

            buffer = BitConverter.GetBytes(this._Sequence_Id);

            Array.Reverse(buffer);

            Buffer.BlockCopy(buffer, 0, bytes, i, 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 SGIP_Bind        //  雙向

    {

        public const int BodyLength = 1 + 16 + 16 + 8;

        private uint _LoginType;      // 1 Unsigned Integer 登入類型。

        private string _LoginName;      // 16 Octet String  伺服器端給用戶端配置設定的登入名

        private string _LoginPassword;  // 16 Octet String  伺服器端和Login Name對應的密碼

        private string _Reserve;        // 8 Octet String  保留,擴充用

        private MessageHeader _Header;

        public SGIP_Bind

         (

          uint LoginType

          , string LoginName

          , string LoginPassword

          , uint Sequence_Id

         )

        {

            this._Header = new MessageHeader(MessageHeader.Length + BodyLength, SGIP_Command_Id.SGIP_BIND, Sequence_Id);

            this._LoginType = LoginType;

            this._LoginName = LoginName;

            this._LoginPassword = LoginPassword;

            this._Reserve = "";

        }

        //public SGIP_Bind

        // (

        //  uint LoginType

        //  , string LoginName

        //  , string LoginPassword

        //  , uint SrcNodeSequence

        //  , uint DateSequence

        //  , uint Sequence_Id

        // )

        //{

        //    this._Header = new MessageHeader(MessageHeader.Length + BodyLength, SGIP_Command_Id.SGIP_BIND,SrcNodeSequence,DateSequence, Sequence_Id);

        //    this._LoginType = LoginType;

        //    this._LoginName = LoginName;

        //    this._LoginPassword = LoginPassword;

        //    this._Reserve = "";

        //}

        public SGIP_Bind(byte[] bytes)

        {

            int i = 0;

            string s = null;

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

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

            this._Header = new MessageHeader(buffer);

            //LoginType 1

            i += MessageHeader.Length;

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

            //LoginName 16

            buffer = new byte[16];

            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._LoginName = s;

            //LoginPassword 16

            i += 16;

            buffer = new byte[16];

            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._LoginPassword = s;

            //LoginPassword 16

            i += 16;

            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._Reserve = s;

        }

        public byte[] ToBytes()

        {

            int i = 0;

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

            //header 20

            byte[] buffer = this._Header.ToBytes();

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

            //LoginType 1

            i += MessageHeader.Length;

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

            //LoginName 16

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

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

            //LoginPassword 16

            i += 16;

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

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

            //Reserve 8

            i += 16;

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

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

            return (bytes);

        }

        public override string ToString()

        {

            return string.Format("Header={0}    LoginType={1}    LoginName={2}    LoginPassword={3}    Reserve={4}"

                , this._Header.ToString()

                , this._LoginType

                , this._LoginName

                , this._LoginPassword

                , this._Reserve);

        }

        /// <summary>

        /// 擷取 登入類型

        /// </summary>

        public uint LoginType

        {

            get { return _LoginType; }

        }

        /// <summary>

        /// 擷取登陸使用者名

        /// </summary>

        public string LoginName

        {

            get { return _LoginName; }

        }

        /// <summary>

        /// 擷取登陸密碼

        /// </summary>

        public string LoginPassword

        {

            get { return _LoginPassword; }

        }

        /// <summary>

        /// 擷取保留資訊

        /// </summary>

        public string Reserve

        {

            get { return _Reserve; }

        }

        public MessageHeader Header

        {

            get

            {

                return this._Header;

            }

        }

    }

    public class SGIP_Bind_Resp // 雙向

    {

        private MessageHeader _Header;

        public const int BodyLength = 1 + 8;

        private uint _Result;       // 1 Unsigned Integer 執行指令是否成功  0:執行成功  其它:錯誤碼

        private string _Reserve;    // 8 Octet String  保留,擴充用

        public SGIP_Bind_Resp

         (

          uint Result

          , uint SrcNodeSequence

          , uint DateSequence

          , uint Sequence_Id

         )

        {

            this._Header = new MessageHeader(MessageHeader.Length + BodyLength, SGIP_Command_Id.SGIP_BIND_RESP, SrcNodeSequence, DateSequence, Sequence_Id);

            this._Result = Result;

            this._Reserve = "null";

        }

        public SGIP_Bind_Resp(byte[] bytes)

        {

            //header 20

            int i = 0;

            string s = null;

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

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

            this._Header = new MessageHeader(buffer);

            //Result 1

            i += MessageHeader.Length;

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

            //Result 8

            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._Reserve = s;

        }

        public byte[] ToBytes()

        {

            int i = 0;

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

            //header 20

            byte[] buffer = this._Header.ToBytes();

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

            //Result 1

            i += MessageHeader.Length;

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

            //Result 8

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

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

            return (bytes);

        }

        public override string ToString()

        {

            return string.Format("Header={0}   Result={1}    Reserve={2}"

                , this._Header.ToString()

                , this._Result

                , this._Reserve);

        }

        /// <summary>

        /// 擷取結果

        /// </summary>

        public uint Result

        {

          get { return _Result; }

        }

        /// <summary>

        /// 擷取保留資訊

        /// </summary>

        public string Reserve

        {

          get { return _Reserve; }

        }

        public MessageHeader Header

        {

            get

            {

                return this._Header;

            }

        }

    }

    public class SGIP_SUBMIT  

    {

        private int _BodyLength;

        public const int FixedBodyLength = 21   //SPNumber

                 + 21   //ChargeNumber

                 + 1    //UserCount

                 +21    //UserNumber

                 + 5    //CorpId

                 + 10   //ServiceType

                 + 1    //FeeType

                 + 6    //FeeValue

                 + 6    //GivenValue

                 + 1    //AgentFlag

                 + 1    //MorelatetoMTFlag

                 + 1    //Priority

                 + 16   //ExpireTime

                 + 16   //ScheduleTime

                 + 1    //ReportFlag

                 + 1    //TP_pid

                 + 1    //TP_udhi

                 + 1    //MessageCoding

                 + 1    //MessageType

                 + 4    //MessageLength

            //+ Message Length  //MessageContent

                 + 8 ;   //Reserve

        private string _SPNumber;       //21 Octet String   SP的接入号碼

        private string _ChargeNumber;   //21 Octet String   付費号碼,手機号碼前加“86”國别标志

        private uint _UserCount;        //1 Unsigned Integer 接收短消息的手機數量,取值範圍1至100

        private string _UserNumber;     //21 Octet String   接收該短消息的手機号 手機号碼前加“86”國别标志

        private string _CorpId;         //5  Octet String  企業代碼,取值範圍0-99999

        private string _ServiceType;    //10  Octet String  業務代碼,由SP定義

        private uint _FeeType;          //1 Unsigned Integer 計費類型

        private string _FeeValue;       //6  Octet String  取值範圍0-99999,該條短消息的收費值,機關為分,由SP定義對于包月制收費的使用者,該值為月租費的值

        private string _GivenValue;     //6  Octet String  贈送使用者的話費,機關為分

        private uint _AgentFlag;        //1 Unsigned Integer  代收費标志,0:應收;1:實收

        private uint _MorelatetoMTFlag;  //1 Unsigned Integer   引起MT消息的原因

        private uint _Priority;         //1 Unsigned Integer   優先級0-9從低到高,預設為0

        private string _ExpireTime;     //16  Octet String     短消息壽命的終止時間,如果為空,表示使用短消息中心的預設值

        private string _ScheduleTime;   //16  Octet String     短消息定時發送的時間,如果為空,表示立刻發送該短消息

        private uint _ReportFlag;       //1 Unsigned Integer    狀态報告标記

        private uint _TP_pid;           //1 Unsigned Integer

        private uint _TP_udhi;          //1 Unsigned Integer

        private uint _MessageCoding;    //1 Unsigned Integer    短消息的編碼格式

        private uint _MessageType;      //1 Unsigned Integer    資訊類型:0-短消息資訊  其它:待定

        private uint _MessageLength;    //4 Unsigned Integer    短消息的長度

        private string _MessageContent;    // MessageLength Octet String 資訊内容。

        private string _LinkID;

        private MessageHeader _Header;

        private uint _Sequence_Id;

        public SGIP_SUBMIT(uint Sequence_Id)

        {

            this._Sequence_Id = Sequence_Id;

        }

        private byte[] _Msg_Content_Bytes;

        private void SetHeader()

        {

            //byte[] buf;

            switch (this._MessageCoding)

            {

                case 8:

                    _Msg_Content_Bytes = Encoding.BigEndianUnicode.GetBytes(this._MessageContent);

                    break;

                case 15: //gb2312

                    _Msg_Content_Bytes = Encoding.GetEncoding("gb2312").GetBytes(this._MessageContent);

                    break;

                case 0: //ascii

                case 3: //短信寫卡操作

                case 4: //二進制資訊

                default:

                    _Msg_Content_Bytes = Encoding.ASCII.GetBytes(this._MessageContent);

                    break;

            }

            this._MessageLength = (uint)_Msg_Content_Bytes.Length;

            this._BodyLength = (int)(FixedBodyLength + this._MessageLength);

            this._Header = new MessageHeader((uint)(MessageHeader.Length + this._BodyLength), SGIP_Command_Id.SGIP_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;

            //SPNumber //21

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

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

            //ChargeNumber //21

            i += 21;

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

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

            //UserCount //1

            i += 21;

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

            //UserNumber //21

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

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

            //CorpId    //5

            i += 21;

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

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

            //ServiceType;    //10

            i += 5;

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

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

            //FeeType          //1

            i += 10;

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

            //FeeValue   //6

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

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

            //GivenValue    //6

            i += 6;

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

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

            i += 6;

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

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

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

            //ExpireTime;     //16

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

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

            //ScheduleTime;   //16

            i += 16;

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

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

            i += 16;

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

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

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

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

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

            //MessageLength //4

            buffer = BitConverter.GetBytes(this._MessageLength);

            Array.Reverse(buffer);

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

            //Msg_Content

            i += 4;

            Buffer.BlockCopy(this._Msg_Content_Bytes, 0, bytes, i, this._Msg_Content_Bytes.Length);

            //LinkID

            i += (int)this._MessageLength;

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

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

            return bytes;

        }

        public MessageHeader Header

        {

            get

            {

                return _Header;

            }

            set

            {

                _Header = value;

            }

        }

        /// <summary>

        /// SP的接入号碼

        /// </summary>

        public string SPNumber

        {

            get { return _SPNumber; }

            set { _SPNumber = value; }

        }

        /// <summary>

        /// 付費号碼,設定時自動在号碼前加“86”

        /// </summary>

        public string ChargeNumber

        {

            get { return _ChargeNumber; }

            set { _ChargeNumber = value; }

        }

        /// <summary>

        /// 接收短消息的手機數量 ,必須為1

        /// </summary>

        public uint UserCount

        {

            get { return _UserCount; }

            set { _UserCount = value; }

        }

        /// <summary>

        /// 接收該短消息的手機号,設定時自動在号碼前加“86”

        /// </summary>

        public string UserNumber

        {

            get { return _UserNumber; }

            set {

                _UserNumber =value;

            }

        }

        /// <summary>

        /// 企業代碼

        /// </summary>

        public string CorpId

        {

            get { return _CorpId; }

            set { _CorpId = value; }

        }

        /// <summary>

        /// 業務代碼,由SP定義

        /// </summary>

        public string ServiceType

        {

            get { return _ServiceType; }

            set { _ServiceType = value; }

        }

        /// <summary>

        /// 計費類型

        /// </summary>

        public uint FeeType

        {

            get { return _FeeType; }

            set { _FeeType = value; }

        }

        /// <summary>

        /// 該條短消息的收費值,機關為分

        /// </summary>

        public string FeeValue

        {

            get { return _FeeValue; }

            set { _FeeValue = value; }

        }

        public string GivenValue

        {

            get { return _GivenValue; }

            set { _GivenValue = value; }

        }

        /// <summary>

        /// 代收費标志,0:應收;1:實收

        /// </summary>

        public uint AgentFlag

        {

            get { return _AgentFlag; }

            set { _AgentFlag = value; }

        }

        /// <summary>

        /// 引起MT消息的原因

        /// </summary>

        public uint MorelatetoMTFlag

        {

            get { return _MorelatetoMTFlag; }

            set { _MorelatetoMTFlag = value; }

        }

        /// <summary>

        /// 優先級

        /// </summary>

        public uint Priority

        {

            get { return _Priority; }

            set { _Priority = value; }

        }

        /// <summary>

        /// 短消息壽命的終止時間

        /// </summary>

        public string ExpireTime

        {

            get { return _ExpireTime; }

            set { _ExpireTime = value; }

        }

        /// <summary>

        /// 短消息定時發送的時間

        /// </summary>

        public string ScheduleTime

        {

            get { return _ScheduleTime; }

            set { _ScheduleTime = value; }

        }

        /// <summary>

        /// 狀态報告标記

        /// </summary>

        public uint ReportFlag

        {

            get { return _ReportFlag; }

            set { _ReportFlag = 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; }

        }

        /// <summary>

        /// 短消息的編碼格式

        /// </summary>

        public uint MessageCoding

        {

            get { return _MessageCoding; }

            set {

                _MessageCoding = value;

                if (this._MessageContent != null)

                {

                    this.SetHeader();

                }

            }

        }

        /// <summary>

        /// 資訊類型:0-短消息資訊  其它:待定

        /// </summary>

        public uint MessageType

        {

            get { return _MessageType; }

            set { _MessageType = value; }

        }

        /// <summary>

        /// 短消息的長度

        /// </summary>

        public uint MessageLength

        {

            get { return _MessageLength; }

            set { _MessageLength = value; }

        }

        /// <summary>

        /// 短消息的内容

        /// </summary>

        public string MessageContent

        {

            get

            {

                return this._MessageContent;

            }

            set

            {

                this._MessageContent = value;

                this.SetHeader();

            }

        }

        public string LinkID

        {

            get { return _LinkID; }

            set { _LinkID = value; }

        }

        public override string ToString()

        {

            return "[/r/n"

               + this._Header.ToString() + "/r/n"

               + string.Format

               (

                "/tMessageBody:"

                + "/r/n/t/tSPNumber: {0}"

                + "/r/n/t/tChargeNumber: {1}"

                + "/r/n/t/tUserCount: {2}"

                + "/r/n/t/tUserNumber: {3}"

                + "/r/n/t/tCorpId: {4}"

                + "/r/n/t/tServiceType {5}"

                + "/r/n/t/tFeeType: {6}"

                + "/r/n/t/tFeeValue: {7}"

                + "/r/n/t/tGivenValue: {8}"

                + "/r/n/t/tAgentFlag: {9}"

                + "/r/n/t/tMorelatetoMTFlag {10}"

                + "/r/n/t/tPriority: {11}"

                + "/r/n/t/tExpireTime: {12}"

                + "/r/n/t/tScheduleTime: {13}"

                + "/r/n/t/tReportFlag: {14}"

                + "/r/n/t/tTP_pid: {15}"

                + "/r/n/t/tTP_udhi: {16}"

                + "/r/n/t/tMessageCoding: {17}"

                + "/r/n/t/tMessageType: {18}"

                + "/r/n/t/tMessageLength: {19}"

                + "/r/n/t/tMessageContent: {20}"

                + "/r/n/t/tlinkID: {21}"

                + "/r/n/t/tSequence_Id: {22}"

                , this._SPNumber

                , this._ChargeNumber

                , this._UserCount

                , this._UserNumber

                , this._CorpId

                , this._ServiceType

                , this._FeeType

                , this._FeeValue

                , this._GivenValue

                , this._AgentFlag

                , this._MorelatetoMTFlag

                , this._Priority

                , this._ExpireTime

                , this._ScheduleTime

                , this._ReportFlag

                , this._TP_pid

                , this._TP_udhi

                , this._MessageCoding

                , this._MessageType

                , this._MessageLength

                , this._MessageContent

                , this._LinkID

                , this._Sequence_Id

               )

             + "/r/n]";

        }

    }

    public class SGIP_SUBMIT_RESP 

    {

        private MessageHeader _Header;

        private uint _Result;

        private string _Reserve;

        public const int BodyLength = 1 + 8;

        public uint Result

        {

            get

            {

                return this._Result;

            }

        }

        public string Reserve

        {

            get

            {

                return this._Reserve;

            }

        }

        public MessageHeader Header

        {

            get

            {

                return this._Header;

            }

        }

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

            //Result

            i += MessageHeader.Length;

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

            //Reserve;

            buffer = new byte[4];

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

            string s = Encoding.ASCII.GetString(buffer).Trim();

            if (s.IndexOf('/0') > 0)

                s = s.Substring(0, s.IndexOf('/0'));

            this._Reserve = s;

        }

        public override string ToString()

        {

            return "[/r/n"

             + this._Header.ToString() + "/r/n"

             + string.Format

              (

               "/tMessageBody:"

               + "/r/n/t/tResult: {0}"

               + "/r/n/t/tReserve: {1}"

               , this._Result

               , this._Reserve

              )

             + "/r/n]";

        }

    }

    public class SGIP_DELIVER 

    {

        private MessageHeader _Header;

        private string _UserNumber; //發送短消息的使用者手機号,手機号碼前加“86”國别标志

        private string _SPNumber;   //SP的接入号碼

        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 _MessageCoding;

        private uint _MessageLength;

        private string _MessageContent;

        private string _LinkID;

        public const int FixedBodyLength = 21 // UserNumber Octet String    資訊辨別。

                + 21    // SPNumber Octet String SP的接入号碼

                 + 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    // MessageCoding  Unsigned Integer

                 + 4    // MessageLength Unsigned Integer

            //+Message Length // MessageLength Octet String 消息内容。

                + 8;      //LinkID Octet String

        private int _BodyLength;

        public int BodyLength

        {

            get{return this._BodyLength;}

        }

        public SGIP_DELIVER(byte[] bytes)

        {

            int i = 0;

            string s = null;

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

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

            this._Header = new MessageHeader(buffer);

            //UserNumber 21

            i += MessageHeader.Length;

            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._UserNumber = s;

            //SPNumber 21

            i += 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'));

            this._SPNumber = s;

            //

            i += 21;

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

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

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

            //MessageLength 4

            buffer = new byte[4];

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

            Array.Reverse(buffer);

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

            //MessageContent

            i += 4;

            buffer = new byte[this._MessageLength];

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

            switch (this._MessageCoding)

            {

                case 8:

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

                    break;

                case 15: //gb2312

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

                    break;

                case 0: //ascii

                case 3: //短信寫卡操作

                case 4: //二進制資訊

                default:

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

                    break;

            }

            //Linkid 8

            i += (int)this._MessageLength;

            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._LinkID = s;

        }

        public MessageHeader Header

        {

            get

            {

                return this._Header;

            }

        }

        public string UserNumber

        {

            get { return _UserNumber; }

        }

        public string SPNumber

        {

            get { return _SPNumber; }

        }

        public uint TP_pid

        {

            get { return _TP_pid; }

        }

        public uint TP_udhi

        {

            get { return _TP_udhi; }

            set { _TP_udhi = value; }

        }

        public uint MessageCoding

        {

            get { return _MessageCoding; }

        }

        public uint MessageLength

        {

            get { return _MessageLength; }

        }

        public string MessageContent

        {

            get { return _MessageContent; }

        }

        public string LinkID

        {

            get { return _LinkID; }

        }

        public override string ToString()

        {

            return "[/r/n"

             + this._Header.ToString() + "/r/n"

             + string.Format

              (

               "/tMessageBody:"

               + "/r/n/t/tBodyLength: {0}"

               + "/r/n/t/tUserNumber: {1}"

               + "/r/n/t/tTP_pid: {2}"

               + "/r/n/t/tTP_udhi: {3}"

               + "/r/n/t/tMessageCoding: {4}"

               + "/r/n/t/tMessageLength: {5}"

               + "/r/n/t/tMessageContent: {6}"

               + "/r/n/t/tLinkID: {7}"

               , this._BodyLength

               , this._SPNumber

               , this._TP_pid

               , this._TP_udhi

               , this._MessageCoding

               , this._MessageLength

               , this._MessageContent

               , this._LinkID

              )

             + "/r/n]";

        }

    }

    public class SGIP_DELIVER_RESP 

    {

        public const int Bodylength = 1 + 8;

        private MessageHeader _Header;

        private uint _Result;

        private string _Reserve;

        public SGIP_DELIVER_RESP

        (

          uint Result

          , string Reserve

          , uint SrcNodeSequence

          , uint DateSequence

          , uint Sequence_Id

         )

        {

            this._Header = new MessageHeader(MessageHeader.Length + Bodylength, SGIP_Command_Id.SGIP_DELIVER_RESP,SrcNodeSequence,DateSequence,Sequence_Id);

            this._Result = Result;

            this._Reserve = Reserve;

        }

        public byte[] ToBytes()

        {

            int i = 0;

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

            byte[] buffer = this._Header.ToBytes();

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

            i += MessageHeader.Length;

            //Result 1

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

            //Reserve 8

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

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

            return bytes;

        }

        public override string ToString()

        {

            return this._Header.ToString() + "/r/n"

             + string.Format

              (

               "[/r/nMessageBody:"

               + "/r/n/tResult: {0}"

               + "/r/n/tReserve: {1}"

               + "/r/n]"

               , this._Result

               , this._Reserve

              );

        }

    }

    public class SGIP_Report 

    {

        public const int BodyLength = 12 + 1 + 21 + 1 + 1 + 8;

        private MessageHeader _Header;

        private uint _SrcNodeSequence;  //4 Unsigned Integer 源節點的編号

        private uint _DateSequence;     //4 Unsigned Integer 格式為十進制的mmddhhmmss

        private uint _Sequence_Id;    // 4 Unsigned Integer 消息流水号,順序累加,步長為1,循環使用(一對請求和應答消息的流水号必須相同)

        private uint _ReportType;       //1 Unsigned Integer Report指令類型    0:對先前一條Submit指令的狀态報告   1:對先前一條前轉Deliver指令的狀态報告

        private string _UserNumber;     //21 Octet String 接收短消息的手機号,手機号碼前加“86”國别标志

        private uint _State;            //1 Unsigned Integer 該指令所涉及的短消息的目前執行狀态 0:發送成功 1:等待發送 2:發送失敗

        private uint _ErrorCode;        //1 Unsigned Integer 當State=2時為錯誤碼值,否則為0

        private string _Reserve;        //8 Octet String保留,擴充用

        public SGIP_Report(byte[] bytes)

        {

            int i = 0;

            string s = null;

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

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

            this._Header = new MessageHeader(buffer);

            //SrcNodeSequence 4

            i += MessageHeader.Length;

            buffer = new byte[4];

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

            Array.Reverse(buffer);

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

            //DateSequence 4

            i += 4;

            buffer = new byte[4];

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

            Array.Reverse(buffer);

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

            //Sequence_Id 4

            i += 4;

            buffer = new byte[4];

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

            Array.Reverse(buffer);

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

            //ReportType 1

            i += 4;

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

            //UserNumber 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._UserNumber = s;

            //State 1

            i += 21;

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

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

            //Linkid 8

            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._Reserve = s;

        }

        public MessageHeader Header

        {

            get

            {

                return this._Header;

            }

        }

        /// <summary>

        /// 擷取原節點

        /// </summary>

        public uint SrcNodeSequence

        {

            get { return _SrcNodeSequence; }

        }

        /// <summary>

        /// 擷取指令産生的日期和時間

        /// </summary>

        public uint DateSequence

        {

            get { return _DateSequence; }

        }

        /// <summary>

        /// 擷取序列号

        /// </summary>

        public uint Sequence_Id

        {

            get{return this._Sequence_Id;}

        }

        /// <summary>

        /// Report指令類型

        /// </summary>

        public uint ReportType

        {

            get { return _ReportType; }

        }

        /// <summary>

        /// 接收短消息的手機号,手機号碼前加“86”國别标志

        /// </summary>

        public string UserNumber

        {

            get { return _UserNumber; }

        }

        /// <summary>

        /// 該指令所涉及的短消息的目前執行狀态 0:發送成功 1:等待發送 2:發送失敗

        /// </summary>

        public uint State

        {

            get { return _State; }

        }

        /// <summary>

        /// 當State=2時為錯誤碼值,否則為0

        /// </summary>

        public uint ErrorCode

        {

            get { return _ErrorCode; }

        }

        public string Reserve

        {

            get { return _Reserve; }

        }

        public override string ToString()

        {

            return string.Format

              (

               "[/r/nMessageBody:"

               + "/r/n/tBodyLength: {0}"

               + "/r/n/tSrcNodeSequence: {1}"

               + "/r/n/tDateSequence: {2}"

               + "/r/n/tSequence_Id: {3}"

               + "/r/n/tReportType: {4}"

               + "/r/n/tUserNumber: {5}"

               + "/r/n/tState {6}"

               + "/r/n/tErrorCode {7}"

               + "/r/n/tReserve {8}"

               + "/r/n]"

               , SGIP_Report.BodyLength

               , this._SrcNodeSequence

               , this._DateSequence

               , this._Sequence_Id

               , this._ReportType

               , this._UserNumber

               , this._State

               , this._ErrorCode

               , this._Reserve

              );

        }

    }

    public class SGIP_Report_Resp

    {

        public const int Bodylength = 1 + 8;

        private MessageHeader _Header;

        private uint _Result;

        private string _Reserve;

        public SGIP_Report_Resp

        (

          uint Result

          , string Reserve

          , uint SrcNodeSequence

          , uint DateSequence

          , uint Sequence_Id

         )

        {

            this._Header = new MessageHeader(MessageHeader.Length + Bodylength, SGIP_Command_Id.SGIP_REPORT_RESP, SrcNodeSequence, DateSequence, Sequence_Id);

            this._Result = Result;

            this._Reserve = Reserve;

        }

        public byte[] ToBytes()

        {

            int i = 0;

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

            byte[] buffer = this._Header.ToBytes();

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

            i += MessageHeader.Length;

            //Result 1

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

            //Reserve 8

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

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

            return bytes;

        }

        public override string ToString()

        {

            return this._Header.ToString() + "/r/n"

             + string.Format

              (

               "[/r/nMessageBody:"

               + "/r/n/tResult: {0}"

               + "/r/n/tReserve: {1}"

               + "/r/n]"

               , this._Result

               , this._Reserve

              );

        }

    }

    public class SGIP_Unbind_Resp

    {

        private MessageHeader _Header;

        public MessageHeader Header

        {

            get

            {

                return this._Header;

            }

        }

        public SGIP_Unbind_Resp

        (

           uint SrcNodeSequence

          , uint DateSequence

          , uint Sequence_Id

         )

        {

            this._Header = new MessageHeader(MessageHeader.Length, SGIP_Command_Id.SGIP_UNBIND_RESP,SrcNodeSequence,DateSequence,Sequence_Id);

        }

        public byte[] ToBytes()

        {

            return this._Header.ToBytes();

        }

        public override string ToString()

        {

            return this._Header.ToString();

        }

    }

}

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

//檔案StateDictionary.cs

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

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace AsiaINFO.SMS.SGIP

{

    /// <summary>

    /// 狀态字典

    /// </summary>

    public class StateDictionary

    {

        /// <summary>

        /// Status 請求傳回結果。響應包用來向請求包傳回成功資訊或者失敗原因。

        /// </summary>

        /// <param name="state"></param>

        /// <returns></returns>

        public static string stateRespDictionary(uint state)

        {

            string result = "結果:";

            switch (state)

            {

                case 0: result += "無錯誤,指令正确接收"; break;

                case 1: result += "非法登入,如登入名、密碼出錯、登入名與密碼不符等。"; break;

                case 2: result += "重複登入,如在同一TCP/IP連接配接中連續兩次以上請求登入。"; break;

                case 3: result += "連接配接過多,指單個節點要求同時建立的連接配接數過多。"; break;

                case 4: result += "登入類型錯,指bind指令中的logintype字段出錯。"; break;

                case 5: result += "參數格式錯,指指令中參數值與參數類型不符或與協定規定的範圍不符。"; break;

                case 6: result += "非法手機号碼,協定中所有手機号碼字段出現非86130号碼或手機号碼前未加“86”時都應報錯。"; break;

                case 7: result += "消息ID錯"; break;

                case 8: result += "資訊長度錯"; break;

                case 9: result += "非法序列号,包括序列号重複、序列号格式錯誤等"; break;

                case 10: result += "非法操作GNS"; break;

                case 11: result += "節點忙,指本節點存儲隊列滿或其他原因,暫時不能提供服務的情況"; break;

                case 21: result += "目的位址不可達,指路由表存在路由且消息路由正确但被路由的節點暫時不能提供服務的情況"; break;

                case 22: result += "路由錯,指路由表存在路由但消息路由出錯的情況,如轉錯SMG等"; break;

                case 23: result += "路由不存在,指消息路由的節點在路由表中不存在"; break;

                case 24: result += "計費号碼無效,鑒權不成功時回報的錯誤資訊"; break;

                case 25: result += "使用者不能通信(如不在服務區、未開機等情況)"; break;

                case 26: result += "手機記憶體不足"; break;

                case 27: result += "手機不支援短消息"; break;

                case 28: result += "手機接收短消息出現錯誤"; break;

                case 29: result += "不知道的使用者"; break;

                case 30: result += "不提供此功能"; break;

                case 31: result += "非法裝置"; break;

                case 32: result += "系統失敗"; break;

                case 33: result += "短信中心隊列滿"; break;

                default: result = "其它錯誤碼" + state.ToString(); break;

            }

            return result;

        }

    }

    /// <summary>

    /// 計費類别定義

    /// </summary>

    public enum FeeTypes : byte

    {

        /// <summary>

        /// 0 “短消息類型”為“發送”,對“計費使用者号碼”不計資訊費,此類話單僅用于核減SP對稱的信道費

        /// </summary>

        FreeSend = 0,

        /// <summary>

        /// 1 對“計費使用者号碼”免費

        /// </summary>

        Free = 1,

        /// <summary>

        /// 2 對“計費使用者号碼”按條計資訊費

        /// </summary>

        RowNumFee = 2,

        /// <summary>

        /// 3 對“計費使用者号碼”按包月收取資訊費

        /// </summary>

        MonthFee = 3,

        /// <summary>

        /// 4 對“計費使用者号碼”的收費是由SP實作

        /// </summary>

        SpFee = 4,

    }

    /// <summary>

    /// Report 狀态與短消息狀态的映射

    /// </summary>

    public enum ReportStatus : uint

    {

        /// <summary>

        /// 0,發送成功 DELIVERED

        /// </summary>

        Delivered = 0,

        /// <summary>

        /// 1,等待發送 ENROUTE,ACCEPTED

        /// </summary>

        Accepted = 1,

        /// <summary>

        /// 2,發送失敗 EXPIRED,DELETED,UNDELIVERABLE,UNKNOWN,REJECTED

        /// </summary>

        Error = 2,

    }

    public enum ErrorCodes : byte

    {

        /// <summary>

        /// 0 無錯誤,指令正确接收

        /// </summary>

        Success = 0,

        /// <summary>

        /// 1 非法登入,如登入名、密碼出錯、登入名與密碼不符等。

        /// </summary>

        LoginError = 1,

        /// <summary>

        /// 2 重複登入,如在同一TCP/IP連接配接中連續兩次以上請求登入。

        /// </summary>

        Relogon = 2,

        /// <summary>

        /// 3 連接配接過多,指單個節點要求同時建立的連接配接數過多。

        /// </summary>

        ConnectionFull = 3,

        /// <summary>

        /// 4 登入類型錯,指bind指令中的logintype字段出錯。

        /// </summary>

        ErrorLoginType = 4,

        /// <summary>

        /// 5 參數格式錯,指指令中參數值與參數類型不符或與協定規定的範圍不符。

        /// </summary>

        ParameterError = 5,

        /// <summary>

        /// 6 非法手機号碼,協定中所有手機号碼字段出現非86130号碼或手機号碼前未加“86”時都應報錯。

        /// </summary>

        TelnumberError = 6,

        /// <summary>

        /// 7 消息ID錯

        /// </summary>

        MsgIDError = 7,

        /// <summary>

        /// 8 資訊長度錯

        /// </summary>

        PackageLengthError = 8,

        /// <summary>

        /// 9 非法序列号,包括序列号重複、序列号格式錯誤等

        /// </summary>

        SequenceError = 9,

        /// <summary>

        /// 10 非法操作GNS

        /// </summary>

        GnsOperationError = 10,

        /// <summary>

        /// 11 節點忙,指本節點存儲隊列滿或其他原因,暫時不能提供服務的情況

        /// </summary>

        NodeBusy = 11,

        /// <summary>

        /// 21 目的位址不可達,指路由表存在路由且消息路由正确但被路由的節點暫時不能提供服務的情況

        /// </summary>

        NodeCanNotReachable = 21,

        /// <summary>

        /// 22 路由錯,指路由表存在路由但消息路由出錯的情況,如轉錯SMG等

        /// </summary>

        RouteError = 22,

        /// <summary>

        /// 23 路由不存在,指消息路由的節點在路由表中不存在

        /// </summary>

        RoutNodeNotExisted = 23,

        /// <summary>

        /// 24 計費号碼無效,鑒權不成功時回報的錯誤資訊

        /// </summary>

        FeeNumberError = 24,

        /// <summary>

        /// 25 使用者不能通信(如不在服務區、未開機等情況)

        /// </summary>

        UserCanNotReachable = 25,

        /// <summary>

        /// 26 手機記憶體不足

        /// </summary>

        HandsetFull = 26,

        /// <summary>

        /// 27 手機不支援短消息

        /// </summary>

        HandsetCanNotRecvSms = 27,

        /// <summary>

        /// 28 手機接收短消息出現錯誤

        /// </summary>

        HandsetReturnError = 28,

        /// <summary>

        /// 29 不知道的使用者

        /// </summary>

        UnknownUser = 29,

        /// <summary>

        /// 30 不提供此功能

        /// </summary>

        NoDevice = 30,

        /// <summary>

        /// 31 非法裝置

        /// </summary>

        InvalidateDevice = 31,

        /// <summary>

        /// 32 系統失敗

        /// </summary>

        SystemError = 32,

        /// <summary>

        /// 33 短信中心隊列滿

        /// </summary>

        FullSequence = 33,

        /// <summary>

        /// 未知錯誤

        /// </summary>

        OtherError = 99,

    }

    /// <summary>

    /// Bind操作,登入類型。

    /// </summary>

    public enum LoginTypes : byte

    {

        /// <summary>

        /// 1:SP向SMG建立的連接配接,用于發送指令

        /// </summary>

        SpToSmg = 1,

        /// <summary>

        /// 2:SMG向SP建立的連接配接,用于發送指令

        /// </summary>

        SmgToSp = 2,

        /// <summary>

        /// 3:SMG之間建立的連接配接,用于轉發指令

        /// </summary>

        SmgToSmg = 3,

        /// <summary>

        /// 4:SMG向GNS建立的連接配接,用于路由表的檢索和維護

        /// </summary>

        SmgToGns = 4,

        /// <summary>

        /// 5:GNS向SMG建立的連接配接,用于路由表的更新

        /// </summary>

        GnsToSmg = 5,

        /// <summary>

        /// 6:主備GNS之間建立的連接配接,用于主備路由表的一緻性

        /// </summary>

        GnsToGns = 6,

        /// <summary>

        /// 11:SP與SMG以及SMG之間建立的測試連接配接,用于跟蹤測試

        /// </summary>

        Test = 11,

        /// <summary>

        /// 其它:保留

        /// </summary>

        Unknown = 0,

    }

    /// <summary>

    /// 短消息的編碼格式。

    /// </summary>

    public enum MessageCodings : byte

    {

        /// <summary>

        /// 0:純ASCII字元串

        /// </summary>

        Ascii = 0,

        /// <summary>

        /// 3:寫卡操作

        /// </summary>

        WriteCard = 3,

        /// <summary>

        /// 4:二進制編碼

        /// </summary>

        Binary = 4,

        /// <summary>

        /// 8:UCS2編碼

        /// </summary>

        Ucs2 = 8,

        /// <summary>

        /// 15: GBK編碼

        /// </summary>

        Gbk = 15,

        /// <summary>

        /// 其它參見GSM3.38第4節:SMS Data Coding Scheme

        /// </summary>

        Others = 99,

    }

    /// <summary>

    /// 引起MT消息的原因

    /// </summary>

    public enum SubmitMorelatetoMTFlags : byte

    {

        /// <summary>

        /// 0-MO點播引起的第一條MT消息;

        /// </summary>

        VoteFirst = 0,

        /// <summary>

        /// 1-MO點播引起的非第一條MT消息;

        /// </summary>

        VoteNonFirst = 1,

        /// <summary>

        /// 2-非MO點播引起的MT消息;

        /// </summary>

        NormalFirst = 2,

        /// <summary>

        /// 3-系統回報引起的MT消息。

        /// </summary>

        NormalNonFirst = 3,

    }

    /// <summary>

    /// Report指令類型

    /// </summary>

    public enum ReportTypes : byte

    {

        /// <summary>

        /// 0:對先前一條Submit指令的狀态報告

        /// </summary>

        Submit = 0,

        /// <summary>

        /// 1:對先前一條前轉Deliver指令的狀态報告

        /// </summary>

        Deliver = 1,

    }

    /// <summary>

    /// 該指令所涉及的短消息的目前執行狀态

    /// </summary>

    public enum ReportStates : byte

    {

        /// <summary>

        /// 0:發送成功

        /// </summary>

        Success = 0,

        /// <summary>

        /// 1:等待發送

        /// </summary>

        Accepted = 1,

        /// <summary>

        /// 2:發送失敗

        /// </summary>

        Error = 2,

    }

    /// <summary>

    /// 代收費标志,0:應收;1:實收

    /// </summary>

    public enum SubmitAgentFlag : byte

    {

        /// <summary>

        /// 0:應收

        /// </summary>

        SouldIncome = 0,

        /// <summary>

        /// 1:實收

        /// </summary>

        RealIncome = 1,

    }

    /// <summary>

    /// 狀态報告标記

    /// </summary>

    public enum SubmitReportFlag : byte

    {

        /// <summary>

        /// 0-該條消息隻有最後出錯時要傳回狀态報告

        /// </summary>

        ErrorReport = 0,

        /// <summary>

        /// 1-該條消息無論最後是否成功都要傳回狀态報告

        /// </summary>

        Always = 1,

        /// <summary>

        /// 2-該條消息不需要傳回狀态報告

        /// </summary>

        NoReport = 2,

        /// <summary>

        /// 3-該條消息僅攜帶包月計費資訊,不下發給使用者,要傳回狀态報告

        /// </summary>

        MonthReport = 3,

    }

}

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

//檔案SyncEvents.cs

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

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

namespace AsiaINFO.SMS.SGIP

{

    /// <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.SGIP

{

    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;

        }

        public static uint bytes2Uint(byte[] bs, int index)

        {

            byte[] dst = new byte[4];

            Buffer.BlockCopy(bs, index, dst, 0, 4);

            byte num = dst[0];

            dst[0] = dst[3];

            dst[3] = num;

            num = dst[1];

            dst[1] = dst[2];

            dst[2] = num;

            return BitConverter.ToUInt32(dst, 0);

        }

        public static byte[] uint2Bytes(uint u)

        {

            byte[] bytes = BitConverter.GetBytes(u);

            byte num = bytes[0];

            bytes[0] = bytes[3];

            bytes[3] = num;

            num = bytes[1];

            bytes[1] = bytes[2];

            bytes[2] = num;

            return bytes;

        }

    }

}

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

//檔案BaseSortedList.cs

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

using System;

using System.Collections.Generic;

using System.Reflection;

namespace AsiaINFO.SMS.SGIP

{

    public class BaseSortedList<K, V>

    {

        protected SortedList<K, V> m_List;

        protected object m_Lock;

        public BaseSortedList()

        {

            this.m_List = new SortedList<K, V>();

            this.m_Lock = new object();

        }

        public void Add(K key, V Obj)

        {

            if (!this.m_List.ContainsKey(key))

            {

                lock (this.m_Lock)

                {

                    this.m_List.Add(key, Obj);

                }

            }

        }

        public void Remove(K key)

        {

            if (this.m_List.ContainsKey(key))

            {

                lock (this.m_Lock)

                {

                    this.m_List.Remove(key);

                }

            }

        }

        public int Count

        {

            get

            {

                return this.m_List.Count;

            }

        }

        public V this[K key]

        {

            get

            {

                if (this.m_List.ContainsKey(key))

                {

                    return this.m_List[key];

                }

                return default(V);

            }

            set

            {

                lock (this.m_Lock)

                {

                    if (this.m_List.ContainsKey(key))

                    {

                        this.m_List[key] = value;

                    }

                }

            }

        }

        public SortedList<K, V> List

        {

            get

            {

                return this.m_List;

            }

        }

    }

}

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

//檔案ClientQueue.cs

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

using System;

using System.Net.Sockets;

namespace AsiaINFO.SMS.SGIP

{

    public class ClientQueue

    {

        private TcpClient m_tc;

        private DateTime m_Time;

        public ClientQueue(TcpClient tc, DateTime time)

        {

            this.m_tc = tc;

            this.m_Time = time;

        }

        public TcpClient Soc

        {

            get

            {

                return this.m_tc;

            }

        }

        public DateTime Time

        {

            get

            {

                return this.m_Time;

            }

            set

            {

                this.m_Time = value;

            }

        }

    }

}