优化代码 修复发送空消息阻塞

This commit is contained in:
_Redstone_c_ 2021-01-06 22:27:40 +08:00
parent 859db61f9c
commit 2cd3447821
6 changed files with 433 additions and 429 deletions

View File

@ -5,85 +5,54 @@
#include "Sockets.h" #include "Sockets.h"
#include "IPAddress.h" #include "IPAddress.h"
#include "SocketSubsystem.h" #include "SocketSubsystem.h"
#include "..\Public\RedNetworkClient.h"
bool URedNetworkClient::Send(const TArray<uint8>& Data) bool URedNetworkClient::Send(const TArray<uint8>& Data)
{ {
if (!IsActive() || !(ClientPass.ID | ClientPass.Key)) return false; if (!IsActive() || !IsLogged()) return false;
return KCPUnit->Send(Data.GetData(), Data.Num()); return KCPUnit->Send(Data.GetData(), Data.Num()) == 0;
} }
int32 URedNetworkClient::UDPSend(const uint8 * Data, int32 Count) void URedNetworkClient::UDPSend(const uint8 * Data, int32 Count)
{
if (!IsActive() || !(ClientPass.ID | ClientPass.Key)) return false;
SendBuffer.SetNumUninitialized(8, false);
SendBuffer[0] = ClientPass.ID >> 0;
SendBuffer[1] = ClientPass.ID >> 8;
SendBuffer[2] = ClientPass.ID >> 16;
SendBuffer[3] = ClientPass.ID >> 24;
SendBuffer[4] = ClientPass.Key >> 0;
SendBuffer[5] = ClientPass.Key >> 8;
SendBuffer[6] = ClientPass.Key >> 16;
SendBuffer[7] = ClientPass.Key >> 24;
SendBuffer.Append(Data, Count);
int32 BytesSend;
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr);
return 0;
}
void URedNetworkClient::Tick(float DeltaTime)
{ {
if (!IsActive()) return; if (!IsActive()) return;
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(); SendBuffer.SetNumUninitialized(8, false);
check(SocketSubsystem);
const FDateTime NowTime = FDateTime::Now(); ClientPass.ToBytes(SendBuffer.GetData());
if (Count != 0) SendBuffer.Append(Data, Count);
int32 BytesSend;
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr);
}
void URedNetworkClient::UpdateKCP()
{
if (!KCPUnit) return;
// update kcp
if (KCPUnit)
{
int32 Current = FPlatformTime::Cycles64() / 1000; int32 Current = FPlatformTime::Cycles64() / 1000;
KCPUnit->Update(Current); KCPUnit->Update(Current);
} }
// send heartbeat void URedNetworkClient::SendHeartbeat()
{ {
if (NowTime - LastHeartbeat > Heartbeat) UDPSend(nullptr, 0);
{ }
SendBuffer.SetNumUninitialized(8, false);
SendBuffer[0] = ClientPass.ID >> 0; void URedNetworkClient::HandleSocketRecv()
SendBuffer[1] = ClientPass.ID >> 8; {
SendBuffer[2] = ClientPass.ID >> 16; ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get();
SendBuffer[3] = ClientPass.ID >> 24; check(SocketSubsystem);
check(SocketPtr);
SendBuffer[4] = ClientPass.Key >> 0;
SendBuffer[5] = ClientPass.Key >> 8;
SendBuffer[6] = ClientPass.Key >> 16;
SendBuffer[7] = ClientPass.Key >> 24;
int32 BytesSend;
if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr) && BytesSend == SendBuffer.Num())
{
LastHeartbeat = NowTime;
}
}
}
// handle socket recv
{
int32 BytesRead; int32 BytesRead;
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
while (SocketPtr) { while (SocketPtr) {
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
RecvBuffer.SetNumUninitialized(65535, false); RecvBuffer.SetNumUninitialized(65535, false);
if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break; if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break;
@ -91,23 +60,30 @@ void URedNetworkClient::Tick(float DeltaTime)
if (BytesRead < 8) continue; if (BytesRead < 8) continue;
RecvBuffer.SetNumUninitialized(BytesRead, false); RecvBuffer.SetNumUninitialized(BytesRead, false);
FRedNetworkPass SourcePass; FRedNetworkPass SourcePass(RecvBuffer.GetData());
SourcePass.ID = 0;
SourcePass.Key = 0;
SourcePass.ID |= (int32)RecvBuffer[0] << 0; HandleLoginRecv(SourcePass);
SourcePass.ID |= (int32)RecvBuffer[1] << 8;
SourcePass.ID |= (int32)RecvBuffer[2] << 16;
SourcePass.ID |= (int32)RecvBuffer[3] << 24;
SourcePass.Key |= (int32)RecvBuffer[4] << 0; if (!IsLogged()) continue;
SourcePass.Key |= (int32)RecvBuffer[5] << 8;
SourcePass.Key |= (int32)RecvBuffer[6] << 16;
SourcePass.Key |= (int32)RecvBuffer[7] << 24;
// is registration request if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key)
if (!IsLogged())
{ {
LastRecvTime = NowTime;
}
if (RecvBuffer.Num() == 8) continue;
if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key)
{
KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8);
}
}
}
void URedNetworkClient::HandleLoginRecv(const FRedNetworkPass & SourcePass)
{
if (IsLogged()) return;
ClientPass = SourcePass; ClientPass = SourcePass;
KCPUnit = MakeShared<FKCPWrap>(ClientPass.ID, FString::Printf(TEXT("Client-%i"), ClientPass.ID)); KCPUnit = MakeShared<FKCPWrap>(ClientPass.ID, FString::Printf(TEXT("Client-%i"), ClientPass.ID));
@ -116,54 +92,38 @@ void URedNetworkClient::Tick(float DeltaTime)
KCPUnit->OutputFunc = [this](const uint8* Data, int32 Count)->int32 KCPUnit->OutputFunc = [this](const uint8* Data, int32 Count)->int32
{ {
return UDPSend(Data, Count); UDPSend(Data, Count);
return 0;
}; };
OnLogin.Broadcast(); OnLogin.Broadcast();
} }
if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key) void URedNetworkClient::HandleKCPRecv()
{ {
LastRecvTime = NowTime;
}
// is heartbeat request
if ((SourcePass.ID | SourcePass.Key) && RecvBuffer.Num() == 8) continue;
// is server request
if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key)
{
KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8);
}
}
}
// handle kcp recv
{
while (KCPUnit) while (KCPUnit)
{ {
int32 Size = KCPUnit->PeekSize(); int32 Size = KCPUnit->PeekSize();
if (Size <= 0) break; if (Size < 0) break;
RecvBuffer.SetNumUninitialized(Size, false); RecvBuffer.SetNumUninitialized(Size, false);
Size = KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num()); Size = KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num());
if (Size <= 0) break; if (Size < 0) break;
RecvBuffer.SetNumUninitialized(Size, false); RecvBuffer.SetNumUninitialized(Size, false);
OnRecv.Broadcast(RecvBuffer); OnRecv.Broadcast(RecvBuffer);
} }
} }
// handle timeout void URedNetworkClient::HandleTimeout()
{ {
if (IsLogged() && NowTime - LastRecvTime > TimeoutLimit) if (IsLogged() && NowTime - LastRecvTime > TimeoutLimit)
{ {
ClientPass.ID = 0; ClientPass.Reset();
ClientPass.Key = 0;
KCPUnit = nullptr; KCPUnit = nullptr;
@ -171,7 +131,19 @@ void URedNetworkClient::Tick(float DeltaTime)
OnUnlogin.Broadcast(); OnUnlogin.Broadcast();
} }
} }
void URedNetworkClient::Tick(float DeltaTime)
{
if (!IsActive()) return;
NowTime = FDateTime::Now();
UpdateKCP();
SendHeartbeat();
HandleSocketRecv();
HandleKCPRecv();
HandleTimeout();
} }
void URedNetworkClient::Activate(bool bReset) void URedNetworkClient::Activate(bool bReset)
@ -215,8 +187,7 @@ void URedNetworkClient::Activate(bool bReset)
return; return;
} }
ClientPass.ID = 0; ClientPass.Reset();
ClientPass.Key = 0;
LastRecvTime = FDateTime::Now(); LastRecvTime = FDateTime::Now();
LastHeartbeat = FDateTime::MinValue(); LastHeartbeat = FDateTime::MinValue();
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Client activate.")); UE_LOG(LogRedNetwork, Log, TEXT("Red Network Client activate."));
@ -239,10 +210,8 @@ void URedNetworkClient::Deactivate()
SendBuffer.SetNum(0); SendBuffer.SetNum(0);
RecvBuffer.SetNum(0); RecvBuffer.SetNum(0);
DataBuffer.SetNum(0);
ClientPass.ID = 0; ClientPass.Reset();
ClientPass.Key = 0;
KCPUnit = nullptr; KCPUnit = nullptr;

