📄 cngpprotocol.cs
字号:
using System;
using System.Threading;
using System.Collections;
using WriteLog;
using System.Timers;
using System.Text;
using System.Net;
using System.Net.Sockets;
using Pierce.AttributeClass;
namespace Cngp
{
/// <summary>
/// CngpProtocol 协议实现
/// </summary>
[LastModified("2006-01-12","修改从数据库取数据的方法,指定时间限制")]
[LastModified("2006-01-18","更改发送方法,先锁定,后检查有无发送信息,发送采用倒序")]
[LastModified("2006-03-13","修改接收deliver信息的方法,停止while内的do while loop")]
[LastModified("2006-03-14","mt,mo记录使用事件,做界面显示方法")]
[LastModified("2007-02-26","修改Cngp_Deliver_Resp,增加写入状态报告的方法")]
[LastModified("2007-04-03","修改DealSubResp和Cngp_Deliver_Resp,增加处理MsgId的方法")]
internal class CngpProtocol
{
public delegate void MtChangeHandler(object sender,MtchangeEventArgs e);
public static event MtChangeHandler MtOnChange;
public static event MtChangeHandler MoOnChange;
//--------------------------------------------------------------------
/// <summary>
/// cngpsocket 类实例
/// </summary>
private CngpSocket cngpSocket=new CngpSocket();
private CngpMessage cngpMessage=new CngpMessage();
private CngpSendMessage cngpSendMessage=new CngpSendMessage();
/// <summary>
/// 发送信息序列号
/// </summary>
public static uint Sequence=0;
/// <summary>
/// 标示,是否同网关连接
/// </summary>
public bool IsConnectedWithIsmg=false;
/// <summary>
/// 存储Thread的ArrayList
/// </summary>
private ArrayList ThreadArray=new ArrayList(13);
/// <summary>
/// 接收的Mo的数量
/// </summary>
private static uint MOCount=0;
/// <summary>
/// 侦听网关请求的进程
/// </summary>
private Thread threadListen;
/// <summary>
/// Submit后的信息放入的Array,Submit后的信息并不能保证送给了用户
/// 需要从网关收到确认信息
/// </summary>
public static ArrayList submitArray=new ArrayList(19);
/// <summary>
/// 准备发送信息Array,存储从数据库中取出的信息
/// </summary>
public static ArrayList readytoSendArray=new ArrayList(101);
/// <summary>
/// 发送Mt的数量
/// </summary>
private static uint MtCount=0;
/// <summary>
/// 同网关的最后通讯时间
/// </summary>
private DateTime LastTalk=DateTime.MinValue;
/// <summary>
/// 发送数据的Timer
/// </summary>
private System.Timers.Timer timerSendData=new System.Timers.Timer();
/// <summary>
/// 从网关收到的信息,标示是否可以继续发送
/// </summary>
public static bool FeebackOk=true;
/// <summary>
/// 标记已经休眠的时间
/// </summary>
private DateTime SleepTime=DateTime.Now;
/// <summary>
/// 全局退出标志
/// </summary>
public static bool quitFlag=false;
private OraData oradata=new OraData();
/// <summary>
/// 短消息子类型
/// </summary>
public enum SubType
{
Cancel=0, //取消订阅
Request=1, //订阅或者点播请求
MODeliver=2,//点播下发
MTDeliver=3 //订阅下发
}
/// <summary>
/// 是否要求返回状态报告
/// </summary>
public enum NeedReport:byte
{
Need=1, //要求状态报告
NotNeed=0 //不要求状态报告
}
/// <summary>
/// 发送优先级
/// </summary>
public enum Priority:byte
{
Low=0, //最低
Normal=1, //正常
High=2, //高
Emegency=3 //最高
}
/// <summary>
/// 资费类型
/// </summary>
public enum FeeType:byte
{
Free=0, //免费
MO=1, //按条收费
MT=2, //包月
Top=3, //封顶
MtFee=4, //包月请求扣费
CR=5 //cr话单
}
/// <summary>
/// 计费用户类型
/// </summary>
public enum FeeUserType:byte
{
Dest=0, //对目的终端计费
Source=1, //对源终端计费
SP=2, //对sp计费
FeeMobile=3//按照计费用户号码计费
}
/// <summary>
/// 信息头的Command_Status值
/// </summary>
public enum Command_Status:uint
{
Success=0, //成功
SystemBusy=1, //系统忙
OverMaxConnection=2, //超过最大连接数
MessageStructError=10, //消息结构错
CommandError=11, //命令字错
SequenceDouble=12, //序列号重复
IPAddressError=20, //ip地址错
AuthenError=21, //认证错
VersionTooHigh=22, //版本太高
InvalidFeeUserType=23, //非法FeeUserType
InvalidSubType=24, //非法SubType
OverNodesCount=25, //NodesCount超过阙值
InvalidMsgID=26, //非法msgId
InvalidSMType=30, //非法smtype
InvalidPriority=31, //非法优先级
InvalidFeeType=32, //非法Feetype
InvalidFeeCode=33, //非法FeeCode
InvalidMsgFormat=34, //非法MsgFormat
InvalidTimeFormat=35, //非法时间格式
InvalidMsgLength=36, //非法消息长度
Expire=37, //有效期已过
InvalidQueryType=38, //非法查询类别
NoRoute=39, //路由错误
NoMobileId=40, //帐户不存在
NoYuE=41, //余额不足
InvalidMobile=42, //帐户不可用
NoPrePayUser=43 //非预付费用户
}
/// <summary>
/// 属性,只读,返回最后通话时间
/// </summary>
public DateTime LastTime
{
get{return LastTalk;}
}
/// <summary>
/// 构造函数 ,初始化自定义变量
/// </summary>
public CngpProtocol()
{
InitializeCompnent();
}
/// <summary>
/// 初始化信息发送timer,设置timer的事件
/// </summary>
private void InitializeCompnent()
{
//
//发送数据Timer,设定参数
//
timerSendData.Interval=Convert.ToInt32(ConfigInformation.Sendspeed);
timerSendData.Elapsed+=new ElapsedEventHandler(timerSendData_Elapsed);
timerSendData.Enabled=false;
}
/// <summary>
/// Connect方法
/// 如果成功,启动发送进程,接收进程
/// </summary>
/// <param name="user">网关设置的用户名</param>
/// <param name="password">网关设置的密码</param>
/// <param name="ipAddr" >网关IP地址</param>
/// <param name="port" >网关端口</param>
[LastModified("2006-03-13","Connect网关的方法")]
public bool Cngp_Login(string user,string password,string ipAddr,int port)
{
//Socket Connect
cngpSocket.Init(ipAddr,port);
//-----------------------------------Authentication-----------------
//authen数组
byte[] bsAuthen=new byte[17+password.Length+user.Length];
//当前时间,格式化为时间戳
string timeStamp=string.Concat(new string[]{
DateTime.Now.Month.ToString("00"),
DateTime.Now.Day.ToString("00"),
DateTime.Now.Hour.ToString("00"),
DateTime.Now.Minute.ToString("00"),
DateTime.Now.Second.ToString("00")});
//7字节的0
byte[] SevenZero=new byte[7];
int i=0;//cursor
cngpMessage.AddToBuffer(ref bsAuthen,ref i,user,user.Length,CngpMessage.Character.ASCII);
cngpMessage.AddToBuffer(ref bsAuthen,ref i,SevenZero);
cngpMessage.AddToBuffer(ref bsAuthen,ref i,password,password.Length,CngpMessage.Character.ASCII);
cngpMessage.AddToBuffer(ref bsAuthen,ref i,timeStamp,10,CngpMessage.Character.ASCII);
//md5
byte[] Authen=cngpMessage.MD5CryptoGraphy(bsAuthen);
//------------------------------------------------------------------------
//-----------------------------body----------------------------------------
byte[] MessageBody=new byte[32];
byte Version=32;
byte LoginMode=2;
int j=0;//cursor
cngpMessage.AddToBuffer(ref MessageBody,ref j,user,10,CngpMessage.Character.ASCII);
cngpMessage.AddToBuffer(ref MessageBody,ref j,Authen);
cngpMessage.AddToBuffer(ref MessageBody,ref j,LoginMode);
cngpMessage.AddToBuffer(ref MessageBody,ref j,int.Parse(timeStamp));
cngpMessage.AddToBuffer(ref MessageBody,ref j,Version);
//---------------------------------------------------------------------------
//----------------Pack-----------------------------------------------------
uint Command=(uint)CngpMessage.Command_Id.login;
byte[] Message=null;
uint CommandStatus=0;
cngpMessage.Pack(Command,CommandStatus,sequence(),MessageBody,ref Message);
//send
int sendbytes=cngpSocket.SendToIsmg(Message);
//receive
byte[] PartMessage=null;
uint Length=0;
uint receivebytes=cngpSocket.ReceiveFromIsmg(ref PartMessage,ref Length);
uint reCommandId=0;
uint reSequence=0;
uint reCommand_Status=0;
byte[] reMessageBody=null;
cngpMessage.UnPack(Length,ref reCommandId,ref reCommand_Status,ref reSequence,ref reMessageBody,PartMessage);
#if DEBUG
Logs.writeLog("commandstatus:"+reCommand_Status.ToString());
#endif
//--------------------------------------------------------------------------------
//如果验证成功,标记连接成功,记录日志
if(reCommandId==(uint)CngpMessage.Command_Id.login_resp && reCommand_Status==0)
{
//Mark连接标记
IsConnectedWithIsmg=true;
//lastTalk
this.RenewTime();
//
//启动发送时钟
//
timerSendData.Start();
//
//启动接收进程
//
threadListen=new Thread(new ThreadStart(ReceiveData));
threadListen.Start();
ThreadArray.Add(threadListen);
//返回
return true;
}
else
{
return false;
}
}
/// <summary>
/// 发送数据的timerSendData的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
[LastModified("2006-01-18","Lock发送对列后,再检查有没有发送信息,保证一致性,"+
"发送为倒序发送")]
private void timerSendData_Elapsed(object sender,ElapsedEventArgs e)
{
try
{
//
//如果信息集合中的信息数小于100,那么发送信息
//采用倒序,发送信息
//发送信息完成后,设置发送参数,加入提交Array
//先锁定readytoSendArray,再检查有没有需要发送的信息
//保证一致性
//
SendInfo sendInfo=null;
uint Sequence=0;
lock(readytoSendArray)
{
if(submitArray.Count<100 && readytoSendArray.Count>0)
{
sendInfo=(SendInfo)readytoSendArray[readytoSendArray.Count-1];
//发送结构的值
SendStruct(sendInfo,ref Sequence);
//从Array中删除
readytoSendArray.RemoveAt(readytoSendArray.Count-1);
}
}
if(sendInfo!=null)
{
//设置发送参数,加入提交Array
sendInfo.Times=1;
sendInfo.DealTime=DateTime.Now;
sendInfo.Sequence=Sequence;
lock(submitArray)
{
submitArray.Add(sendInfo);
}
}
}
catch(Exception ex)
{
Logs.writeLog(string.Concat(
ex.Message,
"\r\n",
ex.StackTrace,
"\r\n",
ex.TargetSite.ToString(),
"\r\n",
ex.Source),false);
}
}
/// <summary>
/// 如果在已经Submit的信息Array中还存在没有收到回复的信息,
/// 那么根据设置的等待时间和发送次数,再次Submit
/// </summary>
[LastModified("2005-12-19","根据设置的等待时间和发送次数,重发信息函数")]
[LastModified("2006-01-06","此方法由Represend Class调用,while循环被终止时,"
+"报错误,一直没有解决")]
[LastModified("2006-03-13","使用全局变量退出循环")]
public void CheckSubmit()
{
while(true)
{
try
{
//
//如果全局退出标志为true,那么停止循环
//
if(quitFlag==true)
{
break;
}
//
//
//
lock(submitArray)
{
if(submitArray.Count>0)
{
for(int i=submitArray.Count-1;i>=0;i--)
{
//在提交Array中的信息
SendInfo sendinfo=(SendInfo)submitArray[i];
//时间间隔
TimeSpan span=DateTime.Now-sendinfo.DealTime;
if( sendinfo.Times<2 && span.TotalSeconds>10)
{
SendStruct(sendinfo); //重新发送
sendinfo.Times++; //更新发送次数
sendinfo.DealTime=DateTime.Now; //更新发送时间
Logs.writeLog(sendinfo.Mobileid,"resend"); //记录日志
}
else if(sendinfo.Times>=2)
{
submitArray.Remove(sendinfo);
Logs.writeLog(sendinfo.Mobileid.Trim()+":"+sendinfo.ServiceId.Trim()+":"+sendinfo.Content.Trim(),false);
//
//发送失败信息写入数据库
//2007-02-26
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -