using System.Security.Cryptography;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Collections;
namespace CMPP.YOURCOMPANY
{
public delegate void ReportEventHandler(object sender, ReportEventArgs e); //声明一个事件的指代(指针)
public delegate void SMSEventHandler(object sender, SMSEventArgs e); //声明一个事件的指代(指针)
public delegate void TerminateEventHandler(object sender,TerminateEventArgs e); //声明收到终止信号
public delegate void TerminateRespEventHandler(object sender,TerminateRespEventArgs e); //回应事件发生
public delegate void TestEventHandler(object sender,TestEventArgs e);
public delegate void TestRespEventHandler(object sender,TestRespEventArgs e);
public delegate void ConnectRespEventHandler(object sender,ConnectRespEventArgs e);
public delegate void CancelRespEventHandler(object sender,CancelRespEventArgs e);
public delegate void SubmitRespEventHandler(object sender,SubmitRespEventArgs e);
public delegate void QueryRespEventHandler(object sender,QueryRespEventArgs e);
public delegate void LogonSuccEventHandler(object sender,EventArgs e); //当成功登录系统
public delegate void SocketClosedEventHandler(object sender,EventArgs e); //当套接字被检测到关闭
public delegate void FailedItemDeletedEventHandler(object sender,WaitingQueueItemEventArgs e); //当一条等待队列的消息超过60秒没有回应
public delegate void CMPPClientSvcStopEventHandler(object sender, ClientQueueStateArgs e); //当CMPP服务停止时候触发事件
/// <summary>
/// 作为CMPP协议的客户端,具有的登陆、发送、接受功能
/// 会开3 个线程处理: 1、处理需要发送 MO(下行)的消息
/// 2、处理从移动服务器发送过来CMPP的消息
/// 3、处理连接断等信息,检查需要重发的消息,检查收到的报告、短信,并调用 OnReport 事件 OnSMS事件
/// </summary>
public class CMPPClient
{
public static long CMPP_ACTIVE_TEST_C_TICKs= 30 ; // *3 ; //长连接的active_test测试时间
public static long CMPP_ACTIVE_TEST_T_TICKs= 60 ; // 消息失败时间 60秒
public static int CMPP_ACTIVE_TEST_N_COUNT=3; //3次
//public static int CMPP_MSG_MAX=100; //一次取得的最大消息数量
public static int CMPP_Port=7890;
public event ReportEventHandler onReportHandler; //指向事件处理代码的指针
public event SMSEventHandler onSMSHandler; //短信到来处理
public event TestEventHandler onTestHandler;
public event TestRespEventHandler onTestRespHandler;
public event ConnectRespEventHandler onConnectRespHandler;
public event CancelRespEventHandler onCancelRespHandler;
public event TerminateEventHandler onTerminateHandler;
public event TerminateRespEventHandler onTerminateRespHandler;
public event SubmitRespEventHandler onSubmitRespHandler;
public event QueryRespEventHandler onQueryRespHandler;
public event LogonSuccEventHandler onLogonSuccEventHandler;
public event SocketClosedEventHandler onSocketClosedHandler;
public event FailedItemDeletedEventHandler onWaitingItemDeltedHandler; //当等待队列消息超时
public event CMPPClientSvcStopEventHandler onClientSvcStopedHandler; //当服务停止时候的事件
//private 函数区域//
private Socket tcp=null;
private IPHostEntry ip=null;
private IPEndPoint cmpp_ep=null;
private int RecvTimeOut =1000; //2000ms的接受超时
private int SendTimeout =2000; //2000ms的发送超时
private string CMPP_Server=""; //移动的服务器IP或者DNS名
private string systemID=""; //企业编号
private string userName=""; //sp的号码 /企业编号
private string PassWord=""; //口令
private bool isStop=false; //本服务是否终止运行
private bool isLogin=false; //是否已经登录
private Thread Send_Thread; //发送线程,专门处理对移动的数据包
private Thread Recv_Thread; //专门处理接收包
private Thread Deamo_Thread; //监控线程
private string ErrorInfo=""; //存放最后一次发生的错误信息 或者参考信息
private DateTime _current_time=DateTime.Now; //上一次 ping的时间
private uint lastSequence; //流水号,每一次重新启动都需要重新设定 lastSequence
private SortedList _outSeqQueue=new SortedList(); //消息队列存储 QueueItem,存储发送队列中的状态
private SortedList _waitingSeqQueue=new SortedList(); //消息队列存储 QueueItem
private int sub_resp=0; //最后返回的包 Sequence
private DateTime _lastOkTime; //最后正确发送消息时间
private bool _bNre=false; //空引用错误,套接字错误
//private ManualResetEvent _connectionDone=new ManualResetEvent(false); //是否连接到套接字服务器,也就是CMPP服务器
//private ManualResetEvent _lastsendDone=new ManualResetEvent(false); //上一次发送是否完毕
//private ManualResetEvent _lastrecvDone=new ManualResetEvent(false); //上一次接收是否完毕
private void ping() //发送一次ping包 ,不经过_outSeqQueue 直接存储在 out queue中
{
uint seq=this.getNextSequence();
MSG.CMPP_MSG_TEST test=new MSG.CMPP_MSG_TEST(seq);
QueueItem q=new QueueItem(seq,(uint)MSG.CMPP_COMMAND_ID.CMPP_ACTIVE_TEST,0,0);
q.setmsgObj(test);
this.addToOutQueue(q);
}
private string getValIdTime(DateTime d) //返回短信存活时间
{
DateTime n=d.AddHours(2); //2小时
return(n.Year.ToString().Substring(2) + n.Month.ToString().PadLeft(2,'0')+n.Day.ToString().PadLeft(2,'0')+n.Hour.ToString().PadLeft(2,'0')+n.Minute.ToString().PadLeft(2,'0')+n.Second.ToString().PadLeft(2,'0')+"032+");
}
private bool isPingTime( ) //是否到了ping一次的时间
{
System.TimeSpan l=(DateTime.Now - this._current_time );
if ( l.TotalSeconds >= (CMPPClient.CMPP_ACTIVE_TEST_C_TICKs))
{
lock(this)
{
this._current_time =DateTime.Now;
return(true);
}
}
else
{
return(false);
}
}
private void checkReSend() //是否需要再一次ping //查询 _waitingSeqQueue 是否存在 上一次 没有相应的消息
{ //调查waiting queue 中的所有消息,如果入列时间超过60
for(int i=0;i<this._waitingSeqQueue.Count;i++)
{
Thread.Sleep(20);
QueueItem q=(QueueItem)this._waitingSeqQueue.GetByIndex(i);
if(q!=null)
{
DateTime this_time=DateTime.Now ; //去当前时间
TimeSpan t=this_time-q.inQueueTime ;
if(t.TotalSeconds >CMPPClient.CMPP_ACTIVE_TEST_T_TICKs ) //达到超时时间
{//需要重新发送消息
if(q.FailedCount>=CMPPClient.CMPP_ACTIVE_TEST_N_COUNT)
{
//报告消息发送失败
if(this.onWaitingItemDeltedHandler!=null)
{
WaitingQueueItemEventArgs e=new WaitingQueueItemEventArgs(q);
this.onWaitingItemDeltedHandler(this,e);
}
this.delFromWaitingQueue(q); //从等待队列中删除
//q.MsgState =(int)MSG_STATE.SENDED_WAITTING;
}
else
{//可以尝试继续发送
q.inQueueTime = this_time;
q.FailedCount ++ ;
q.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
this.sendQueueItem(q);
}
}
}
}
}
private void startThreads()
{
Deamo_Thread=new Thread(new ThreadStart(this.DeamonThread));
Deamo_Thread.Start();
}
private QueueItem newQueueItem(int msgtype,int msgstate,object msg) //生成一个消息队列成员对象实例
{
uint seq=this.getNextSequence(); //
QueueItem q=new QueueItem(seq,(uint)msgtype,0,msgstate);
q.setmsgObj(msg); //设定消息为 object
return(q);
}
private QueueItem getOutQueueItem(uint seq) //获取MT 队列中的消息项目
{
lock(this)
{
return((QueueItem)this._outSeqQueue[seq]) ;
}
}
private QueueItem getWaitingQueueItem(uint seq) //获取等待队列中的消息
{
return((QueueItem) this._waitingSeqQueue[seq]);
}
private void addToOutQueue(QueueItem q)
{
lock(this)
{
this._outSeqQueue.Add(q.Sequence,q);
}
}
private void addToWaitingQueue(QueueItem q)
{
lock(this)
{
if(!this._waitingSeqQueue.ContainsKey(q.Sequence))
{
this._waitingSeqQueue.Add(q.Sequence,q);
}
}
}
private QueueItem getTopOutQueue() //需要在取之前进行判断
{
for(int i=0;i<this._outSeqQueue.Count;i++)
{
QueueItem q=(QueueItem)this._outSeqQueue.GetByIndex(i);
if(q!=null)
{
if(q.MsgState==(int)MSG_STATE.NEW) //新消息,立即返回
{
lock(this)
{
q.MsgState =(int)MSG_STATE.SENDING; //发送状态
}
return(q);
}
else
{
q=null;
}
}
}
return(null);
}
private ArrayList getTop16Queue() //返回16条最顶的消息
{
int arrlength=0;
ArrayList reArr=new ArrayList() ;
QueueItem q=getTopOutQueue();
while(q!=null || arrlength <= 16)
{
if(q!=null)
{
reArr.Add(q);
arrlength++;
}
else
{
break;
}
q=getTopOutQueue();
}
if(arrlength>0)
{
return(reArr);
}
else
{
return(null);
}
}
private void delFromOutQueue(QueueItem q)
{
lock(this)
{
this._outSeqQueue.Remove(q.Sequence);
}
}
private void delFromOutQueue(uint seq)
{
lock(this)
{
this._outSeqQueue.Remove(seq);
}
}
private void delFromWaitingQueue(QueueItem q)
{
lock(this)
{
this._waitingSeqQueue.Remove(q.Sequence);
}
}
private void delFromWaitingQueue(uint seq)
{
this._waitingSeqQueue.Remove(seq);
}
private void SendLogin(string SystemID,string spNum,string Password)
{//发送登录验证包
systemID=SystemID;
userName=spNum;
PassWord=Password;
uint seq=this.getNextSequence(); //取得一个流水号
MSG.CMPP_MSG_CONNECT cn=new MSG.CMPP_MSG_CONNECT(seq);
cn.Password =Password.Trim();
cn.SourceAdd =SystemID.Trim();
tcp.Send(cn.ToBytes());
}
private byte[] prepairPKs(QueueItem outitem)//将QueueItem发送出去
{
uint seq=outitem.Sequence ;
uint msgtype=outitem.MsgType;
switch(msgtype)
{
case (uint)MSG.CMPP_COMMAND_ID.CMPP_ACTIVE_TEST :
MSG.CMPP_MSG_TEST test=(MSG.CMPP_MSG_TEST) outitem.getMsgObj(); //发送队列中取出
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem); //等待服务器的active_TEST_resp
}
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
return(test.toBytes());
case (uint)MSG.CMPP_COMMAND_ID.CMPP_ACTIVE_TEST_RESP:
MSG.CMPP_MSG_TEST_RESP test_reply=(MSG.CMPP_MSG_TEST_RESP)outitem.getMsgObj(); //发送队列中取出//取出需要发送的具体消息
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
}
outitem.MsgState = (int)MSG_STATE.SENDING_FINISHED ; //完成
return(test_reply.toBytes());
case (uint)MSG.CMPP_COMMAND_ID.CMPP_CANCEL :
MSG.CMPP_MSG_CANCEL cancel=(MSG.CMPP_MSG_CANCEL)outitem.getMsgObj(); //还原成消息类
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem); //等待回应
}
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
return(cancel.toBytes());
case (uint)MSG.CMPP_COMMAND_ID.CMPP_DELIVER_RESP:
MSG.CMPP_MSG_DELIVER_RESP deliver_resp=(MSG.CMPP_MSG_DELIVER_RESP)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
}
outitem.MsgState=(int)MSG_STATE.SENDING_FINISHED ; //完成
return (deliver_resp.toBytes());
case (uint)MSG.CMPP_COMMAND_ID.CMPP_QUERY :
MSG.CMPP_MSG_QUERY query = (MSG.CMPP_MSG_QUERY )outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem);
}
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ; //等待回应
return(query.toBytes());
case (uint)MSG.CMPP_COMMAND_ID.CMPP_SUBMIT :
MSG.CMPP_MSG_SUBMIT submit =(MSG.CMPP_MSG_SUBMIT)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue (outitem);
}
outitem.MsgState =(int)MSG_STATE.SENDING_FINISHED ;
return(submit.toBytes());
case (uint)MSG.CMPP_COMMAND_ID.CMPP_TERMINATE :
MSG.CMPP_MSG_TERMINATE terminate=(MSG.CMPP_MSG_TERMINATE)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem);
}
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
return(terminate.toBytes());
case (uint)MSG.CMPP_COMMAND_ID.CMPP_TERMINATE_RESP :
MSG.CMPP_MSG_TERMINATE_RESP terminate_resp=(MSG.CMPP_MSG_TERMINATE_RESP)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
}
outitem.MsgState =(int)MSG_STATE.SENDING_FINISHED ;
return(terminate_resp.toBytes());
default:
test=(MSG.CMPP_MSG_TEST) outitem.getMsgObj(); //发送队列中取出
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem); //等待服务器的active_TEST_resp
}
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
return(test.toBytes());
}
}
private void sendQueueItem(QueueItem outitem)//将QueueItem发送出去
{
uint seq=outitem.Sequence ;
uint msgtype=outitem.MsgType;
try
{
switch(msgtype)
{
case (uint)MSG.CMPP_COMMAND_ID.CMPP_ACTIVE_TEST :
MSG.CMPP_MSG_TEST test=(MSG.CMPP_MSG_TEST) outitem.getMsgObj(); //发送队列中取出
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem); //等待服务器的active_TEST_resp
}
tcp.Send(test.toBytes());
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
break;
case (uint)MSG.CMPP_COMMAND_ID.CMPP_ACTIVE_TEST_RESP:
MSG.CMPP_MSG_TEST_RESP test_reply=(MSG.CMPP_MSG_TEST_RESP)outitem.getMsgObj(); //发送队列中取出//取出需要发送的具体消息
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
}
tcp.Send(test_reply.toBytes());
outitem.MsgState = (int)MSG_STATE.SENDING_FINISHED ; //完成
break;
case (uint)MSG.CMPP_COMMAND_ID.CMPP_CANCEL :
MSG.CMPP_MSG_CANCEL cancel=(MSG.CMPP_MSG_CANCEL)outitem.getMsgObj(); //还原成消息类
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem); //等待回应
}
tcp.Send(cancel.toBytes());
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
break;
case (uint)MSG.CMPP_COMMAND_ID.CMPP_DELIVER_RESP:
MSG.CMPP_MSG_DELIVER_RESP deliver_resp=(MSG.CMPP_MSG_DELIVER_RESP)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
}
tcp.Send(deliver_resp.toBytes());
outitem.MsgState=(int)MSG_STATE.SENDING_FINISHED ; //完成
break;
case (uint)MSG.CMPP_COMMAND_ID.CMPP_QUERY :
MSG.CMPP_MSG_QUERY query = (MSG.CMPP_MSG_QUERY )outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem);
}
tcp.Send(query.toBytes());
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ; //等待回应
break;
case (uint)MSG.CMPP_COMMAND_ID.CMPP_SUBMIT :
MSG.CMPP_MSG_SUBMIT submit =(MSG.CMPP_MSG_SUBMIT)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue (outitem);
}
tcp.Send(submit.toBytes());
outitem.MsgState =(int)MSG_STATE.SENDING_FINISHED ;
break;
case (uint)MSG.CMPP_COMMAND_ID.CMPP_TERMINATE :
MSG.CMPP_MSG_TERMINATE terminate=(MSG.CMPP_MSG_TERMINATE)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
this.addToWaitingQueue(outitem);
}
if(this.tcpIsCanUse())
{
tcp.Send(terminate.toBytes());
outitem.MsgState =(int)MSG_STATE.SENDED_WAITTING ;
}
this.isStop =true; //通知其他线程可以退出了
break;
case (uint)MSG.CMPP_COMMAND_ID.CMPP_TERMINATE_RESP :
MSG.CMPP_MSG_TERMINATE_RESP terminate_resp=(MSG.CMPP_MSG_TERMINATE_RESP)outitem.getMsgObj(); //发送队列中取出;
lock(this)
{
outitem.MsgState =(int)MSG_STATE.SENDING ;
this.delFromOutQueue(seq);
}
tcp.Send(terminate_resp.toBytes());
outitem.MsgState =(int)MSG_STATE.SENDING_FINISHED ;
break;
}
LogLastOkTime(DateTime.Now ); //记录当前最后一次消息soket正确时间
}
catch(SocketException se)
{
//发生套接字错误
this.ErrorInfo =this.ErrorInfo +"/r/n"+se.ToString ();
}
catch(NullReferenceException nre)
{
this._bNre =true; //出现空引用错误
this.ErrorInfo =this.ErrorInfo +"/r/n"+nre.ToString ();
}
}
private bool tcpIsCanUse() //测试当前tcp是否可用
{
bool reval=true;
DateTime t=DateTime.Now ;
TimeSpan ts=t- this._lastOkTime;
if(ts.TotalSeconds > CMPPClient.CMPP_ACTIVE_TEST_T_TICKs ) //60秒
{
reval=false; //不可用
}
if(this._bNre )
{
reval=false;
}
return(reval);
}
private void _reStartRecvNSend()
{
Send_Thread=new Thread(new ThreadStart(this.SendSPMsgThread));
Send_Thread.Start();
Recv_Thread=new Thread(new ThreadStart(this.RecvISMGMsgThread));
Recv_Thread.Start();
}
private void LogLastOkTime(DateTime lastoktime)
{
lock(this)
{
this._lastOkTime=lastoktime; //设定最后成功消息交互时间
}
}
private void defaultReportHandler() //却省的报告事件处理函数
{
}
private void defaultSMSHandler()
{
}
private void defaultTeminateHandler()
{
}
private void defaultTestEventHandler()
{
}
private void defaultTestRespEventHandler()
{
}
private void defaultTerminateEventHandler()
{
}
private void defaultTerminateRespEventHandler()
{
}
private void defaultCancelRespEventHandler()
{
}
private void defaultQueryRespEventHandler()
{
}
private void defaultConnectRespEventHandler()
{
QueueItem q=new QueueItem(this.getNextSequence(),(uint)MSG.CMPP_COMMAND_ID.CMPP_ACTIVE_TEST,0,(int)MSG_STATE.NEW);
MSG.CMPP_MSG_TEST test=new MSG.CMPP_MSG_TEST(q.Sequence ); //立即发送包过去
q.setmsgObj(test);
this.addToOutQueue(q);
}
private void defaultSubmitRespEventHandler()
{
}
private void defaultClientStopEventHandler()
{}
private void rePortError(string info)
{
}
private bool _init(string CMPPServer,int CMPPPort)
{
bool reVal=false;
CMPP_Server=CMPPServer;
CMPP_Port=CMPPPort;
try
{
tcp=new Socket(AddressFamily.InterNetwork ,SocketType.Stream ,ProtocolType.Tcp );
ip=Dns.GetHostByName(CM