View File

@ -6,289 +6,233 @@
#include "IPAddress.h" #include "IPAddress.h"
#include "SocketSubsystem.h" #include "SocketSubsystem.h"
#include "HAL/UnrealMemory.h" #include "HAL/UnrealMemory.h"
#include "..\Public\RedNetworkServer.h"
bool URedNetworkServer::Send(int32 ClientID, const TArray<uint8>& Data) bool URedNetworkServer::Send(int32 ClientID, const TArray<uint8>& Data)
{ {
if (!IsActive() || !Registration.Contains(ClientID)) return false; if (!IsActive() || !Connections.Contains(ClientID)) return false;
const FRegistrationInfo& Info = Registration[ClientID]; const FConnectionInfo& Info = Connections[ClientID];
return !Info.KCPUnit->Send(Data.GetData(), Data.Num()); return Info.KCPUnit->Send(Data.GetData(), Data.Num()) == 0;
} }
int32 URedNetworkServer::UDPSend(int32 ClientID, const uint8* Data, int32 Count) void URedNetworkServer::UDPSend(int32 ClientID, const uint8* Data, int32 Count)
{ {
if (!IsActive() || !Registration.Contains(ClientID)) return false; if (!IsActive() || !Connections.Contains(ClientID)) return;
const FRegistrationInfo& Info = Registration[ClientID]; const FConnectionInfo& Info = Connections[ClientID];
SendBuffer.SetNumUninitialized(8, false); SendBuffer.SetNumUninitialized(8, false);
SendBuffer[0] = Info.Pass.ID >> 0; Info.Pass.ToBytes(SendBuffer.GetData());
SendBuffer[1] = Info.Pass.ID >> 8;
SendBuffer[2] = Info.Pass.ID >> 16;
SendBuffer[3] = Info.Pass.ID >> 24;
SendBuffer[4] = Info.Pass.Key >> 0; if (Count != 0) SendBuffer.Append(Data, Count);
SendBuffer[5] = Info.Pass.Key >> 8;
SendBuffer[6] = Info.Pass.Key >> 16;
SendBuffer[7] = Info.Pass.Key >> 24;
SendBuffer.Append(Data, Count);
int32 BytesSend; int32 BytesSend;
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *Info.Addr); SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *Info.Addr);
return 0;
} }
void URedNetworkServer::Tick(float DeltaTime) void URedNetworkServer::UpdateKCP()
{ {
if (!IsActive()) return;
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get();
check(SocketSubsystem);
const FDateTime NowTime = FDateTime::Now();
// update kcp
{
TArray<int32> RegistrationAddr;
Registration.GetKeys(RegistrationAddr);
int32 Current = FPlatformTime::Cycles64() / 1000; int32 Current = FPlatformTime::Cycles64() / 1000;
for (int32 ID : RegistrationAddr) for (auto Info : Connections)
{ {
Registration[ID].KCPUnit->Update(Current); Info.Value.KCPUnit->Update(Current);
}
} }
}
// send heartbeat void URedNetworkServer::SendHeartbeat()
{
for (auto Info : Connections)
{ {
TArray<int32> RegistrationAddr; UDPSend(Info.Key, nullptr, 0);
Registration.GetKeys(RegistrationAddr);
for (int32 ID : RegistrationAddr)
{
if (NowTime - Registration[ID].Heartbeat > Heartbeat)
{
SendBuffer.SetNum(8, false);
SendBuffer[0] = Registration[ID].Pass.ID >> 0;
SendBuffer[1] = Registration[ID].Pass.ID >> 8;
SendBuffer[2] = Registration[ID].Pass.ID >> 16;
SendBuffer[3] = Registration[ID].Pass.ID >> 24;
SendBuffer[4] = Registration[ID].Pass.Key >> 0;
SendBuffer[5] = Registration[ID].Pass.Key >> 8;
SendBuffer[6] = Registration[ID].Pass.Key >> 16;
SendBuffer[7] = Registration[ID].Pass.Key >> 24;
int32 BytesSend;
if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *Registration[ID].Addr) && BytesSend == SendBuffer.Num())
{
Registration[ID].Heartbeat = NowTime;
}
}
}
} }
}
// handle socket recv void URedNetworkServer::HandleSocketRecv()
{ {
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get();
check(SocketSubsystem);
check(SocketPtr);
int32 BytesRead; int32 BytesRead;
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
while (SocketPtr) { while (SocketPtr) {
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
RecvBuffer.SetNumUninitialized(65535, false); RecvBuffer.SetNumUninitialized(65535, false);
if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break; if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break;
if (BytesRead < 8) continue; if (RecvBuffer.Num() < 8) continue;
RecvBuffer.SetNumUninitialized(BytesRead, false); RecvBuffer.SetNumUninitialized(BytesRead, false);
FRedNetworkPass SourcePass; FRedNetworkPass SourcePass(RecvBuffer.GetData());
SourcePass.ID = 0;
SourcePass.Key = 0;
SourcePass.ID |= (int32)RecvBuffer[0] << 0; if (!SourcePass.IsValid())
SourcePass.ID |= (int32)RecvBuffer[1] << 8;
SourcePass.ID |= (int32)RecvBuffer[2] << 16;
SourcePass.ID |= (int32)RecvBuffer[3] << 24;
SourcePass.Key |= (int32)RecvBuffer[4] << 0;
SourcePass.Key |= (int32)RecvBuffer[5] << 8;
SourcePass.Key |= (int32)RecvBuffer[6] << 16;
SourcePass.Key |= (int32)RecvBuffer[7] << 24;
FString SourceAddrStr = SourceAddr->ToString(true);
// is pre-register pass request
if (!(SourcePass.ID | SourcePass.Key))
{ {
if (!PreRegistration.Contains(SourceAddrStr)) SendReadyPass(SourceAddr);
{ continue;
FPreRegistrationInfo NewRegistration;
NewRegistration.Time = NowTime;
NewRegistration.Pass.ID = NextRegistrationID++;
NewRegistration.Pass.Key ^= FMath::Rand() << 0;
NewRegistration.Pass.Key ^= FMath::Rand() << 8;
NewRegistration.Pass.Key ^= FMath::Rand() << 16;
NewRegistration.Pass.Key ^= FMath::Rand() << 24;
PreRegistration.Add(SourceAddrStr, NewRegistration);
UE_LOG(LogRedNetwork, Log, TEXT("Pre-register pass %i from %s."), NewRegistration.Pass.ID, *SourceAddrStr);
} }
const FRedNetworkPass& Pass = PreRegistration[SourceAddrStr].Pass; RedirectConnection(SourcePass, SourceAddr);
RegisterConnection(SourcePass, SourceAddr);
if (!Connections.Contains(SourcePass.ID)) continue;
Connections[SourcePass.ID].RecvTime = NowTime;
if (RecvBuffer.Num() == 8) continue;
if (Connections.Contains(SourcePass.ID))
{
Connections[SourcePass.ID].KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8);
}
}
}
void URedNetworkServer::SendReadyPass(const TSharedRef<FInternetAddr>& SourceAddr)
{
FString SourceAddrStr = SourceAddr->ToString(true);
if (!ReadyPass.Contains(SourceAddrStr))
{
FReadyInfo NewReadyPass;
NewReadyPass.Time = NowTime;
NewReadyPass.Pass.ID = NextReadyID++;
NewReadyPass.Pass.RandKey();
ReadyPass.Add(SourceAddrStr, NewReadyPass);
UE_LOG(LogRedNetwork, Log, TEXT("Ready pass %i from %s."), NewReadyPass.Pass.ID, *SourceAddrStr);
}
const FRedNetworkPass& Pass = ReadyPass[SourceAddrStr].Pass;
SendBuffer.SetNum(8, false); SendBuffer.SetNum(8, false);
SendBuffer[0] = Pass.ID >> 0; Pass.ToBytes(SendBuffer.GetData());
SendBuffer[1] = Pass.ID >> 8;
SendBuffer[2] = Pass.ID >> 16;
SendBuffer[3] = Pass.ID >> 24;
SendBuffer[4] = Pass.Key >> 0;
SendBuffer[5] = Pass.Key >> 8;
SendBuffer[6] = Pass.Key >> 16;
SendBuffer[7] = Pass.Key >> 24;
int32 BytesSend; int32 BytesSend;
if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *SourceAddr) && BytesSend == SendBuffer.Num()) SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *SourceAddr);
{
UE_LOG(LogRedNetwork, Log, TEXT("Send pre-registration pass %i to %s."), Pass.ID, *SourceAddrStr);
}
}
else
{
// redirect connection
if (Registration.Contains(SourcePass.ID))
{
if (!(*Registration[SourcePass.ID].Addr == *SourceAddr))
{
Registration[SourcePass.ID].Addr = SourceAddr;
UE_LOG(LogRedNetwork, Log, TEXT("Redirect connection %i."), SourcePass.ID); UE_LOG(LogRedNetwork, Log, TEXT("Send ready pass %i to %s."), Pass.ID, *SourceAddrStr);
}
void URedNetworkServer::RedirectConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr)
{
if (!Connections.Contains(SourcePass.ID) || Connections[SourcePass.ID].Pass.Key != SourcePass.Key) return;
if (!(*Connections[SourcePass.ID].Addr == *SourceAddr))
{
UE_LOG(LogRedNetwork, Log, TEXT("Redirect connection %i from %s to %s."), SourcePass.ID, *Connections[SourcePass.ID].Addr->ToString(true), *SourceAddr->ToString(true));
Connections[SourcePass.ID].Addr = SourceAddr;
} }
}
} void URedNetworkServer::RegisterConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr)
{
FString SourceAddrStr = SourceAddr->ToString(true);
// register connection if (!ReadyPass.Contains(SourceAddrStr)) return;
{ if (ReadyPass[SourceAddrStr].Pass.ID != SourcePass.ID || ReadyPass[SourceAddrStr].Pass.Key != SourcePass.Key) return;
bool bIsValidRegistration = false;
if (PreRegistration.Contains(SourceAddrStr))
{
if (PreRegistration[SourceAddrStr].Pass.ID == SourcePass.ID && PreRegistration[SourceAddrStr].Pass.Key == SourcePass.Key)
{
bIsValidRegistration = true;
}
}
if (bIsValidRegistration) FConnectionInfo NewConnections;
{ NewConnections.Pass = SourcePass;
FRegistrationInfo NewRegistration; NewConnections.RecvTime = NowTime;
NewRegistration.Pass = SourcePass; NewConnections.Heartbeat = FDateTime::MinValue();
NewRegistration.RecvTime = NowTime; NewConnections.Addr = SourceAddr;
NewRegistration.Heartbeat = FDateTime::MinValue();
NewRegistration.Addr = SourceAddr;
NewRegistration.KCPUnit = MakeShared<FKCPWrap>(NewRegistration.Pass.ID, FString::Printf(TEXT("Server-%i"), NewRegistration.Pass.ID)); NewConnections.KCPUnit = MakeShared<FKCPWrap>(NewConnections.Pass.ID, FString::Printf(TEXT("Server-%i"), NewConnections.Pass.ID));
NewRegistration.KCPUnit->SetTurboMode(); NewConnections.KCPUnit->SetTurboMode();
NewRegistration.KCPUnit->GetKCPCB().logmask = KCPLogMask; NewConnections.KCPUnit->GetKCPCB().logmask = KCPLogMask;
NewRegistration.KCPUnit->OutputFunc = [this, ID = NewRegistration.Pass.ID](const uint8* Data, int32 Count) -> int32 NewConnections.KCPUnit->OutputFunc = [this, ID = NewConnections.Pass.ID](const uint8* Data, int32 Count)->int32
{ {
return UDPSend(ID, Data, Count); UDPSend(ID, Data, Count);
return 0;
}; };
Registration.Add(SourcePass.ID, NewRegistration); Connections.Add(SourcePass.ID, NewConnections);
PreRegistration.Remove(SourceAddrStr); ReadyPass.Remove(SourceAddrStr);
UE_LOG(LogRedNetwork, Log, TEXT("Register connection %i."), SourcePass.ID); UE_LOG(LogRedNetwork, Log, TEXT("Register connection %i."), SourcePass.ID);
OnLogin.Broadcast(SourcePass.ID); OnLogin.Broadcast(SourcePass.ID);
} }
}
}
if (Registration.Contains(SourcePass.ID)) void URedNetworkServer::HandleKCPRecv()
{
for (auto Info : Connections)
{ {
Registration[SourcePass.ID].RecvTime = NowTime; while (Info.Value.KCPUnit)
}
// is heartbeat request
if ((SourcePass.ID | SourcePass.Key) && RecvBuffer.Num() == 8) continue;
// is client request
if (Registration.Contains(SourcePass.ID))
{ {
Registration[SourcePass.ID].KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8); int32 Size = Info.Value.KCPUnit->PeekSize();
}
if (Size < 0) break;
RecvBuffer.SetNumUninitialized(Size, false);
Size = Info.Value.KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num());
if (Size < 0) break;
RecvBuffer.SetNumUninitialized(Size, false);
OnRecv.Broadcast(Info.Key, RecvBuffer);
} }
} }
}
// handle pre-registration timeout void URedNetworkServer::HandleExpiredReadyPass()
{ {
TArray<FString> PreRegistrationAddr; TArray<FString> ReadyPassAddr;
PreRegistration.GetKeys(PreRegistrationAddr); ReadyPass.GetKeys(ReadyPassAddr);
for (const FString& Addr : PreRegistrationAddr) for (const FString& Addr : ReadyPassAddr)
{ {
if (NowTime - PreRegistration[Addr].Time > TimeoutLimit) if (NowTime - ReadyPass[Addr].Time > TimeoutLimit)
{ {
UE_LOG(LogRedNetwork, Log, TEXT("Pre-registration pass %i timeout."), PreRegistration[Addr].Pass.ID); UE_LOG(LogRedNetwork, Log, TEXT("Ready pass %i timeout."), ReadyPass[Addr].Pass.ID);
PreRegistration.Remove(Addr); ReadyPass.Remove(Addr);
}
} }
} }
}
// handle running timeout void URedNetworkServer::HandleExpiredConnection()
{ {
TArray<int32> RegistrationAddr; TArray<int32> ConnectionsAddr;
Registration.GetKeys(RegistrationAddr); Connections.GetKeys(ConnectionsAddr);
for (int32 ID : RegistrationAddr) for (int32 ID : ConnectionsAddr)
{ {
if (NowTime - Registration[ID].RecvTime > TimeoutLimit) if (NowTime - Connections[ID].RecvTime > TimeoutLimit)
{ {
UE_LOG(LogRedNetwork, Log, TEXT("Registration connection %i timeout."), Registration[ID].Pass.ID); UE_LOG(LogRedNetwork, Log, TEXT("Connections connection %i timeout."), Connections[ID].Pass.ID);
Registration.Remove(ID); Connections.Remove(ID);
OnUnlogin.Broadcast(ID); OnUnlogin.Broadcast(ID);
} }
} }
} }
// handle kcp recv void URedNetworkServer::Tick(float DeltaTime)
{ {
TArray<int32> RegistrationAddr; if (!IsActive()) return;
Registration.GetKeys(RegistrationAddr); NowTime = FDateTime::Now();
for (int32 ID : RegistrationAddr) UpdateKCP();
{ SendHeartbeat();
while (Registration[ID].KCPUnit) HandleSocketRecv();
{ HandleKCPRecv();
int32 Size = Registration[ID].KCPUnit->PeekSize(); HandleExpiredReadyPass();
HandleExpiredConnection();
if (Size <= 0) break;
RecvBuffer.SetNumUninitialized(Size, false);
Size = Registration[ID].KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num());
if (Size <= 0) break;
RecvBuffer.SetNumUninitialized(Size, false);
OnRecv.Broadcast(ID, RecvBuffer);
}
}
}
} }
void URedNetworkServer::Activate(bool bReset) void URedNetworkServer::Activate(bool bReset)
@ -331,7 +275,7 @@ void URedNetworkServer::Activate(bool bReset)
return; return;
} }
NextRegistrationID = 1; NextReadyID = 1;
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server activate.")); UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server activate."));
@ -342,10 +286,10 @@ void URedNetworkServer::Deactivate()
{ {
if (!bIsActive) return; if (!bIsActive) return;
TArray<int32> RegistrationAddr; TArray<int32> ConnectionsAddr;
Registration.GetKeys(RegistrationAddr); Connections.GetKeys(ConnectionsAddr);
for (int32 ID : RegistrationAddr) for (int32 ID : ConnectionsAddr)
{ {
OnUnlogin.Broadcast(ID); OnUnlogin.Broadcast(ID);
} }
@ -356,10 +300,9 @@ void URedNetworkServer::Deactivate()
SendBuffer.SetNum(0); SendBuffer.SetNum(0);
RecvBuffer.SetNum(0); RecvBuffer.SetNum(0);
DataBuffer.SetNum(0);
PreRegistration.Reset(); ReadyPass.Reset();
Registration.Reset(); Connections.Reset();
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server deactivate.")); UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server deactivate."));

