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

文章标题】中国移动短信网关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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CMPP模拟器主要是模拟使用中国移动CMPP协议(版本1.x~3.x)的各种网关。此网关只使用一个收发连接(短信接收和发送在一个链接上进行)。 模拟器要求使用JDK1.4以上的Java运行环境,请确认相关环境已经安装妥当。如果还没有安装Java环境,请访问java.sun.com下载最新J2SE的SDK。 此模拟器已经使用了全新的核心设计,主要针对应用程序的稳定性、可靠性、效率以及配置、管理和监控方面做了很大的调整。基本界面风格和应用功能上没什么变化。 1.建立Socket连接与登陆 使用自己的CMPP客户端程序,与7890端口建立Socket连接。然后按照CMPP协议发送登陆数据包。模拟器会按照协议处理相关连接和登陆过程。 2.发送短信息 正确建立连接和登陆以后,可以按照CMPP协议的Submit过程提交相关数据并得到应答。模拟器在接收到数据以后,会进行解析并按照协议要求进行应答和回复。相关的处理信息会记录在日志文件中。 3.接收短信息 正确建立连接和登陆以后,在同一连接上等待模拟器的Deliver数据包即可,并且要求客户端按照协议给予应答。模拟器会对相关过程记录在日志信息当中。 4.模拟MT以及状态报告过程 发送submit时,请将registered_delivery设置为1即可。 模拟器收到相关数据包以后,会通过submit_response应答给出message_id;随后模拟出deliver数据包给出状态报告,其中registered_delivery为1。 5.模拟MO过程 发送submit时,请将registered_delivery设置为0即可。 模拟器收到相关数据包以后,会通过deliver请求发送模拟的MO。其中deliver的相关数据全部来自接收到的submit数据。包括来源号码、目标号码、业务代码以及信息内容。 6.模拟压力测试 如果需要进行模拟的完整压力测试过程,只需要以最大速度重复步骤5即可。 模拟器的监控 模拟器有一个基于Web监控后台,系统启动的时候同时启动。缺省端口建立在8081上。监控的URL地址、用户名和密码可以在配置文件中找到。 http://localhost:8081 forest_luo root
前 言 4 1 范围 5 2 缩略语 5 3 网络结构 6 4 CMPP功能概述 7 5 协议栈 8 6 通信方式 9 6.1 长连接 9 6.2 短连接 11 6.3 本协议中涉及的端口号 12 6.4 交互过程中的应答方式 12 7 消息定义 12 7.1 基本数据型 12 7.2 消息结构 13 7.3 消息头格式(Message Header) 13 7.4 信息资源站实体(SP)与互联网短信网关(ISMG)间的消息定义 13 7.4.1 SP请求连接到ISMG(CMPP_CONNECT)操作 13 7.4.2 SP或ISMG请求拆除连接(CMPP_TERMINATE)操作 14 7.4.3 SP向ISMG提交短信(CMPP_SUBMIT)操作 15 7.4.4 SP向ISMG查询发送短信状态(CMPP_QUERY)操作 17 7.4.5 ISMG向SP送交短信(CMPP_DELIVER)操作 18 7.4.6 SP向ISMG发起删除短信(CMPP_CANCEL)操作 21 7.4.7 链路检测(CMPP_ACTIVE_TEST)操作 21 7.5 互联网短信网关(ISMG)之间的消息定义 22 7.5.1 源ISMG请求连接到目的ISMG(CMPP_CONNECT)操作 22 7.5.2 源ISMG请求拆除到目的ISMG的连接(CMPP_TERMINATE)操作 22 7.5.3 链路检测(CMPP_ACTIVE_TEST)操作 22 7.5.4 源ISMG向目的ISMG转发短信(CMPP_FWD)操作 22 7.6 互联网短信网关(ISMG)与汇接网关(GNS)之间的消息定义 27 7.6.1 ISMG请求连接到GNS或GNS请求连接到ISMG(CMPP_CONNECT)操作 27 7.6.2 ISMG请求拆除到GNS的连接或GNS请求拆除到ISMG的连接(CMPP_TERMINATE)操作 27 7.6.3 ISMG向汇接网关查询MT路由(CMPP_MT_ROUTE)操作 27 7.6.4 ISMG向汇接网关查询MO路由(CMPP_MO_ROUTE)操作 28 7.6.5 ISMG向汇接网关获取MT路由(CMPP_GET_MT_ROUTE)操作 29 7.6.6 ISMG向汇接网关获取MO路由(CMPP_GET_MO_ROUTE)操作 30 7.6.7 ISMG向汇接网关更新MT路由(CMPP_MT_ROUTE_UPDATE)操作 31 7.6.8 ISMG向汇接网关更新MO路由(CMPP_MO_ROUTE_UPDATE)操作 33 7.6.9 汇接网关向ISMG更新MT路由(CMPP_PUSH_MT_ROUTE_UPDATE)操作 34 7.6.10 汇接网关向ISMG更新MO路由(CMPP_PUSH_MO_ROUTE_UPDATE)操作 35 7.7 系统定义 36 7.7.1 Command_Id定义 36 附录1 MO状态报告的产生 38 修订历史 40

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值