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;

  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/389173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

水文分析提取河网_基于图的河网段地理信息分析排序算法

水文分析提取河网The topic of this article is the application of information technologies in environmental science, namely, in hydrology. Below is a description of the algorithm for ranking rivers and the plugin we implemented for the open-source geographic…

请不要更多的基本情节

“If I see one more basic blue bar plot…”“如果我再看到一个基本的蓝色条形图……” After completing the first module in my studies at Flatiron School NYC, I started playing with plot customizations and design using Seaborn and Matplotlib. Much like doodl…

Powershell-获取DHCP地址租用信息

需求&#xff1a;业务需要获取现阶段DHCP服务器所有地址租用信息。 1.首先查看DHCP相关帮助信息&#xff1a;2.确定执行命令并获取相关帮助信息&#xff1a;help Get-DhcpServerv4Scope 名称 Get-DhcpServerv4Scope 语法 Get-DhcpServerv4Scope [[-ScopeId] <ipaddress[]>…

c# 对COM+对象反射调用时地址参数处理 c# 对COM+对象反射调用时地址参数处理

使用反射的方式调用组件里面的方法&#xff0c;经常会遇见一些象地址参数的处理&#xff0c;在C#中表现为ref参数&#xff0c;比如用C#写了一个装配件&#xff0c;里面有一个方法openProcedure(string ProcName,int paraCount,ref string[] parameters)&#xff0c;最后有一个r…

android触摸消息的派发过程

1.触摸消息是消息获取模块直接派发给应用程序的。 2.触摸消息在处理时&#xff0c; 需要根据触摸坐标计算该消息应该派发给哪个View/ViewGroup, 在案件取消处理中不存在 该计算过程。 3.没有类似”系统按键”的”系统触摸键”&#xff0c; 应用程序可完全控制触摸行为。 4.子…

python 交互式流程图_使用Python创建漂亮的交互式和弦图

python 交互式流程图Python中的数据可视化 (Data Visualization in Python) R vs Python is a constant tussle when it comes to what is the best language, according to data scientists. Though each language has it’s strengths, R, in my opinion has one cutting-edg…

机器学习解决什么问题_机器学习帮助解决水危机

机器学习解决什么问题According to Water.org and Lifewater International, out of 57 million people in Tanzania, 25 million do not have access to safe water. Women and children must travel each day multiple times to gather water when the safety of that water …

递归原来可以so easy|-连载(3)

本期我们再通过几个例子&#xff0c;加深递归的理解和熟练度。 上期有一个练习题&#xff1a;用递归逆序输出一个包含整型数据的链表。 先完成这个练习题。 对于程序员来说&#xff0c;代码是最好的沟通工具&#xff0c;什么都不说&#xff0c;上代码&#xff1a; public class…

Viewport3D 类Viewport3D 类Viewport3D 类

.NET Framework 类库Viewport3D 类更新&#xff1a;2007 年 11 月为三维可视内容提供呈现图面。命名空间&#xff1a; System.Windows.Controls程序集&#xff1a; PresentationFramework&#xff08;在 PresentationFramework.dll 中&#xff09;用于 XAML 的 XMLNS&#xf…

升级android 6.0系统

How to Fix errors by manually flashing Marshmallow update 镜像下载for nexus Factory image Step 1: Download the [Marshmallow factory image](http://www.theandroidsoul.com/download-mra58k-android-6-0-marshmallow-update-released-for-nexus-5-nexus-6-nexus-9-n…

AGC 022 B - GCD Sequence

题面在这里&#xff01; 锻炼脑子的小构造题。。。 一开始被 a[]<30000 且 序列 gcd 1所困扰&#xff0c;但是发现这并没有什么&#xff0c;因为我接下来发现了一种总是能构造出 序列和是6的倍数的方案。 首先如果 n3 的话输出样例&#xff0c;因为只有这种情况没法用我的方…

最接近原点的 k 个点_第K个最接近原点的位置

最接近原点的 k 个点In this article, I will be explaining to you one of the problems that you may find when tackling questions in data structures and algorithm. You will need some basic knowledge of data structures in order to understand the optimized solut…

网络浏览器如何工作

Behind the scenes of modern Web Browsers现代Web浏览器的幕后花絮 The Web Browser is inarguably the most common portal for users to access the web. The advancement of the web browsers (through the series of history) has led many traditional “thick clients”…

让自己的头脑极度开放

为什么80%的码农都做不了架构师&#xff1f;>>> 一. 头脑封闭和头脑开放 头脑封闭 你是否经常有这样的经历&#xff0c;在一次会议或者在一次小组讨论时&#xff0c;当你提出一个观点而被别人否定时&#xff0c;你非常急迫地去反驳别人&#xff0c;从而捍卫自己的尊…

简介DOTNET 编译原理 简介DOTNET 编译原理 简介DOTNET 编译原理

简介DOTNET 编译原理 相信大家都使用过 Dotnet &#xff0c;可能还有不少高手。不过我还要讲讲Dotnet的基础知识&#xff0c;Dotnet的编译原理。 Dotnet是一种建立在虚拟机上执行的语言&#xff0c;它直接生成 MSIL 的中间语言&#xff0c;再由DotNet编译器 JIT 解释映象为本机…

RecyclerView详细了解

关于RecyclerView大家都不陌生了&#xff0c;它的使用也越来越受欢迎&#xff0c;现在总体了解一下RecyclerView的作用&#xff0c;为什么会有RecyclerView呢&#xff0c;我用ListView也能干所有的事情啊&#xff0c;尺有所短&#xff0c;寸有所长&#xff0c;先来看看Recycler…

案例与案例之间的非常规排版

In 1929 the Cond Nast publishing group brought Russian-born Mehemed Fehmy Agha—who had been working for the German edition of Vogue magazine—to America as art director for House & Garden, Vanity Fair, and the senior edition of Vogue.1929年&#xff0c…

熊猫分发_熊猫新手:第二部分

熊猫分发This article is a continuation of a previous article which kick-started the journey to learning Python for data analysis. You can check out the previous article here: Pandas for Newbies: An Introduction Part I.本文是上一篇文章的延续&#xff0c;该文…

浅析微信支付:申请退款、退款回调接口、查询退款

本文是【浅析微信支付】系列文章的第八篇&#xff0c;主要讲解商户如何处理微信申请退款、退款回调、查询退款接口&#xff0c;其中有一些坑的地方&#xff0c;会着重强调。 浅析微信支付系列已经更新七篇了哟&#xff5e;&#xff0c;没有看过的朋友们可以看一下哦。 浅析微信…

view工作原理-计算视图大小的过程(onMeasure)

view的视图有两种情况&#xff1a; 内容型视图&#xff1a;由视图的内容决定其大小。图形型视图&#xff1a;父视图为view动态调整大小。 ### measure的本质 把视图布局使用的“相对值”转化成具体值的过程&#xff0c;即把WRAP_CONTENT,MATCH_PARENT转化为具体的值。 measur…