View File

@ -1 +1,62 @@
#include "RedNetworkType.h" #include "RedNetworkType.h"
#include "..\Public\RedNetworkType.h"
FRedNetworkPass::FRedNetworkPass()
: ID(0)
, Key(0)
{
}
FRedNetworkPass::FRedNetworkPass(uint8 * Data)
: FRedNetworkPass()
{
FromBytes(Data);
}
void FRedNetworkPass::FromBytes(const uint8 * Data)
{
ID = 0;
Key = 0;
ID |= (int32)Data[0] << 0;
ID |= (int32)Data[1] << 8;
ID |= (int32)Data[2] << 16;
ID |= (int32)Data[3] << 24;
Key |= (int32)Data[4] << 0;
Key |= (int32)Data[5] << 8;
Key |= (int32)Data[6] << 16;
Key |= (int32)Data[7] << 24;
}
void FRedNetworkPass::ToBytes(uint8 * Data) const
{
Data[0] = ID >> 0;
Data[1] = ID >> 8;
Data[2] = ID >> 16;
Data[3] = ID >> 24;
Data[4] = Key >> 0;
Data[5] = Key >> 8;
Data[6] = Key >> 16;
Data[7] = Key >> 24;
}
void FRedNetworkPass::RandKey()
{
Key ^= FMath::Rand() << 0;
Key ^= FMath::Rand() << 8;
Key ^= FMath::Rand() << 16;
Key ^= FMath::Rand() << 24;
}
void FRedNetworkPass::Reset()
{
ID = 0;
Key = 0;
}
bool FRedNetworkPass::IsValid() const
{
return ID;
}

View File

@ -43,7 +43,7 @@ public:
void Deactivate(); void Deactivate();
UFUNCTION(BlueprintCallable, Category = "Red|Network") UFUNCTION(BlueprintCallable, Category = "Red|Network")
bool IsLogged() const { return ClientPass.ID | ClientPass.Key; } bool IsLogged() const { return ClientPass.IsValid(); }
UFUNCTION(BlueprintCallable, Category = "Red|Network") UFUNCTION(BlueprintCallable, Category = "Red|Network")
bool Send(const TArray<uint8>& Data); bool Send(const TArray<uint8>& Data);
@ -72,7 +72,6 @@ private:
TArray<uint8> SendBuffer; TArray<uint8> SendBuffer;
TArray<uint8> RecvBuffer; TArray<uint8> RecvBuffer;
TArray<uint8> DataBuffer;
FRedNetworkPass ClientPass; FRedNetworkPass ClientPass;
@ -81,7 +80,16 @@ private:
TSharedPtr<FKCPWrap> KCPUnit; TSharedPtr<FKCPWrap> KCPUnit;
int32 UDPSend(const uint8* Data, int32 Count); void UDPSend(const uint8* Data, int32 Count);
FDateTime NowTime;
void UpdateKCP();
void SendHeartbeat();
void HandleSocketRecv();
void HandleLoginRecv(const FRedNetworkPass& SourcePass);
void HandleKCPRecv();
void HandleTimeout();
public: public:

View File

@ -8,6 +8,7 @@
class FSocket; class FSocket;
class FKCPWrap; class FKCPWrap;
class FInternetAddr;
UCLASS(BlueprintType) UCLASS(BlueprintType)
class REDNETWORK_API URedNetworkServer : public UObject, public FTickableGameObject class REDNETWORK_API URedNetworkServer : public UObject, public FTickableGameObject
@ -67,19 +68,18 @@ private:
TArray<uint8> SendBuffer; TArray<uint8> SendBuffer;
TArray<uint8> RecvBuffer; TArray<uint8> RecvBuffer;
TArray<uint8> DataBuffer;
int32 NextRegistrationID; int32 NextReadyID;
struct FPreRegistrationInfo struct FReadyInfo
{ {
FDateTime Time; FDateTime Time;
FRedNetworkPass Pass; FRedNetworkPass Pass;
}; };
TMap<FString, FPreRegistrationInfo> PreRegistration; TMap<FString, FReadyInfo> ReadyPass;
struct FRegistrationInfo struct FConnectionInfo
{ {
FRedNetworkPass Pass; FRedNetworkPass Pass;
FDateTime RecvTime; FDateTime RecvTime;
@ -88,9 +88,21 @@ private:
TSharedPtr<FKCPWrap> KCPUnit; TSharedPtr<FKCPWrap> KCPUnit;
}; };
TMap<int32, FRegistrationInfo> Registration; TMap<int32, FConnectionInfo> Connections;
int32 UDPSend(int32 ClientID, const uint8* Data, int32 Count); void UDPSend(int32 ClientID, const uint8* Data, int32 Count);
FDateTime NowTime;
void UpdateKCP();
void SendHeartbeat();
void HandleSocketRecv();
void SendReadyPass(const TSharedRef<FInternetAddr>& SourceAddr);
void RedirectConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr);
void RegisterConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr);
void HandleKCPRecv();
void HandleExpiredReadyPass();
void HandleExpiredConnection();
public: public:

View File

@ -6,4 +6,15 @@ struct REDNETWORK_API FRedNetworkPass
{ {
int32 ID; int32 ID;
int32 Key; int32 Key;
FRedNetworkPass();
FRedNetworkPass(uint8* Data);
void FromBytes(const uint8* Data);
void ToBytes(uint8* Data) const;
void RandKey();
void Reset();
bool IsValid() const;
}; };