中国移动短信网关CMPP3.0 C#源代码:CMPP30类(1)

    技术2022-05-11  80

    文章标题】中国移动短信网关CMPP3.0 C#源代码:CMPP30类 (1)【发布日期】2006-05-30【文章作者】Jason              原创不易,引用请注明出处、作者,并保留作者数字签名!【内容摘要】CMPP3.0的C#源代码,支持多线程、滑动窗口、异步发送、全事件模式、自动识别ASCII、GBK、UCS-2

    这是2005年6月云南移动短信网关升级到3.0时写的,在SP那稳定运行了很长时间的。因为SP倒闭了,贴出来给有兴趣的朋友参考。优点:支持多线程、滑动窗口、异步发送、全事件模式、自动识别ASCII、GBK、UCS-2缺点:不支持长短信自动分页、不支持PROVISION接口(偶的PROVISION接口是用WEB SERVICE实现的)

    using System;using System.Text;using System.Runtime.InteropServices;using System.Threading;using System.Collections;using System.Diagnostics;using System.Net.Sockets;using System.Security.Cryptography;

    namespace Tiray.SMS{ /// <summary> /// CMPP30 的摘要说明。 /// </summary> 

     public class CMPP30 {  #region Constants  public const Byte CMPP_VERSION_30   =0x30;  public const Byte CMPP_VERSION_21   =0x20;  public const UInt32 CMD_ERROR    =0xFFFFFFFF;  public const UInt32 CMD_CONNECT    =0x00000001;     public const UInt32 CMD_CONNECT_RESP  =0x80000001;  public const UInt32 CMD_TERMINATE   =0x00000002; // 终止连接  public const UInt32 CMD_TERMINATE_RESP  =0x80000002; // 终止连接应答  public const UInt32 CMD_SUBMIT    =0x00000004; // 提交短信  public const UInt32 CMD_SUBMIT_RESP   =0x80000004; // 提交短信应答  public const UInt32 CMD_DELIVER    =0x00000005; // 短信下发  public const UInt32 CMD_DELIVER_RESP  =0x80000005; // 下发短信应答  public const UInt32 CMD_QUERY    =0x00000006; // 短信状态查询  public const UInt32 CMD_QUERY_RESP   =0x80000006; // 短信状态查询应答  public const UInt32 CMD_CANCEL    =0x00000007; // 删除短信  public const UInt32 CMD_CANCEL_RESP   =0x80000007; // 删除短信应答  public const UInt32 CMD_ACTIVE_TEST   =0x00000008; // 激活测试  public const UInt32 CMD_ACTIVE_TEST_RESP =0x80000008; // 激活测试应答  #endregion

      #region Protected Member Variables;  protected string m_strSPID;//SP企业代码;  protected string m_strPassword;//SP密码;  protected string m_strAddress;//短信网关地址  protected int m_iPort;//短信网关端口号;  protected static UInt32 m_iSeqID=0;//命令的序号

      protected int m_iSlidingWindowSize=16;//滑动窗口大小(W)  protected int m_iActiveTestSpan=150;//ACTIVETEST的时间间隔(C,以秒为单位),标准为180  protected DateTime m_dtLastTransferTime;//最近一次网络传输时间  protected int m_iTimeOut=60;//响应超时时间(T,以秒为单位)  protected int m_iSendCount=3;//最大发送次数(N)  protected DATA_PACKAGE[] SlidingWindow=null;  protected TcpClient m_TcpClient=null;  protected NetworkStream m_NetworkStream=null;  protected Queue m_MessageQueue=null;//消息队列,用于保存所有待发送数据  protected int m_iTcpClientTimeout=5;//TcpClient接收和发送超时(以秒为单位)  protected int m_iSendSpan=10;//发送间隔,以毫秒为单位  #endregion

      #region Worker Thread  protected System.Threading.Thread m_SendThread=null;  protected System.Threading.Thread m_ReceiveThread=null;    protected AutoResetEvent m_eventSendExit=new AutoResetEvent(false);  protected AutoResetEvent m_eventReceiveExit=new AutoResetEvent(false);  protected AutoResetEvent m_eventConnect=new AutoResetEvent(false);  protected AutoResetEvent m_eventDisconnect=new AutoResetEvent(false);  protected ManualResetEvent m_eventSend=new ManualResetEvent(false);  protected ManualResetEvent m_eventReceive=new ManualResetEvent(false);

      protected void SendThreadProc()  {   while(true)   {    if(m_eventSendExit.WaitOne(TimeSpan.FromMilliseconds(0),false))     {     Disconnect();     break;    }    if(m_eventConnect.WaitOne(TimeSpan.FromMilliseconds(0),false))//连接    {     if(Connect())//连接上,开始发送和接收     {      m_eventSend.Set();      m_eventReceive.Set();     }     else     {      Close();      Thread.Sleep(5000);      m_eventConnect.Set();     }    }    if(m_eventDisconnect.WaitOne(TimeSpan.FromMilliseconds(0),false))//拆除连接    {     m_eventSend.Reset();     m_eventReceive.Reset();     Disconnect();     Thread.Sleep(5000);     m_eventConnect.Set();    }    if((m_eventSend.WaitOne(TimeSpan.FromMilliseconds(0),false))&&(m_NetworkStream!=null))    {     bool bOK=true;     ActiveTest();         Monitor.Enter(SlidingWindow);     for(int i=0;i<m_iSlidingWindowSize;i++)//首先用消息队列中的数据填充滑动窗口     {      if(SlidingWindow[i].Status==0)      {       DATA_PACKAGE dp=new DATA_PACKAGE();       dp.Data=null;       Monitor.Enter(m_MessageQueue);       if(m_MessageQueue.Count>0)       {        dp =(DATA_PACKAGE)m_MessageQueue.Dequeue();        SlidingWindow[i]=dp;       }       Monitor.Exit(m_MessageQueue);

          }

         }     for(int i=0;i<m_iSlidingWindowSize;i++)     {      DATA_PACKAGE dp =SlidingWindow[i];      if((dp.Status==1)&&(dp.SendCount==0))//第一次发送      {       bOK=Send(dp);       if((bOK)&&(dp.Command>0x80000000))//发送的是Response类的消息,不需等待Response       {        SlidingWindow[i].Status=0;//清空窗口       }       else if((bOK)&&(dp.Command<0x80000000))//发送的是需要等待Response的消息       {                SlidingWindow[i].SendTime=DateTime.Now;        SlidingWindow[i].SendCount++;       }       else       {        bOK=false;        break;//网络出错       }             }      else if((dp.Status==1)&&(dp.SendCount>0))//第N次发送      {       if(dp.SendCount>m_iSendCount-1)//已发送m_iSendCount次,丢弃数据包       {        SlidingWindow[i].Status=0;//清空窗口        if(dp.Command==CMPP30.CMD_ACTIVE_TEST)//是ActiveTest        {         bOK=false;         break;//ActiveTest出错        }

                   }       else       {        TimeSpan ts=DateTime.Now-dp.SendTime;        if(ts.TotalSeconds>=m_iTimeOut)//超时后未收到回应包        {         bOK=Send(dp);//再次发送         if(bOK)         {          SlidingWindow[i].SendTime=DateTime.Now;          SlidingWindow[i].SendCount++;         }         else         {          bOK=false;          break;//网络出错         }        }       }

          }     }     Monitor.Exit(SlidingWindow);     

         if(!bOK)     {      Close();//关闭连接      Thread.Sleep(5000);//等待5秒      m_eventSend.Reset();      m_eventConnect.Set();     }    }   }

      }  protected void ReceiveThreadProc()  {   while(true)   {    if(m_eventReceiveExit.WaitOne(TimeSpan.FromMilliseconds(0),false))     {     break;    }    if((m_eventReceive.WaitOne(TimeSpan.FromMilliseconds(0),false)&&(m_NetworkStream!=null)))    {     CMPP_HEAD Head=ReadHead();     if(Head.CommandID==CMPP30.CMD_SUBMIT_RESP)     {      ReadSubmitResp(Head);     }     else if(Head.CommandID==CMPP30.CMD_ACTIVE_TEST)     {      ActiveTestResponse(Head.SequenceID);     }     else if(Head.CommandID==CMPP30.CMD_ACTIVE_TEST_RESP)     {      ReadActiveTestResponse(Head);     }     else if(Head.CommandID==CMPP30.CMD_DELIVER)     {      ReadDeliver(Head);     }     else if(Head.CommandID==CMPP30.CMD_ERROR)//网络故障     {      m_eventReceive.Reset();      m_eventDisconnect.Set();     }    }

       }  }  #endregion

      #region Constructor

      public CMPP30(string SPID,string Password,string Address,int Port)  {   m_strSPID=SPID;   m_strPassword=Password;   m_strAddress=Address;   m_iPort=Port;   SlidingWindow=new DATA_PACKAGE[m_iSlidingWindowSize];//初始化滑动窗口   for(int i=0;i<m_iSlidingWindowSize;i++)    SlidingWindow[i]=new DATA_PACKAGE();   m_MessageQueue=new Queue();

      }  #endregion

      #region SMSEvents  public event Tiray.SMS.SMSEventHandler SMSStateChanged;

      protected  void RaiseEvent(SMS_STATE State,Object Data)  {   if(null!=SMSStateChanged)   {    SMSEventArgs e=new SMSEventArgs();    e.Time=DateTime.Now;    e.State=State;    e.Data=Data;    SMSStateChanged(this,e);   }

      }  #endregion

      #region Protected Methods  protected UInt32 TimeStamp(DateTime dt)  {   string str=String.Format("{0:MMddhhmmss}",dt);   return Convert.ToUInt32(str);  }  protected UInt32 CreateID()  {   UInt32 id=m_iSeqID;   m_iSeqID++;   if(m_iSeqID>UInt32.MaxValue)    m_iSeqID=0;   return id;  }  protected Byte[] CreateDigest(DateTime dt)  {   int iLength=25+m_strPassword.Length;   Byte[] btContent=new Byte[iLength];   Array.Clear(btContent,0,iLength);   int iPos=0;   foreach(char ch in m_strSPID)   {    btContent[iPos]=(Byte)ch;    iPos++;   }   iPos+=9;   foreach(char ch in m_strPassword)   {    btContent[iPos]=(Byte)ch;    iPos++;   }   string strTimeStamp=String.Format("{0:MMddhhmmss}",dt);   foreach(char ch in strTimeStamp)   {    btContent[iPos]=(Byte)ch;    iPos++;   }   MD5 md5 = new MD5CryptoServiceProvider();   return md5.ComputeHash(btContent);  }

      protected bool Close()  {   if(m_NetworkStream!=null)    m_NetworkStream.Close();   if(m_TcpClient!=null)    m_TcpClient.Close();      m_TcpClient=null;   m_NetworkStream=null;

       return true;

      }

      protected bool Connect()  {   bool bOK=true;   string strError=string.Empty;   CMPP_CONNECT_RESP resp=new CMPP_CONNECT_RESP();   try   {    m_TcpClient=new TcpClient();    m_TcpClient.ReceiveTimeout=m_TcpClient.SendTimeout=m_iTcpClientTimeout*1000;    m_TcpClient.Connect(m_strAddress,m_iPort);    m_NetworkStream=m_TcpClient.GetStream();        DateTime dt=DateTime.Now;    CMPP_CONNECT conn=new CMPP_CONNECT();    conn.Head=new CMPP_HEAD();    conn.Head.CommandID=CMPP30.CMD_CONNECT;    conn.Head.SequenceID=CreateID();    conn.SourceAddress=m_strSPID;    conn.TimeStamp=TimeStamp(dt);    conn.AuthenticatorSource=CreateDigest(dt);    conn.Version=CMPP_VERSION_30;    Byte[] buffer=conn.GetBuffer();    m_NetworkStream.Write(buffer,0,(Int32)conn.Head.TotalLength);    int iSpan=0;    bool bTimeOut=false;    while(!m_NetworkStream.DataAvailable)//等待RESPONSE 5秒    {     Thread.Sleep(10);     iSpan++;     if(iSpan>500)     {      bTimeOut=true;      break;     }

        }    if(!bTimeOut)    {     CMPP_HEAD Head=ReadHead();     if(Head.CommandID==CMD_CONNECT_RESP)     {      resp=ReadConnectResp(Head);      if(resp.Status==0)       bOK=true;      else      {       bOK=false;       strError="未正确接收CONNECT_RESP";      }     }    }    else     {     bOK=false;     strError="等待CONNECT_RESP超时";    }   }   catch(Exception e)   {    strError=e.Message;    bOK=false;   }

       if(bOK)    RaiseEvent(SMS_STATE.SP_CONNECT,resp);   else    RaiseEvent(SMS_STATE.SP_CONNECT_ERROR,strError);

       return bOK;

      }  protected bool Disconnect()  {   bool bOK=true;   string strError=string.Empty;   try   {    DateTime dt=DateTime.Now;    CMPP_HEAD Head=new CMPP_HEAD();    Head.CommandID=CMPP30.CMD_TERMINATE;    Head.SequenceID=CreateID();    Head.TotalLength=(UInt32)Marshal.SizeOf(Head);    Byte[] buffer=Head.GetBuffer();    m_NetworkStream.Write(buffer,0,(Int32)Head.TotalLength);    int iSpan=0;    bool bTimeOut=false;    while(!m_NetworkStream.DataAvailable)//等待RESPONSE 5秒    {     Thread.Sleep(10);     iSpan++;     if(iSpan>500)     {      bTimeOut=true;      break;     }

        }    if(!bTimeOut)    {     Head=ReadHead();     if(Head.CommandID==CMD_TERMINATE_RESP)      bOK=true;     else     {      bOK=false;      strError="未正确接收TERMINATE_RESP";     }    }    else    {     bOK=false;     strError="等待TERMINATE_RESP超时";    }

       }   catch (Exception ex)   {    bOK=false;    strError=ex.Message;   }   if(m_NetworkStream!=null)    m_NetworkStream.Close();   if(m_TcpClient!=null)    m_TcpClient.Close();   m_TcpClient=null;   m_NetworkStream=null;

       if(bOK)    RaiseEvent(SMS_STATE.SP_DISCONNECT,null);   else    RaiseEvent(SMS_STATE.SP_DISCONNECT_ERROR,strError);

       return bOK;  }  protected bool Send(DATA_PACKAGE dp)  {   bool bOK=true;   string strError=string.Empty;   SMS_STATE state=SMS_STATE.UNKNOW_ERROR;   try   {    Thread.Sleep(m_iSendSpan);    Byte[] btData=null;    if(dp.Command==CMD_ACTIVE_TEST)    {     btData=((CMPP_HEAD)dp.Data).GetBuffer();     state=SMS_STATE.ACTIVE_TEST;    }    else if(dp.Command==CMD_ACTIVE_TEST_RESP)    {     btData=((CMPP_ACTIVE_TEST_RESP)dp.Data).GetBuffer();     state=SMS_STATE.ACTIVE_TEST_RESPONSE;    }    else if(dp.Command==CMD_DELIVER_RESP)    {     btData=((CMPP_DELIVER_RESP)dp.Data).GetBuffer();     state=SMS_STATE.DELIVER_RESPONSE;    }    else if(dp.Command==CMD_SUBMIT)    {     btData=((CMPP_SUBMIT)dp.Data).GetBuffer();     state=SMS_STATE.SUBMIT;    }    m_NetworkStream.Write(btData,0,btData.Length);    m_dtLastTransferTime=DateTime.Now;   }   catch(Exception ex)   {        bOK=false;    strError=ex.Message;   }   if(bOK)   {    RaiseEvent(state,dp.Data);   }   else   {    if(state==SMS_STATE.ACTIVE_TEST)     state=SMS_STATE.ACTIVE_TEST_ERROR;    else if(state==SMS_STATE.ACTIVE_TEST_RESPONSE)     state=SMS_STATE.ACTIVE_TEST_RESPONSE_ERROR;    else if(state==SMS_STATE.DELIVER_RESPONSE)     state=SMS_STATE.DELIVER_RESPONSE_ERROR;    else if(state==SMS_STATE.SUBMIT)     state=SMS_STATE.SUBMIT_ERROR;

        RaiseEvent(state,strError);   }   return bOK;

      } 【待续】

     

    最新回复(0)