📄 cmppclient.cs
字号:
//附CMPPClient.cs:
/*
作者:TNT 时间:2003年12月
文件说明:本文件实现SP端的协议开发。
*/
using System;
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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -