完善物联协议,登录请求Json数据包成功发给服务端并收到

This commit is contained in:
大石头 2017-08-20 23:38:53 +08:00
parent 1abdedef5a
commit 0bd0d82c8c
6 changed files with 215 additions and 71 deletions

View File

@ -26,12 +26,7 @@ LinkClient::LinkClient()
Delay = 0;
MaxNotActive = 0;
NextReport = -1;
ReportLength = 0;
_Expect = nullptr;
assert(!Current, "只能有一个令牌客户端实例");
assert(!Current, "只能有一个物联客户端实例");
Current = this;
}
@ -42,7 +37,7 @@ void LinkClient::Open()
TS("LinkClient::Open");
// 令牌客户端定时任务
_task = Sys.AddTask(&LinkClient::LoopTask, this, 0, 1000, "令牌客户");
_task = Sys.AddTask(&LinkClient::LoopTask, this, 0, 1000, "物联客户");
// 启动时记为最后一次活跃接收
LastActive = Sys.Ms();
@ -55,24 +50,89 @@ void LinkClient::Close()
if (!Opened) return;
Sys.RemoveTask(_task);
//Sys.RemoveTask(_taskBroadcast);
Opened = false;
}
bool LinkClient::Send(LinkMessage& msg) {
return false;
void LinkClient::CheckNet()
{
auto mst = Master;
// 检测主链接
if (!mst)
{
auto uri = Server;
// 创建连接服务器的Socket
auto socket = Socket::CreateRemote(uri);
if (!socket) return;
Master = socket;
debug_printf("LinkClient::CheckNet %s 成功创建主连接\r\n", socket->Host->Name);
// 已连接时,减慢网络检查速度
Sys.SetTaskPeriod(_task, 5000);
}
// 检测主链接是否已经断开
else if (!mst->Host->Linked)
{
debug_printf("LinkClient::CheckNet %s断开切换主连接\r\n", mst->Host->Name);
delete mst;
Master = nullptr;
Status = 0;
// 未连接时,加快网络检查速度
Sys.SetTaskPeriod(_task, 1000);
}
}
bool LinkClient::Invoke(String& action, String& args) {
// 定时任务
void LinkClient::LoopTask()
{
TS("LinkClient::LoopTask");
// 最大不活跃时间ms超过该时间时重启系统
// WiFi触摸开关建议5~10分钟网关建议5分钟
// MaxNotActive 为零便不考虑重启
if (MaxNotActive != 0 && LastActive + MaxNotActive < Sys.Ms()) Sys.Reboot();
CheckNet();
if (!Master) return;
// 状态。0准备、1握手完成、2登录后
switch (Status)
{
case 0:
Login();
// 登录成功后,心跳一次,把数据同步上去
Sys.Sleep(1000);
if (Status >= 2) Ping();
break;
case 2:
Ping();
break;
}
}
bool LinkClient::Send(const LinkMessage& msg) {
return Master->Send(msg.GetString());
}
bool LinkClient::Invoke(const String& action, const String& args) {
// 消息缓冲区,跳过头部
char cs[512];
String str(&cs[sizeof(LinkMessage)], sizeof(cs) - sizeof(LinkMessage));
String str(&cs[sizeof(LinkMessage)], sizeof(cs) - sizeof(LinkMessage), false);
str.SetLength(0);
// 构造内容
str += "{\"action\":\"";
str += action;
str += "\",\"args\":}";
str += "\",\"args\":{";
str += args;
str += "\"}";
@ -92,3 +152,122 @@ bool LinkClient::Invoke(String& action, String& args) {
// 发送
return Send(msg);
}
// 登录
void LinkClient::Login()
{
TS("LinkClient::Login");
Json json;
String args;
json.SetOut(args);
json.Add("User", User);
// 原始密码对盐值进行加密,得到登录密码
auto now = DateTime::Now().TotalMs();
auto arr = Buffer(&now, 8);
ByteArray bs;
bs = arr;
RC4::Encrypt(arr, Pass);
// 散列明文和密码连接在一起
auto pass = bs.ToHex();
pass += arr.ToHex();
json.Add("Password", pass);
Invoke("Login", args);
}
bool LinkClient::OnLogin(LinkMessage& msg)
{
if (!msg.Reply) return false;
TS("LinkClient::OnLogin");
msg.Show(true);
auto str = msg.GetString();
//Json json = str;
if (msg.Error)
{
Status = 0;
debug_printf("登录失败!\r\n");
}
else
{
Status = 2;
debug_printf("登录成功!\r\n");
// 登录成功后加大心跳间隔
Sys.SetTaskPeriod(_task, 60000);
}
return true;
}
// 心跳,用于保持与对方的活动状态
void LinkClient::Ping()
{
TS("LinkClient::Ping");
if (LastActive > 0 && LastActive + 300000 < Sys.Ms())
{
// 30秒无法联系服务端可能已经掉线重启Hello任务
debug_printf("300秒无法联系服务端可能已经掉线重新开始握手\r\n");
delete Master;
Master = nullptr;
Status = 0;
Sys.SetTaskPeriod(_task, 5000);
return;
}
// 30秒内发过数据不再发送心跳
if (LastSend > 0 && LastSend + 60000 > Sys.Ms()) return;
Json json;
String args;
json.SetOut(args);
//json.Add("Data", Store.Data.ToHex());
// 原始密码对盐值进行加密,得到登录密码
auto ms = (int)Sys.Ms();
json.Add("Time", ms);
Invoke("Ping", args);
}
bool LinkClient::OnPing(LinkMessage& msg)
{
TS("LinkClient::OnPing");
if (!msg.Reply) return false;
msg.Show(true);
if (msg.Error) return false;
auto str = msg.GetString();
Json json = str;
int ms = json["Time"].AsInt();
int cost = (int)(Sys.Ms() - ms);
if (Delay)
Delay = (Delay + cost) / 2;
else
Delay = cost;
debug_printf("心跳延迟 %dms / %dms \r\n", cost, Delay);
// 同步本地时间
int serverTime = json["ServerTime"].AsInt();
if (serverTime > 1000) ((TTime&)Time).SetTime(serverTime);
return true;
}

View File

@ -21,7 +21,11 @@ public:
int Delay; // 心跳延迟。一条心跳指令从发出到收到所花费的时间
int MaxNotActive; // 最大不活跃时间ms超过该时间时重启系统。默认0
Socket* Socket;
NetUri Server;
String User;
String Pass;
Socket* Master; // 主链接。服务器长连接
DataStore Store; // 数据存储区
Dictionary<cstring, IDelegate*> Routes; // 路由集合
@ -31,84 +35,32 @@ public:
void Close();
// 发送消息
bool Invoke(String& action, String& args);
bool Invoke(const String& action, const String& args);
bool Reply(String& action, int code, String& result, int seq);
void OnReceive(String& data);
void LocalSend(int start, const Buffer& bs);
// 收到功能消息时触发
//MessageHandler Received;
void* Param;
// 常用系统级消息
// 握手广播
void SayHello(bool broadcast);
// 注册
void Register();
// 登录
void Login();
// 重置并上报
void Reset(const String& reason);
void Reboot(const String& reason);
// Ping指令用于保持与对方的活动状态
// 心跳,用于保持与对方的活动状态
void Ping();
/*void Read(int start, int size);
void Write(int start, const Buffer& bs);
void Write(int start, byte dat);
// 异步上传并等待响应,返回实际上传字节数
int WriteAsync(int start, const Buffer& bs, int msTimeout);
// 必须满足 start > 0 才可以。
void ReportAsync(int start, uint length = 1);
// 远程调用
void Invoke(const String& action, const Buffer& bs);
// 远程调用委托。传入参数名值对以及结果缓冲区引用业务失败时返回false并把错误信息放在结果缓冲区
typedef bool(*InvokeHandler)(void* param, const Pair& args, Stream& result);
// 注册远程调用处理器
void Register(cstring action, InvokeHandler handler, void* param = nullptr);
// 模版支持成员函数
template<typename T>
void Register(cstring action, bool(T::*func)(const Pair&, Stream&), T* target)
{
Register(action, *(InvokeHandler*)&func, target);
}*/
static LinkClient* Current;
private:
bool Send(LinkMessage& msg);
// 跳转
/*bool OnRedirect(IDictionary);
bool Send(const LinkMessage& msg);
bool OnLogin(TokenMessage& msg, TokenController* ctrl);
bool OnPing(TokenMessage& msg, TokenController* ctrl);
bool ChangeIPEndPoint(const NetUri& uri);
void OnRead(const TokenMessage& msg, TokenController* ctrl);
void OnWrite(const TokenMessage& msg, TokenController* ctrl);
void OnInvoke(const TokenMessage& msg, TokenController* ctrl);
bool OnInvoke(const String& action, const Pair& args, Stream& result);*/
bool OnPing(LinkMessage& msg);
bool OnLogin(LinkMessage& msg);
private:
uint _task;
void* _Expect; // 等待内容
int NextReport = -1; // 下次上报偏移,-1不动
byte ReportLength; // 下次上报数据长度
void LoopTask();
bool CheckReport();
void CheckNet();
};

View File

@ -13,5 +13,11 @@
void LinkMessage::Init() {
*(byte*)Reply = 0;
Seq = 0;
Code = 0;
Length = 0;
}
void LinkMessage::Show(bool newline) const {
String str((cstring)&this[1], Length);
str.Show(newline);
}

View File

@ -18,9 +18,12 @@ public:
// 数据指针
const void* Data() const { return (const void*)&this[1]; }
const String GetString() const { return String((cstring)&this[1], Length); }
void Init();
void Show(bool newline = false) const;
private:
};

View File

@ -107,6 +107,7 @@
<ClCompile Include="..\Kernel\Time.cpp" />
<ClCompile Include="..\Kernel\WaitHandle.cpp" />
<ClCompile Include="..\Link\LinkClient.cpp" />
<ClCompile Include="..\Link\LinkMessage.cpp" />
<ClCompile Include="..\Message\BinaryPair.cpp" />
<ClCompile Include="..\Message\Controller.cpp" />
<ClCompile Include="..\Message\DataStore.cpp" />

View File

@ -587,5 +587,8 @@
<ClCompile Include="..\Link\LinkClient.cpp">
<Filter>Link</Filter>
</ClCompile>
<ClCompile Include="..\Link\LinkMessage.cpp">
<Filter>Link</Filter>
</ClCompile>
</ItemGroup>
</Project>