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;
}
Tiray.SMSTiray.SMSTiray.SMSTiray.SMSTiray.SMSTiray.SMS相关推荐
- java 短信平台_Java通过SMS短信平台实现发短信功能
本程序是通过使用中国网建提供的SMS短信平台实现的(该平台目前为注册用户提供5条免费短信,3条免费彩信,这足够用于我们测试用了.在使用前需要注册,注册地址为http://sms.webchinese. ...
- django-后台sms管理系统的css框架
django-后台sms管理系统的css框架 地址:https://adminlte.io/ 下载代码.使用index.html的页面及相关文件 通过下在线检查adminlte.io的后台的各种模块元 ...
- SMS主站点配置详细图解:Sms2003系列之二
SMS主站点配置 在上一篇文章中,我们介绍了如何进行SMS2003+SP2的部署.本文中,我们将介绍如何进行SMS主站点的配置.在SMS中,站点(site)定义并包含了所有SMS管理的对象.当我们第一 ...
- SMS系列之六:利用SMS实现操作系统的补丁分发
利用SMS实现操作系统的补丁分发 杜 飞 微软的每个操作系统都会不断的推出新的补丁,如Win2000的补丁达到SP4,XP的补丁达到SP3,Win2003也达到了SP2.那么做为一个IT管 ...
- 利用SMS OSD实现win2008操作系统的部署
我们知道SMS是一个强大的桌面操作系统,利用SMS可以实现对客户端的软件.硬件等数据的统计,还可以管理公司的资产等等.那么利用SMS OSD是否能部署出XP.win2003.win2008等操作系 ...
- GSM手机SMS编码解码
有两种方式,一有短信网关,二是通过SMS的DTE-DCE接口标准(AT命令集).我们来讨论一下At命令发送短信,下面是在Siemens M75验证. 一共有三种方式来发送和接收SMS信息:Block ...
- Sms中关于操作系统的部署之上
Sms中关于操作系统的部署之上 在企业中当有新的操作系统上市,我们需要把老的操作系统进行升级,对于网管来说如果方法得当,则会达到事半功倍的效果.比较简单的方法是在服务器上进行统一的部署,再也不用到每一 ...
- LLVM笔记(5) - SMS
1. SMS介绍 SMS(Swing Modulo Scheduling, 摇摆模调度)是一个基于循环的与架构无关的SWP(software pipelining)指令调度框架, 其目的是通过将当 ...
- 替代微软SMS的好工具——Lansweeper
lansweeper安装及使用指南 一. 软件介绍 Lansweeper是一款可以实现对WINDOWS网络里面的计算机软件.硬件以及与资产管理相关的信息收集,功能有点类似于微软的SMS(现在最新版本叫 ...
最新文章
- mysql join order by_MySQL 14 慢查询优化join、order by、group by
- 小朋友也能看懂的机器学习
- java zipinputstream_Java之解压流(ZipInputStream)
- Kong APIGW — OpenResty
- 用java代码实现Singleton_为什么在Java代码中实现Singleton模式(有时)被认为是Java世界中的反模式?...
- 黑马程序员 oc对象的方法成员变量
- 华为P40 Pro Plus:徕卡五摄加持 称霸DxOMark几无悬念
- 概率论 方差公式_【考研数学】概率论与数理统计
- Python调用Tushare抓取上证指数并作初步分析示例
- python3.7读取csv文件_Python3 读取csv文件
- hdu 4004The Frog's Games 二分查找!!!!!!!
- Windows文件同步
- BugFree使用指南
- 10分钟带你学习华为云数据库RDS
- 吐血整理公众号推文制作技巧
- 小米投资美的布局智能家居 董明珠呛声:两个骗子
- 【Luogu1879】玉米田
- 【C++篇】STL常见容器String的模拟实现
- 如何用微信编辑器排版出美观的图文消息
- 网易易盾web端H5接入