拆分令牌消息和令牌控制器,多个控制器共用一个令牌统计
This commit is contained in:
parent
0a5f2df77c
commit
59ee67febe
|
@ -25,7 +25,6 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ITransport* Port; // 数据传输口数组
|
ITransport* Port; // 数据传输口数组
|
||||||
//ushort MaxSize; // 最大消息大小
|
|
||||||
byte MinSize; // 最小消息大小
|
byte MinSize; // 最小消息大小
|
||||||
bool Opened;
|
bool Opened;
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,13 @@
|
||||||
Message::Message(byte code)
|
Message::Message(byte code)
|
||||||
{
|
{
|
||||||
Code = code;
|
Code = code;
|
||||||
Length = 0;
|
|
||||||
Data = nullptr;
|
|
||||||
Reply = false;
|
Reply = false;
|
||||||
Error = false;
|
Error = false;
|
||||||
|
OneWay = false;
|
||||||
|
|
||||||
|
Length = 0;
|
||||||
|
Data = nullptr;
|
||||||
|
|
||||||
State = nullptr;
|
State = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,9 @@ class Message
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
byte Code; // 消息代码
|
byte Code; // 消息代码
|
||||||
byte Reply; // 是否响应指令
|
byte Reply; // 是否响应
|
||||||
byte Error; // 是否错误
|
byte Error; // 是否错误
|
||||||
|
byte OneWay; // 是否单向
|
||||||
ushort Length; // 数据长度
|
ushort Length; // 数据长度
|
||||||
byte* Data; // 数据。指向子类内部声明的缓冲区
|
byte* Data; // 数据。指向子类内部声明的缓冲区
|
||||||
|
|
||||||
|
@ -35,7 +36,6 @@ public:
|
||||||
virtual bool Clone(const Message& msg);
|
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 SetData(const Buffer& bs, uint offset = 0);
|
||||||
void SetError(byte errorCode, const char* msg = nullptr);
|
void SetError(byte errorCode, const char* msg = nullptr);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "Net\Dhcp.h"
|
#include "Net\Dhcp.h"
|
||||||
#include "Net\DNS.h"
|
#include "Net\DNS.h"
|
||||||
|
|
||||||
|
#include "TokenNet\TokenController.h"
|
||||||
|
|
||||||
#include "TokenNet\Gateway.h"
|
#include "TokenNet\Gateway.h"
|
||||||
#include "TokenNet\Token.h"
|
#include "TokenNet\Token.h"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include "TokenMessage.h"
|
#include "TokenMessage.h"
|
||||||
#include "HelloMessage.h"
|
#include "HelloMessage.h"
|
||||||
|
|
||||||
|
#include "TokenNet\TokenController.h"
|
||||||
|
|
||||||
class TokenSession;
|
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;
|
Data = _Data;
|
||||||
|
|
||||||
/*_Code = 0;
|
//OneWay = false;
|
||||||
_Reply = 0;
|
|
||||||
_Error = 0;
|
|
||||||
_Length = 0;*/
|
|
||||||
|
|
||||||
OneWay = false;
|
|
||||||
Seq = 0;
|
Seq = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +129,6 @@ void TokenMessage::Show() const
|
||||||
debug_printf("$");
|
debug_printf("$");
|
||||||
else
|
else
|
||||||
debug_printf("#");
|
debug_printf("#");
|
||||||
//debug_printf(" _Code=0x%02X", Code);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -157,578 +151,3 @@ void TokenMessage::Show() const
|
||||||
debug_printf("\r\n");
|
debug_printf("\r\n");
|
||||||
#endif
|
#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,22 +3,16 @@
|
||||||
|
|
||||||
#include "Sys.h"
|
#include "Sys.h"
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "Net\ITransport.h"
|
|
||||||
|
|
||||||
#include "Message\Controller.h"
|
#include "Message\Message.h"
|
||||||
|
|
||||||
// 令牌消息
|
// 令牌消息
|
||||||
class TokenMessage : public Message
|
class TokenMessage : public Message
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*byte _Code:6; // 功能码
|
//byte OneWay; // 单向传输。无应答
|
||||||
byte _Error:1; // 是否错误
|
|
||||||
byte _Reply:1; // 是否响应指令
|
|
||||||
byte _Length; // 数据长度*/
|
|
||||||
|
|
||||||
byte OneWay; // 单向传输。无应答
|
|
||||||
byte Seq; // 消息序号
|
byte Seq; // 消息序号
|
||||||
|
|
||||||
byte _Data[256]; // 数据
|
byte _Data[256]; // 数据
|
||||||
|
|
||||||
static const uint HeaderSize = 1 + 1 + 1; // 消息头部大小
|
static const uint HeaderSize = 1 + 1 + 1; // 消息头部大小
|
||||||
|
@ -49,104 +43,4 @@ public:
|
||||||
virtual void Show() const;
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue