拆分令牌消息和令牌控制器,多个控制器共用一个令牌统计
This commit is contained in:
parent
0a5f2df77c
commit
59ee67febe
|
@ -25,7 +25,6 @@ protected:
|
|||
|
||||
public:
|
||||
ITransport* Port; // 数据传输口数组
|
||||
//ushort MaxSize; // 最大消息大小
|
||||
byte MinSize; // 最小消息大小
|
||||
bool Opened;
|
||||
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
Message::Message(byte code)
|
||||
{
|
||||
Code = code;
|
||||
Length = 0;
|
||||
Data = nullptr;
|
||||
Reply = false;
|
||||
Error = false;
|
||||
OneWay = false;
|
||||
|
||||
Length = 0;
|
||||
Data = nullptr;
|
||||
|
||||
State = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,9 @@ class Message
|
|||
{
|
||||
public:
|
||||
byte Code; // 消息代码
|
||||
byte Reply; // 是否响应指令
|
||||
byte Error; // 是否错误
|
||||
byte Reply; // 是否响应
|
||||
byte Error; // 是否错误
|
||||
byte OneWay; // 是否单向
|
||||
ushort Length; // 数据长度
|
||||
byte* Data; // 数据。指向子类内部声明的缓冲区
|
||||
|
||||
|
@ -35,7 +36,6 @@ public:
|
|||
virtual bool Clone(const Message& msg);
|
||||
|
||||
// 设置数据
|
||||
//void SetData(const void* buf, uint len, uint offset = 0);
|
||||
void SetData(const Buffer& bs, uint offset = 0);
|
||||
void SetError(byte errorCode, const char* msg = nullptr);
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "Net\Dhcp.h"
|
||||
#include "Net\DNS.h"
|
||||
|
||||
#include "TokenNet\TokenController.h"
|
||||
|
||||
#include "TokenNet\Gateway.h"
|
||||
#include "TokenNet\Token.h"
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "TokenMessage.h"
|
||||
#include "HelloMessage.h"
|
||||
|
||||
#include "TokenNet\TokenController.h"
|
||||
|
||||
class TokenSession;
|
||||
|
||||
// 微网客户端
|
||||
|
|
|
@ -0,0 +1,572 @@
|
|||
#include "Time.h"
|
||||
#include "TokenController.h"
|
||||
|
||||
#include "Net\Net.h"
|
||||
#include "Security\RC4.h"
|
||||
|
||||
#define MSG_DEBUG DEBUG
|
||||
//#define MSG_DEBUG 0
|
||||
|
||||
// 令牌统计
|
||||
class TokenStat : public Object
|
||||
{
|
||||
public:
|
||||
// 发送统计
|
||||
int SendRequest;
|
||||
int RecvReply;
|
||||
int Time;
|
||||
|
||||
String Percent() const; // 成功率百分比,已乘以100
|
||||
int Speed() const; // 平均速度,指令发出到收到响应的时间
|
||||
|
||||
// 接收统计
|
||||
int RecvRequest;
|
||||
int SendReply;
|
||||
int RecvReplyAsync;
|
||||
String PercentReply() const;
|
||||
|
||||
// 数据操作统计
|
||||
int Read;
|
||||
int ReadReply;
|
||||
int Write;
|
||||
int WriteReply;
|
||||
|
||||
TokenStat();
|
||||
~TokenStat();
|
||||
|
||||
void Clear();
|
||||
|
||||
virtual String& ToStr(String& str) const;
|
||||
|
||||
private:
|
||||
TokenStat* _Last;
|
||||
TokenStat* _Total;
|
||||
};
|
||||
|
||||
// 全局的令牌统计指针
|
||||
static TokenStat* Stat = nullptr;
|
||||
|
||||
#if DEBUG
|
||||
static void StatTask(void* param);
|
||||
#endif
|
||||
|
||||
/******************************** TokenController ********************************/
|
||||
|
||||
TokenController::TokenController() : Controller(), Key(0)
|
||||
{
|
||||
Token = 0;
|
||||
|
||||
MinSize = TokenMessage::MinSize;
|
||||
|
||||
Server = nullptr;
|
||||
|
||||
// 默认屏蔽心跳日志和确认日志
|
||||
Buffer(NoLogCodes, sizeof(NoLogCodes)).Clear();
|
||||
NoLogCodes[0] = 0x03;
|
||||
|
||||
_Response = nullptr;
|
||||
|
||||
Buffer(_Queue, ArrayLength(_Queue) * sizeof(_Queue[0])).Clear();
|
||||
}
|
||||
|
||||
TokenController::~TokenController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TokenController::Open()
|
||||
{
|
||||
if(Opened) return;
|
||||
|
||||
assert(Port, "还没有传输口呢");
|
||||
|
||||
debug_printf("TokenNet::Inited 使用传输接口 ");
|
||||
#if DEBUG
|
||||
auto obj = dynamic_cast<Object*>(Port);
|
||||
if(obj) obj->Show(true);
|
||||
//Port->Show(true);
|
||||
#endif
|
||||
|
||||
auto sock = dynamic_cast<ISocket*>(Port);
|
||||
if(sock) Server = &sock->Remote;
|
||||
|
||||
if(!Stat)
|
||||
{
|
||||
Stat = new TokenStat();
|
||||
#if DEBUG
|
||||
Sys.AddTask(StatTask, Stat, 5000, 30000, "令牌统计");
|
||||
#endif
|
||||
}
|
||||
|
||||
Controller::Open();
|
||||
}
|
||||
|
||||
void TokenController::Close()
|
||||
{
|
||||
}
|
||||
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
bool TokenController::Send(byte code, const Buffer& arr)
|
||||
{
|
||||
TokenMessage msg;
|
||||
msg.Code = code;
|
||||
msg.SetData(arr);
|
||||
|
||||
return Send(msg);
|
||||
}
|
||||
|
||||
bool TokenController::Dispatch(Stream& ms, Message* pmsg, void* param)
|
||||
{
|
||||
TokenMessage msg;
|
||||
return Controller::Dispatch(ms, &msg, param);
|
||||
}
|
||||
|
||||
// 收到消息校验后调用该函数。返回值决定消息是否有效,无效消息不交给处理器处理
|
||||
bool TokenController::Valid(const Message& msg)
|
||||
{
|
||||
TS("TokenController::Valid");
|
||||
|
||||
// 代码为0是非法的
|
||||
if(!msg.Code) return false;
|
||||
|
||||
// 握手和登录指令可直接通过
|
||||
if(msg.Code <= 0x02) return true;
|
||||
|
||||
if(Token != 0) return true;
|
||||
|
||||
// 合法来源验证,暂时验证云平台,其它连接将来验证
|
||||
auto svr = (IPEndPoint*)Server;
|
||||
auto rmt = (IPEndPoint*)msg.State;
|
||||
|
||||
if(!rmt || svr && *svr != *rmt)
|
||||
{
|
||||
debug_printf("Token::Valid 非法来源 ");
|
||||
if(rmt) rmt->Show();
|
||||
debug_printf("\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if MSG_DEBUG
|
||||
/*msg_printf("TokenController::Dispatch ");
|
||||
// 输出整条信息
|
||||
ByteArray(buf, ms.Length).Show(true);*/
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Encrypt(Message& msg, const Buffer& pass)
|
||||
{
|
||||
// 加解密。握手不加密,握手响应不加密
|
||||
if(msg.Length > 0 && pass.Length() > 0 && !(msg.Code == 0x01 || msg.Code == 0x08))
|
||||
{
|
||||
Buffer bs(msg.Data, msg.Length);
|
||||
RC4::Encrypt(bs, pass);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 接收处理函数
|
||||
bool TokenController::OnReceive(Message& msg)
|
||||
{
|
||||
TS("TokenController::OnReceive");
|
||||
|
||||
// 如果有等待响应,则交给它
|
||||
if(msg.Reply && _Response && (msg.Code == _Response->Code || msg.Code == 0x08 && msg.Data[0] == _Response->Code))
|
||||
{
|
||||
_Response->SetData(Buffer(msg.Data, msg.Length));
|
||||
_Response->Reply = true;
|
||||
|
||||
// 加解密。握手不加密,登录响应不加密
|
||||
Encrypt(msg, Key);
|
||||
|
||||
ShowMessage("RecvSync", msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(msg.Reply)
|
||||
{
|
||||
bool rs = EndSendStat(msg.Code, true);
|
||||
|
||||
// 如果匹配了发送队列,那么这里不再作为收到响应
|
||||
if(!rs) Stat->RecvReplyAsync++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Stat->RecvRequest++;
|
||||
}
|
||||
|
||||
//ShowMessage("Recv$", msg);
|
||||
|
||||
// 加解密。握手不加密,登录响应不加密
|
||||
Encrypt(msg, Key);
|
||||
|
||||
ShowMessage("Recv", msg);
|
||||
|
||||
return Controller::OnReceive(msg);
|
||||
}
|
||||
|
||||
static byte _Sequence = 0;
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
bool TokenController::Send(Message& msg)
|
||||
{
|
||||
TS("TokenController::Send");
|
||||
// 未登录,登录注册,握手可通过
|
||||
//if(Token == 0&&!( msg.Code <= 0x2||msg.Code == 0x07)) return false;
|
||||
|
||||
//static byte _Sequence = 0;
|
||||
auto& tmsg = (TokenMessage&)msg;
|
||||
// 附上序列号。响应消息保持序列号不变
|
||||
if(!msg.Reply && tmsg.Seq == 0) tmsg.Seq = ++_Sequence;
|
||||
|
||||
if(msg.Reply)
|
||||
ShowMessage("Reply", msg);
|
||||
else
|
||||
ShowMessage("Send", msg);
|
||||
|
||||
// 加解密。握手不加密,登录响应不加密
|
||||
Encrypt(msg, Key);
|
||||
|
||||
// 加入统计
|
||||
if(!msg.Reply) StartSendStat(msg.Code);
|
||||
|
||||
return Controller::Send(msg);
|
||||
}
|
||||
|
||||
// 发送消息并接受响应,msTimeout毫秒超时时间内,如果对方没有响应,会重复发送
|
||||
bool TokenController::SendAndReceive(TokenMessage& msg, int retry, int msTimeout)
|
||||
{
|
||||
TS("TokenController::SendAndReceive");
|
||||
|
||||
#if MSG_DEBUG
|
||||
if(_Response) debug_printf("设计错误!正在等待Code=0x%02X的消息,完成之前不能再次调用\r\n", _Response->Code);
|
||||
|
||||
TimeCost ct;
|
||||
#endif
|
||||
|
||||
if(msg.Reply) return Send(msg) != 0;
|
||||
|
||||
byte code = msg.Code;
|
||||
if(msg.Reply) code |= 0x80;
|
||||
//if(msg.Error) code |= 0x40;
|
||||
if(!msg.Reply && msg.OneWay || msg.Reply && msg.Error) code |= (1 << 6);
|
||||
|
||||
// 加入统计
|
||||
if(!msg.Reply) StartSendStat(msg.Code);
|
||||
|
||||
_Response = &msg;
|
||||
|
||||
bool rs = false;
|
||||
while(retry-- >= 0)
|
||||
{
|
||||
if(!Send(msg)) break;
|
||||
|
||||
// 等待响应
|
||||
TimeWheel tw(0, msTimeout);
|
||||
tw.Sleep = 1;
|
||||
do
|
||||
{
|
||||
if(_Response->Reply)
|
||||
{
|
||||
rs = true;
|
||||
break;
|
||||
}
|
||||
}while(!tw.Expired());
|
||||
if(rs) break;
|
||||
}
|
||||
|
||||
#if MSG_DEBUG
|
||||
debug_printf("Token::SendAndReceive Len=%d Time=%dus ", msg.Size(), ct.Elapsed());
|
||||
if(rs) _Response->Show();
|
||||
debug_printf("\r\n");
|
||||
#endif
|
||||
|
||||
_Response = nullptr;
|
||||
|
||||
EndSendStat(code, rs);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
void TokenController::ShowMessage(const char* action, const Message& msg)
|
||||
{
|
||||
#if MSG_DEBUG
|
||||
TS("TokenController::ShowMessage");
|
||||
|
||||
for(int i=0; i<ArrayLength(NoLogCodes); i++)
|
||||
{
|
||||
if(msg.Code == NoLogCodes[i]) return;
|
||||
if(NoLogCodes[i] == 0) break;
|
||||
}
|
||||
|
||||
debug_printf("Token::%s ", action);
|
||||
|
||||
if(msg.State)
|
||||
{
|
||||
auto svr = (IPEndPoint*)Server;
|
||||
auto rmt = (IPEndPoint*)msg.State;
|
||||
if(!svr || *svr != *rmt)
|
||||
{
|
||||
rmt->Show();
|
||||
debug_printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
msg.Show();
|
||||
|
||||
// 如果是错误,显示错误信息
|
||||
if(msg.Error)
|
||||
{
|
||||
debug_printf("Error=0x%02X ", msg.Data[0]);
|
||||
if(msg.Data[0] == 0x01 && msg.Length - 1 < 0x40)
|
||||
{
|
||||
Stream ms(msg.Data + 1, msg.Length - 1);
|
||||
ms.ReadString().Show(false);
|
||||
}
|
||||
debug_printf("\r\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TokenController::StartSendStat(byte code)
|
||||
{
|
||||
TS("TokenController::StartSendStat");
|
||||
|
||||
auto st = Stat;
|
||||
|
||||
// 仅统计请求信息,不统计响应信息
|
||||
if ((code & 0x80) != 0)
|
||||
{
|
||||
st->SendReply++;
|
||||
return true;
|
||||
}
|
||||
|
||||
st->SendRequest++;
|
||||
byte code2 = code & 0x3F;
|
||||
if (code2 == 0x15 || code2 == 0x05)
|
||||
st->Read++;
|
||||
else if (code2 == 0x16 || code2 == 0x06)
|
||||
st->Write++;
|
||||
|
||||
for(int i=0; i<ArrayLength(_Queue); i++)
|
||||
{
|
||||
if(_Queue[i].Code == 0)
|
||||
{
|
||||
_Queue[i].Code = code;
|
||||
_Queue[i].Time = Sys.Ms();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TokenController::EndSendStat(byte code, bool success)
|
||||
{
|
||||
TS("TokenController::EndSendStat");
|
||||
|
||||
auto st = Stat;
|
||||
|
||||
byte code2 = code & 0x3F;
|
||||
|
||||
for(int i=0; i<ArrayLength(_Queue); i++)
|
||||
{
|
||||
if(_Queue[i].Code == code2)
|
||||
{
|
||||
bool rs = false;
|
||||
if(success)
|
||||
{
|
||||
int cost = (int)(Sys.Ms() - _Queue[i].Time);
|
||||
// 莫名其妙,有时候竟然是负数
|
||||
if(cost < 0) cost = -cost;
|
||||
if(cost < 1000)
|
||||
{
|
||||
st->RecvReply++;
|
||||
st->Time += cost;
|
||||
|
||||
rs = true;
|
||||
}
|
||||
}
|
||||
|
||||
_Queue[i].Code = 0;
|
||||
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
|
||||
if ((code & 0x80) != 0)
|
||||
{
|
||||
if (code2 == 0x15 || code2 == 0x05)
|
||||
st->ReadReply++;
|
||||
else if (code2 == 0x16 || code2 == 0x06)
|
||||
st->WriteReply++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************** TokenStat ********************************/
|
||||
|
||||
TokenStat::TokenStat()
|
||||
{
|
||||
Buffer(&SendRequest, (byte*)&_Total + sizeof(_Total) - (byte*)&SendRequest).Clear();
|
||||
}
|
||||
|
||||
TokenStat::~TokenStat()
|
||||
{
|
||||
if (_Last == nullptr) delete _Last;
|
||||
if (_Total == nullptr) delete _Total;
|
||||
}
|
||||
|
||||
String CaclPercent(int d1, int d2)
|
||||
{
|
||||
String str;
|
||||
if(d2 == 0) return str + "0";
|
||||
|
||||
// 分开处理整数部分和小数部分
|
||||
d1 *= 100;
|
||||
int d = d1 / d2;
|
||||
//d1 %= d2;
|
||||
// %会产生乘减指令MLS,再算一次除法
|
||||
d1 -= d * d2;
|
||||
d1 *= 100;
|
||||
int f = d1 / d2;
|
||||
|
||||
str += d;
|
||||
if(f > 0)
|
||||
{
|
||||
str += ".";
|
||||
if(f < 10) str += "0";
|
||||
str += f;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
String TokenStat::Percent() const
|
||||
{
|
||||
int send = SendRequest;
|
||||
int sucs = RecvReply;
|
||||
if(_Last)
|
||||
{
|
||||
send += _Last->SendRequest;
|
||||
sucs += _Last->RecvReply;
|
||||
}
|
||||
|
||||
return CaclPercent(sucs, send);
|
||||
}
|
||||
|
||||
int TokenStat::Speed() const
|
||||
{
|
||||
int time = Time;
|
||||
int sucs = RecvReply;
|
||||
if(_Last)
|
||||
{
|
||||
time += _Last->Time;
|
||||
sucs += _Last->RecvReply;
|
||||
}
|
||||
if(sucs == 0) return 0;
|
||||
|
||||
return time / sucs;
|
||||
}
|
||||
|
||||
String TokenStat::PercentReply() const
|
||||
{
|
||||
int req = RecvRequest;
|
||||
int rep = SendReply;
|
||||
if(_Last)
|
||||
{
|
||||
req += _Last->RecvRequest;
|
||||
rep += _Last->SendReply;
|
||||
}
|
||||
|
||||
return CaclPercent(rep, req);
|
||||
}
|
||||
|
||||
void TokenStat::Clear()
|
||||
{
|
||||
if (_Last == nullptr) _Last = new TokenStat();
|
||||
if (_Total == nullptr) _Total = new TokenStat();
|
||||
|
||||
_Last->SendRequest = SendRequest;
|
||||
_Last->RecvReply = RecvReply;
|
||||
_Last->SendReply = SendReply;
|
||||
_Last->Time = Time;
|
||||
_Last->RecvRequest = RecvRequest;
|
||||
_Last->RecvReplyAsync = RecvReplyAsync;
|
||||
_Last->Read = Read;
|
||||
_Last->ReadReply = ReadReply;
|
||||
_Last->Write = Write;
|
||||
_Last->WriteReply = WriteReply;
|
||||
|
||||
_Total->SendRequest += SendRequest;
|
||||
_Total->RecvReply += RecvReply;
|
||||
_Total->SendReply += SendReply;
|
||||
_Total->Time += Time;
|
||||
_Total->RecvRequest += RecvRequest;
|
||||
_Total->RecvReplyAsync += RecvReplyAsync;
|
||||
_Total->Read += Read;
|
||||
_Total->ReadReply += ReadReply;
|
||||
_Total->Write += Write;
|
||||
_Total->WriteReply += WriteReply;
|
||||
|
||||
SendRequest = 0;
|
||||
RecvReply = 0;
|
||||
Time = 0;
|
||||
|
||||
SendReply = 0;
|
||||
RecvRequest = 0;
|
||||
RecvReplyAsync = 0;
|
||||
|
||||
Read = 0;
|
||||
ReadReply = 0;
|
||||
Write = 0;
|
||||
WriteReply = 0;
|
||||
}
|
||||
|
||||
String& TokenStat::ToStr(String& str) const
|
||||
{
|
||||
TS("TokenStat::ToStr");
|
||||
assert_ptr(this);
|
||||
|
||||
/*debug_printf("this=0x%08X _Last=0x%08X _Total=0x%08X ", this, _Last, _Total);
|
||||
Percent().Show(true);*/
|
||||
str = str + "发:" + Percent() + "% " + RecvReply + "/" + SendRequest + " " + Speed() + "ms";
|
||||
str = str + " 收:" + PercentReply() + "% " + SendReply + "/" + RecvRequest;
|
||||
if(RecvReplyAsync > 0) str = str + " 异步 " + RecvReplyAsync;
|
||||
if (Read > 0) str = str + " 读:" + (ReadReply * 100 / Read) + " " + ReadReply + "/" + Read;
|
||||
if (Write > 0) str = str + " 写:" + (WriteReply * 100 / Write) + " " + WriteReply + "/" + Write;
|
||||
if(_Total)
|
||||
{
|
||||
str += " 总";
|
||||
_Total->ToStr(str);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
void StatTask(void* param)
|
||||
{
|
||||
TS("TokenController::ShowStat");
|
||||
|
||||
auto st = (TokenStat*)param;
|
||||
|
||||
char cs[128];
|
||||
String str(cs, ArrayLength(cs));
|
||||
st->ToStr(str);
|
||||
str.Show(true);
|
||||
|
||||
st->Clear();
|
||||
|
||||
// 向以太网广播
|
||||
/*auto sock = dynamic_cast<ISocket*>(Port);
|
||||
if(sock)
|
||||
{
|
||||
IPEndPoint ep(IPAddress::Broadcast(), 514);
|
||||
sock->SendTo(str, ep);
|
||||
}*/
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef __TokenController_H__
|
||||
#define __TokenController_H__
|
||||
|
||||
#include "Sys.h"
|
||||
#include "Stream.h"
|
||||
#include "Net\ITransport.h"
|
||||
|
||||
#include "Message\Controller.h"
|
||||
|
||||
#include "TokenMessage.h"
|
||||
|
||||
// 令牌控制器
|
||||
class TokenController : public Controller
|
||||
{
|
||||
private:
|
||||
void* Server; // 服务器结点地址
|
||||
|
||||
protected:
|
||||
virtual bool Dispatch(Stream& ms, Message* pmsg, void* param);
|
||||
// 收到消息校验后调用该函数。返回值决定消息是否有效,无效消息不交给处理器处理
|
||||
virtual bool Valid(const Message& msg);
|
||||
// 接收处理函数
|
||||
virtual bool OnReceive(Message& msg);
|
||||
|
||||
public:
|
||||
uint Token; // 令牌
|
||||
ByteArray Key; // 通信密码
|
||||
|
||||
byte NoLogCodes[8]; // 没有日志的指令
|
||||
|
||||
TokenController();
|
||||
virtual ~TokenController();
|
||||
|
||||
virtual void Open();
|
||||
virtual void Close();
|
||||
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
virtual bool Send(Message& msg);
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
virtual bool Send(byte code, const Buffer& arr);
|
||||
|
||||
// 响应消息
|
||||
private:
|
||||
Message* _Response; // 等待响应的指令
|
||||
|
||||
void ShowMessage(const char* action, const Message& msg);
|
||||
|
||||
public:
|
||||
// 发送消息并接受响应,msTimeout毫秒超时时间内,如果对方没有响应,会重复发送
|
||||
bool SendAndReceive(TokenMessage& msg, int retry = 0, int msTimeout = 20);
|
||||
|
||||
// 统计
|
||||
private:
|
||||
class QueueItem
|
||||
{
|
||||
public:
|
||||
byte Code;
|
||||
UInt64 Time; // 时间ms
|
||||
};
|
||||
|
||||
QueueItem _Queue[16];
|
||||
|
||||
bool StartSendStat(byte code);
|
||||
bool EndSendStat(byte code, bool success);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -14,12 +14,7 @@ TokenMessage::TokenMessage(byte code) : Message(code)
|
|||
{
|
||||
Data = _Data;
|
||||
|
||||
/*_Code = 0;
|
||||
_Reply = 0;
|
||||
_Error = 0;
|
||||
_Length = 0;*/
|
||||
|
||||
OneWay = false;
|
||||
//OneWay = false;
|
||||
Seq = 0;
|
||||
}
|
||||
|
||||
|
@ -134,7 +129,6 @@ void TokenMessage::Show() const
|
|||
debug_printf("$");
|
||||
else
|
||||
debug_printf("#");
|
||||
//debug_printf(" _Code=0x%02X", Code);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -157,578 +151,3 @@ void TokenMessage::Show() const
|
|||
debug_printf("\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************** TokenController ********************************/
|
||||
|
||||
TokenController::TokenController() : Controller(), Key(0)
|
||||
{
|
||||
Token = 0;
|
||||
|
||||
MinSize = TokenMessage::MinSize;
|
||||
//MaxSize = 1500;
|
||||
|
||||
Server = nullptr;
|
||||
|
||||
// 默认屏蔽心跳日志和确认日志
|
||||
Buffer(NoLogCodes, sizeof(NoLogCodes)).Clear();
|
||||
NoLogCodes[0] = 0x03;
|
||||
//NoLogCodes[1] = 0x08;
|
||||
|
||||
_Response = nullptr;
|
||||
|
||||
Stat = nullptr;
|
||||
|
||||
Buffer(_Queue, ArrayLength(_Queue) * sizeof(_Queue[0])).Clear();
|
||||
}
|
||||
|
||||
TokenController::~TokenController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TokenController::Open()
|
||||
{
|
||||
if(Opened) return;
|
||||
|
||||
assert(Port, "还没有传输口呢");
|
||||
|
||||
debug_printf("TokenNet::Inited 使用传输接口 ");
|
||||
#if DEBUG
|
||||
auto obj = dynamic_cast<Object*>(Port);
|
||||
if(obj) obj->Show(true);
|
||||
//Port->Show(true);
|
||||
#endif
|
||||
|
||||
auto sock = dynamic_cast<ISocket*>(Port);
|
||||
if(sock) Server = &sock->Remote;
|
||||
|
||||
if(!Stat)
|
||||
{
|
||||
Stat = new TokenStat();
|
||||
//Stat->Start();
|
||||
//debug_printf("TokenStat::令牌统计 ");
|
||||
#if DEBUG
|
||||
_taskID = Sys.AddTask([](void* param){ ((TokenController*)param)->ShowStat(); }, this, 5000, 30000, "令牌统计");
|
||||
#endif
|
||||
}
|
||||
|
||||
Controller::Open();
|
||||
}
|
||||
|
||||
void TokenController::Close()
|
||||
{
|
||||
delete Stat;
|
||||
Stat = nullptr;
|
||||
|
||||
Sys.RemoveTask(_taskID);
|
||||
}
|
||||
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
bool TokenController::Send(byte code, const Buffer& arr)
|
||||
{
|
||||
TokenMessage msg;
|
||||
msg.Code = code;
|
||||
msg.SetData(arr);
|
||||
|
||||
return Send(msg);
|
||||
}
|
||||
|
||||
bool TokenController::Dispatch(Stream& ms, Message* pmsg, void* param)
|
||||
{
|
||||
TokenMessage msg;
|
||||
return Controller::Dispatch(ms, &msg, param);
|
||||
}
|
||||
|
||||
// 收到消息校验后调用该函数。返回值决定消息是否有效,无效消息不交给处理器处理
|
||||
bool TokenController::Valid(const Message& msg)
|
||||
{
|
||||
TS("TokenController::Valid");
|
||||
|
||||
// 代码为0是非法的
|
||||
if(!msg.Code) return false;
|
||||
|
||||
// 握手和登录指令可直接通过
|
||||
if(msg.Code <= 0x02) return true;
|
||||
|
||||
if(Token != 0) return true;
|
||||
|
||||
// 合法来源验证,暂时验证云平台,其它连接将来验证
|
||||
auto svr = (IPEndPoint*)Server;
|
||||
auto rmt = (IPEndPoint*)msg.State;
|
||||
|
||||
if(!rmt || svr && *svr != *rmt)
|
||||
{
|
||||
debug_printf("Token::Valid 非法来源 ");
|
||||
if(rmt) rmt->Show();
|
||||
debug_printf("\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if MSG_DEBUG
|
||||
/*msg_printf("TokenController::Dispatch ");
|
||||
// 输出整条信息
|
||||
ByteArray(buf, ms.Length).Show(true);*/
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Encrypt(Message& msg, const Buffer& pass)
|
||||
{
|
||||
// 加解密。握手不加密,握手响应不加密
|
||||
if(msg.Length > 0 && pass.Length() > 0 && !(msg.Code == 0x01 || msg.Code == 0x08))
|
||||
{
|
||||
Buffer bs(msg.Data, msg.Length);
|
||||
RC4::Encrypt(bs, pass);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 接收处理函数
|
||||
bool TokenController::OnReceive(Message& msg)
|
||||
{
|
||||
TS("TokenController::OnReceive");
|
||||
|
||||
/*byte code = msg.Code;
|
||||
if(msg.Reply) code |= 0x80;
|
||||
//if(msg.Error) code |= 0x40;
|
||||
if(!msg.Reply && msg.OneWay || msg.Reply && msg.Error) code |= (1 << 6);*/
|
||||
|
||||
/*// 起点和终点节点,收到响应时需要发出确认指令,而收到请求时不需要
|
||||
// 系统指令也不需要确认
|
||||
if(msg.Code >= 0x10 && msg.Code != 0x08)
|
||||
{
|
||||
// 需要为请求发出确认,因为转发以后不知道还要等多久才能收到另一方的响应
|
||||
//if(msg.Reply)
|
||||
{
|
||||
TokenMessage ack;
|
||||
ack.Code = 0x08;
|
||||
ack.Length = 1;
|
||||
ack.Data[0] = code; // 这里考虑最高位
|
||||
|
||||
Reply(ack);
|
||||
}
|
||||
}*/
|
||||
|
||||
// 如果有等待响应,则交给它
|
||||
if(msg.Reply && _Response && (msg.Code == _Response->Code || msg.Code == 0x08 && msg.Data[0] == _Response->Code))
|
||||
{
|
||||
_Response->SetData(Buffer(msg.Data, msg.Length));
|
||||
_Response->Reply = true;
|
||||
|
||||
// 加解密。握手不加密,登录响应不加密
|
||||
Encrypt(msg, Key);
|
||||
|
||||
ShowMessage("RecvSync", msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*// 确认指令已完成使命直接跳出
|
||||
if(msg.Code == 0x08)
|
||||
{
|
||||
if(msg.Length >= 1) EndSendStat(msg.Data[0], true);
|
||||
|
||||
ShowMessage("Recv", msg);
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
if(msg.Reply)
|
||||
{
|
||||
bool rs = EndSendStat(msg.Code, true);
|
||||
|
||||
// 如果匹配了发送队列,那么这里不再作为收到响应
|
||||
if(!rs) Stat->RecvReplyAsync++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Stat->RecvRequest++;
|
||||
}
|
||||
|
||||
//ShowMessage("Recv$", msg);
|
||||
|
||||
// 加解密。握手不加密,登录响应不加密
|
||||
Encrypt(msg, Key);
|
||||
|
||||
ShowMessage("Recv", msg);
|
||||
|
||||
return Controller::OnReceive(msg);
|
||||
}
|
||||
|
||||
static byte _Sequence = 0;
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
bool TokenController::Send(Message& msg)
|
||||
{
|
||||
TS("TokenController::Send");
|
||||
// 未登录,登录注册,握手可通过
|
||||
//if(Token == 0&&!( msg.Code <= 0x2||msg.Code == 0x07)) return false;
|
||||
|
||||
//static byte _Sequence = 0;
|
||||
auto& tmsg = (TokenMessage&)msg;
|
||||
// 附上序列号。响应消息保持序列号不变
|
||||
if(!msg.Reply && tmsg.Seq == 0) tmsg.Seq = ++_Sequence;
|
||||
|
||||
if(msg.Reply)
|
||||
ShowMessage("Reply", msg);
|
||||
else
|
||||
ShowMessage("Send", msg);
|
||||
|
||||
// 加解密。握手不加密,登录响应不加密
|
||||
Encrypt(msg, Key);
|
||||
|
||||
// 加入统计
|
||||
if(!msg.Reply) StartSendStat(msg.Code);
|
||||
|
||||
return Controller::Send(msg);
|
||||
}
|
||||
|
||||
// 发送消息并接受响应,msTimeout毫秒超时时间内,如果对方没有响应,会重复发送
|
||||
bool TokenController::SendAndReceive(TokenMessage& msg, int retry, int msTimeout)
|
||||
{
|
||||
TS("TokenController::SendAndReceive");
|
||||
|
||||
#if MSG_DEBUG
|
||||
if(_Response) debug_printf("设计错误!正在等待Code=0x%02X的消息,完成之前不能再次调用\r\n", _Response->Code);
|
||||
|
||||
TimeCost ct;
|
||||
#endif
|
||||
|
||||
if(msg.Reply) return Send(msg) != 0;
|
||||
|
||||
byte code = msg.Code;
|
||||
if(msg.Reply) code |= 0x80;
|
||||
//if(msg.Error) code |= 0x40;
|
||||
if(!msg.Reply && msg.OneWay || msg.Reply && msg.Error) code |= (1 << 6);
|
||||
|
||||
// 加入统计
|
||||
if(!msg.Reply) StartSendStat(msg.Code);
|
||||
|
||||
_Response = &msg;
|
||||
|
||||
bool rs = false;
|
||||
while(retry-- >= 0)
|
||||
{
|
||||
if(!Send(msg)) break;
|
||||
|
||||
// 等待响应
|
||||
TimeWheel tw(0, msTimeout);
|
||||
tw.Sleep = 1;
|
||||
do
|
||||
{
|
||||
if(_Response->Reply)
|
||||
{
|
||||
rs = true;
|
||||
break;
|
||||
}
|
||||
}while(!tw.Expired());
|
||||
if(rs) break;
|
||||
}
|
||||
|
||||
#if MSG_DEBUG
|
||||
debug_printf("Token::SendAndReceive Len=%d Time=%dus ", msg.Size(), ct.Elapsed());
|
||||
if(rs) _Response->Show();
|
||||
debug_printf("\r\n");
|
||||
#endif
|
||||
|
||||
_Response = nullptr;
|
||||
|
||||
EndSendStat(code, rs);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
void TokenController::ShowMessage(const char* action, const Message& msg)
|
||||
{
|
||||
#if MSG_DEBUG
|
||||
TS("TokenController::ShowMessage");
|
||||
|
||||
for(int i=0; i<ArrayLength(NoLogCodes); i++)
|
||||
{
|
||||
if(msg.Code == NoLogCodes[i]) return;
|
||||
if(NoLogCodes[i] == 0) break;
|
||||
}
|
||||
|
||||
debug_printf("Token::%s ", action);
|
||||
|
||||
if(msg.State)
|
||||
{
|
||||
auto svr = (IPEndPoint*)Server;
|
||||
auto rmt = (IPEndPoint*)msg.State;
|
||||
if(!svr || *svr != *rmt)
|
||||
{
|
||||
rmt->Show();
|
||||
debug_printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
msg.Show();
|
||||
|
||||
// 如果是错误,显示错误信息
|
||||
if(msg.Error)
|
||||
{
|
||||
debug_printf("Error=0x%02X ", msg.Data[0]);
|
||||
if(msg.Data[0] == 0x01 && msg.Length - 1 < 0x40)
|
||||
{
|
||||
Stream ms(msg.Data + 1, msg.Length - 1);
|
||||
ms.ReadString().Show(false);
|
||||
}
|
||||
debug_printf("\r\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TokenController::StartSendStat(byte code)
|
||||
{
|
||||
TS("TokenController::StartSendStat");
|
||||
|
||||
// 仅统计请求信息,不统计响应信息
|
||||
if ((code & 0x80) != 0)
|
||||
{
|
||||
Stat->SendReply++;
|
||||
return true;
|
||||
}
|
||||
|
||||
Stat->SendRequest++;
|
||||
byte code2 = code & 0x3F;
|
||||
if (code2 == 0x15 || code2 == 0x05)
|
||||
Stat->Read++;
|
||||
else if (code2 == 0x16 || code2 == 0x06)
|
||||
Stat->Write++;
|
||||
|
||||
for(int i=0; i<ArrayLength(_Queue); i++)
|
||||
{
|
||||
if(_Queue[i].Code == 0)
|
||||
{
|
||||
_Queue[i].Code = code;
|
||||
_Queue[i].Time = Sys.Ms();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TokenController::EndSendStat(byte code, bool success)
|
||||
{
|
||||
TS("TokenController::EndSendStat");
|
||||
|
||||
byte code2 = code & 0x3F;
|
||||
|
||||
for(int i=0; i<ArrayLength(_Queue); i++)
|
||||
{
|
||||
if(_Queue[i].Code == code2)
|
||||
{
|
||||
bool rs = false;
|
||||
if(success)
|
||||
{
|
||||
int cost = (int)(Sys.Ms() - _Queue[i].Time);
|
||||
// 莫名其妙,有时候竟然是负数
|
||||
if(cost < 0) cost = -cost;
|
||||
if(cost < 1000)
|
||||
{
|
||||
Stat->RecvReply++;
|
||||
Stat->Time += cost;
|
||||
|
||||
rs = true;
|
||||
}
|
||||
}
|
||||
|
||||
_Queue[i].Code = 0;
|
||||
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
|
||||
if ((code & 0x80) != 0)
|
||||
{
|
||||
if (code2 == 0x15 || code2 == 0x05)
|
||||
Stat->ReadReply++;
|
||||
else if (code2 == 0x16 || code2 == 0x06)
|
||||
Stat->WriteReply++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TokenController::ShowStat()
|
||||
{
|
||||
TS("TokenController::ShowStat");
|
||||
|
||||
char cs[128];
|
||||
String str(cs, ArrayLength(cs));
|
||||
//str.Clear();
|
||||
Stat->ToStr(str);
|
||||
str.Show(true);
|
||||
|
||||
Stat->Clear();
|
||||
|
||||
// 向以太网广播
|
||||
auto sock = dynamic_cast<ISocket*>(Port);
|
||||
if(sock)
|
||||
{
|
||||
IPEndPoint ep(IPAddress::Broadcast(), 514);
|
||||
sock->SendTo(str, ep);
|
||||
}
|
||||
}
|
||||
|
||||
/*void TokenController::StatTask(void* param)
|
||||
{
|
||||
auto st = (TokenController*)param;
|
||||
st->ShowStat();
|
||||
}*/
|
||||
|
||||
/******************************** TokenStat ********************************/
|
||||
|
||||
TokenStat::TokenStat()
|
||||
{
|
||||
/*SendRequest = 0;
|
||||
RecvReply = 0;
|
||||
SendReply = 0;
|
||||
Time = 0;
|
||||
RecvRequest = 0;
|
||||
RecvReplyAsync = 0;
|
||||
|
||||
Read = 0;
|
||||
|
||||
_Last = nullptr;
|
||||
_Total = nullptr;*/
|
||||
|
||||
/*int start = offsetof(TokenStat, SendRequest);
|
||||
Buffer((byte*)this + start, sizeof(TokenStat) - start).Clear();*/
|
||||
Buffer(&SendRequest, (byte*)&_Total + sizeof(_Total) - (byte*)&SendRequest).Clear();
|
||||
}
|
||||
|
||||
TokenStat::~TokenStat()
|
||||
{
|
||||
if (_Last == nullptr) delete _Last;
|
||||
if (_Total == nullptr) delete _Total;
|
||||
}
|
||||
|
||||
String CaclPercent(int d1, int d2)
|
||||
{
|
||||
String str;
|
||||
if(d2 == 0) return str + "0";
|
||||
|
||||
// 分开处理整数部分和小数部分
|
||||
d1 *= 100;
|
||||
int d = d1 / d2;
|
||||
//d1 %= d2;
|
||||
// %会产生乘减指令MLS,再算一次除法
|
||||
d1 -= d * d2;
|
||||
d1 *= 100;
|
||||
int f = d1 / d2;
|
||||
|
||||
str += d;
|
||||
if(f > 0)
|
||||
{
|
||||
str += ".";
|
||||
if(f < 10) str += "0";
|
||||
str += f;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
String TokenStat::Percent() const
|
||||
{
|
||||
int send = SendRequest;
|
||||
int sucs = RecvReply;
|
||||
if(_Last)
|
||||
{
|
||||
send += _Last->SendRequest;
|
||||
sucs += _Last->RecvReply;
|
||||
}
|
||||
|
||||
return CaclPercent(sucs, send);
|
||||
}
|
||||
|
||||
int TokenStat::Speed() const
|
||||
{
|
||||
int time = Time;
|
||||
int sucs = RecvReply;
|
||||
if(_Last)
|
||||
{
|
||||
time += _Last->Time;
|
||||
sucs += _Last->RecvReply;
|
||||
}
|
||||
if(sucs == 0) return 0;
|
||||
|
||||
return time / sucs;
|
||||
}
|
||||
|
||||
String TokenStat::PercentReply() const
|
||||
{
|
||||
int req = RecvRequest;
|
||||
int rep = SendReply;
|
||||
if(_Last)
|
||||
{
|
||||
req += _Last->RecvRequest;
|
||||
rep += _Last->SendReply;
|
||||
}
|
||||
|
||||
return CaclPercent(rep, req);
|
||||
}
|
||||
|
||||
void TokenStat::Clear()
|
||||
{
|
||||
if (_Last == nullptr) _Last = new TokenStat();
|
||||
if (_Total == nullptr) _Total = new TokenStat();
|
||||
|
||||
_Last->SendRequest = SendRequest;
|
||||
_Last->RecvReply = RecvReply;
|
||||
_Last->SendReply = SendReply;
|
||||
_Last->Time = Time;
|
||||
_Last->RecvRequest = RecvRequest;
|
||||
_Last->RecvReplyAsync = RecvReplyAsync;
|
||||
_Last->Read = Read;
|
||||
_Last->ReadReply = ReadReply;
|
||||
_Last->Write = Write;
|
||||
_Last->WriteReply = WriteReply;
|
||||
|
||||
_Total->SendRequest += SendRequest;
|
||||
_Total->RecvReply += RecvReply;
|
||||
_Total->SendReply += SendReply;
|
||||
_Total->Time += Time;
|
||||
_Total->RecvRequest += RecvRequest;
|
||||
_Total->RecvReplyAsync += RecvReplyAsync;
|
||||
_Total->Read += Read;
|
||||
_Total->ReadReply += ReadReply;
|
||||
_Total->Write += Write;
|
||||
_Total->WriteReply += WriteReply;
|
||||
|
||||
SendRequest = 0;
|
||||
RecvReply = 0;
|
||||
Time = 0;
|
||||
|
||||
SendReply = 0;
|
||||
RecvRequest = 0;
|
||||
RecvReplyAsync = 0;
|
||||
|
||||
Read = 0;
|
||||
ReadReply = 0;
|
||||
Write = 0;
|
||||
WriteReply = 0;
|
||||
}
|
||||
|
||||
String& TokenStat::ToStr(String& str) const
|
||||
{
|
||||
TS("TokenStat::ToStr");
|
||||
assert_ptr(this);
|
||||
|
||||
/*debug_printf("this=0x%08X _Last=0x%08X _Total=0x%08X ", this, _Last, _Total);
|
||||
Percent().Show(true);*/
|
||||
str = str + "发:" + Percent() + "% " + RecvReply + "/" + SendRequest + " " + Speed() + "ms";
|
||||
str = str + " 收:" + PercentReply() + "% " + SendReply + "/" + RecvRequest;
|
||||
if(RecvReplyAsync > 0) str = str + " 异步 " + RecvReplyAsync;
|
||||
if (Read > 0) str = str + " 读:" + (ReadReply * 100 / Read) + " " + ReadReply + "/" + Read;
|
||||
if (Write > 0) str = str + " 写:" + (WriteReply * 100 / Write) + " " + WriteReply + "/" + Write;
|
||||
if(_Total)
|
||||
{
|
||||
str += " 总";
|
||||
_Total->ToStr(str);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -3,20 +3,14 @@
|
|||
|
||||
#include "Sys.h"
|
||||
#include "Stream.h"
|
||||
#include "Net\ITransport.h"
|
||||
|
||||
#include "Message\Controller.h"
|
||||
#include "Message\Message.h"
|
||||
|
||||
// 令牌消息
|
||||
class TokenMessage : public Message
|
||||
{
|
||||
public:
|
||||
/*byte _Code:6; // 功能码
|
||||
byte _Error:1; // 是否错误
|
||||
byte _Reply:1; // 是否响应指令
|
||||
byte _Length; // 数据长度*/
|
||||
|
||||
byte OneWay; // 单向传输。无应答
|
||||
//byte OneWay; // 单向传输。无应答
|
||||
byte Seq; // 消息序号
|
||||
|
||||
byte _Data[256]; // 数据
|
||||
|
@ -49,104 +43,4 @@ public:
|
|||
virtual void Show() const;
|
||||
};
|
||||
|
||||
class TokenStat;
|
||||
|
||||
// 令牌控制器
|
||||
class TokenController : public Controller
|
||||
{
|
||||
private:
|
||||
void* Server; // 服务器结点地址
|
||||
|
||||
protected:
|
||||
virtual bool Dispatch(Stream& ms, Message* pmsg, void* param);
|
||||
// 收到消息校验后调用该函数。返回值决定消息是否有效,无效消息不交给处理器处理
|
||||
virtual bool Valid(const Message& msg);
|
||||
// 接收处理函数
|
||||
virtual bool OnReceive(Message& msg);
|
||||
|
||||
public:
|
||||
uint Token; // 令牌
|
||||
ByteArray Key; // 通信密码
|
||||
|
||||
byte NoLogCodes[8]; // 没有日志的指令
|
||||
|
||||
TokenController();
|
||||
virtual ~TokenController();
|
||||
|
||||
virtual void Open();
|
||||
virtual void Close();
|
||||
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
virtual bool Send(Message& msg);
|
||||
// 发送消息,传输口参数为空时向所有传输口发送消息
|
||||
virtual bool Send(byte code, const Buffer& arr);
|
||||
|
||||
// 响应消息
|
||||
private:
|
||||
Message* _Response; // 等待响应的指令
|
||||
|
||||
void ShowMessage(const char* action, const Message& msg);
|
||||
|
||||
public:
|
||||
// 发送消息并接受响应,msTimeout毫秒超时时间内,如果对方没有响应,会重复发送
|
||||
bool SendAndReceive(TokenMessage& msg, int retry = 0, int msTimeout = 20);
|
||||
|
||||
// 统计
|
||||
private:
|
||||
TokenStat* Stat;
|
||||
|
||||
uint _taskID;
|
||||
|
||||
void ShowStat();
|
||||
//static void StatTask(void* param);
|
||||
|
||||
class QueueItem
|
||||
{
|
||||
public:
|
||||
byte Code;
|
||||
UInt64 Time; // 时间ms
|
||||
};
|
||||
|
||||
QueueItem _Queue[16];
|
||||
|
||||
bool StartSendStat(byte code);
|
||||
bool EndSendStat(byte code, bool success);
|
||||
};
|
||||
|
||||
// 令牌统计
|
||||
class TokenStat : public Object
|
||||
{
|
||||
public:
|
||||
// 发送统计
|
||||
int SendRequest;
|
||||
int RecvReply;
|
||||
int Time;
|
||||
|
||||
String Percent() const; // 成功率百分比,已乘以100
|
||||
int Speed() const; // 平均速度,指令发出到收到响应的时间
|
||||
|
||||
// 接收统计
|
||||
int RecvRequest;
|
||||
int SendReply;
|
||||
int RecvReplyAsync;
|
||||
String PercentReply() const;
|
||||
|
||||
// 数据操作统计
|
||||
int Read;
|
||||
int ReadReply;
|
||||
int Write;
|
||||
int WriteReply;
|
||||
|
||||
TokenStat();
|
||||
~TokenStat();
|
||||
|
||||
void Clear();
|
||||
|
||||
virtual String& ToStr(String& str) const;
|
||||
|
||||
private:
|
||||
TokenStat* _Last;
|
||||
TokenStat* _Total;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue