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

}

Tiray.SMSTiray.SMSTiray.SMSTiray.SMSTiray.SMSTiray.SMS相关推荐

  1. java 短信平台_Java通过SMS短信平台实现发短信功能

    本程序是通过使用中国网建提供的SMS短信平台实现的(该平台目前为注册用户提供5条免费短信,3条免费彩信,这足够用于我们测试用了.在使用前需要注册,注册地址为http://sms.webchinese. ...

  2. django-后台sms管理系统的css框架

    django-后台sms管理系统的css框架 地址:https://adminlte.io/ 下载代码.使用index.html的页面及相关文件 通过下在线检查adminlte.io的后台的各种模块元 ...

  3. SMS主站点配置详细图解:Sms2003系列之二

    SMS主站点配置 在上一篇文章中,我们介绍了如何进行SMS2003+SP2的部署.本文中,我们将介绍如何进行SMS主站点的配置.在SMS中,站点(site)定义并包含了所有SMS管理的对象.当我们第一 ...

  4. SMS系列之六:利用SMS实现操作系统的补丁分发

    利用SMS实现操作系统的补丁分发 杜 飞       微软的每个操作系统都会不断的推出新的补丁,如Win2000的补丁达到SP4,XP的补丁达到SP3,Win2003也达到了SP2.那么做为一个IT管 ...

  5. 利用SMS OSD实现win2008操作系统的部署

      我们知道SMS是一个强大的桌面操作系统,利用SMS可以实现对客户端的软件.硬件等数据的统计,还可以管理公司的资产等等.那么利用SMS OSD是否能部署出XP.win2003.win2008等操作系 ...

  6. GSM手机SMS编码解码

    有两种方式,一有短信网关,二是通过SMS的DTE-DCE接口标准(AT命令集).我们来讨论一下At命令发送短信,下面是在Siemens M75验证. 一共有三种方式来发送和接收SMS信息:Block ...

  7. Sms中关于操作系统的部署之上

    Sms中关于操作系统的部署之上 在企业中当有新的操作系统上市,我们需要把老的操作系统进行升级,对于网管来说如果方法得当,则会达到事半功倍的效果.比较简单的方法是在服务器上进行统一的部署,再也不用到每一 ...

  8. LLVM笔记(5) - SMS

    1. SMS介绍   SMS(Swing Modulo Scheduling, 摇摆模调度)是一个基于循环的与架构无关的SWP(software pipelining)指令调度框架, 其目的是通过将当 ...

  9. 替代微软SMS的好工具——Lansweeper

    lansweeper安装及使用指南 一. 软件介绍 Lansweeper是一款可以实现对WINDOWS网络里面的计算机软件.硬件以及与资产管理相关的信息收集,功能有点类似于微软的SMS(现在最新版本叫 ...

最新文章

  1. mysql join order by_MySQL 14 慢查询优化join、order by、group by
  2. 小朋友也能看懂的机器学习
  3. java zipinputstream_Java之解压流(ZipInputStream)
  4. Kong APIGW — OpenResty
  5. 用java代码实现Singleton_为什么在Java代码中实现Singleton模式(有时)被认为是Java世界中的反模式?...
  6. 黑马程序员 oc对象的方法成员变量
  7. 华为P40 Pro Plus:徕卡五摄加持 称霸DxOMark几无悬念
  8. 概率论 方差公式_【考研数学】概率论与数理统计
  9. Python调用Tushare抓取上证指数并作初步分析示例
  10. python3.7读取csv文件_Python3 读取csv文件
  11. hdu 4004The Frog's Games 二分查找!!!!!!!
  12. Windows文件同步
  13. BugFree使用指南
  14. 10分钟带你学习华为云数据库RDS
  15. 吐血整理公众号推文制作技巧
  16. 小米投资美的布局智能家居 董明珠呛声:两个骗子
  17. 【Luogu1879】玉米田
  18. 【C++篇】STL常见容器String的模拟实现
  19. 如何用微信编辑器排版出美观的图文消息
  20. 网易易盾web端H5接入

热门文章

  1. python批处理栅格转点_python获取栅格点和面值的实现
  2. C++语法:求vector中的最大值及其位置
  3. dig下载_DIG的完整形式是什么?
  4. 将文件拖到docker容器里,将docke 容器里文件拖到宿主里
  5. mysql主从1594错误_3分钟解决MySQL主从1594错误
  6. UVA 514——Rails
  7. 邮箱验证 ——ACM
  8. ySQL挑战搭建一个简易的成绩管理系统的数据库
  9. C++ 类模板遇到继承的问题以及解决
  10. Redis常见问题及其一些重点知识总结