Tiray.SMSTiray.SMSTiray.SMSTiray.SMSTiray.SMSTiray.SMS

 

这是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;

  }

你可能感兴趣的:(exception,String,cmd,null,byte,sms)