From 2cd3447821d709384e18de3a7a6628e69d1b0d38 Mon Sep 17 00:00:00 2001 From: _Redstone_c_ <2824517378@qq.com> Date: Wed, 6 Jan 2021 22:27:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=91=E9=80=81=E7=A9=BA=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E9=98=BB=E5=A1=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RedNetwork/Private/RedNetworkClient.cpp | 271 +++++----- .../RedNetwork/Private/RedNetworkServer.cpp | 479 ++++++++---------- Source/RedNetwork/Private/RedNetworkType.cpp | 61 +++ Source/RedNetwork/Public/RedNetworkClient.h | 14 +- Source/RedNetwork/Public/RedNetworkServer.h | 26 +- Source/RedNetwork/Public/RedNetworkType.h | 11 + 6 files changed, 433 insertions(+), 429 deletions(-) diff --git a/Source/RedNetwork/Private/RedNetworkClient.cpp b/Source/RedNetwork/Private/RedNetworkClient.cpp index a2bd877..43fbf5e 100644 --- a/Source/RedNetwork/Private/RedNetworkClient.cpp +++ b/Source/RedNetwork/Private/RedNetworkClient.cpp @@ -5,173 +5,145 @@ #include "Sockets.h" #include "IPAddress.h" #include "SocketSubsystem.h" +#include "..\Public\RedNetworkClient.h" bool URedNetworkClient::Send(const TArray& 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; + if (!IsActive()) return; SendBuffer.SetNumUninitialized(8, false); - SendBuffer[0] = ClientPass.ID >> 0; - SendBuffer[1] = ClientPass.ID >> 8; - SendBuffer[2] = ClientPass.ID >> 16; - SendBuffer[3] = ClientPass.ID >> 24; + ClientPass.ToBytes(SendBuffer.GetData()); - SendBuffer[4] = ClientPass.Key >> 0; - SendBuffer[5] = ClientPass.Key >> 8; - SendBuffer[6] = ClientPass.Key >> 16; - SendBuffer[7] = ClientPass.Key >> 24; - - SendBuffer.Append(Data, Count); + if (Count != 0) SendBuffer.Append(Data, Count); int32 BytesSend; SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr); - return 0; +} + +void URedNetworkClient::UpdateKCP() +{ + if (!KCPUnit) return; + + int32 Current = FPlatformTime::Cycles64() / 1000; + + KCPUnit->Update(Current); +} + +void URedNetworkClient::SendHeartbeat() +{ + UDPSend(nullptr, 0); +} + +void URedNetworkClient::HandleSocketRecv() +{ + ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(); + check(SocketSubsystem); + check(SocketPtr); + int32 BytesRead; + + while (SocketPtr) { + + TSharedRef SourceAddr = SocketSubsystem->CreateInternetAddr(); + + RecvBuffer.SetNumUninitialized(65535, false); + + if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break; + + if (BytesRead < 8) continue; + RecvBuffer.SetNumUninitialized(BytesRead, false); + + FRedNetworkPass SourcePass(RecvBuffer.GetData()); + + HandleLoginRecv(SourcePass); + + if (!IsLogged()) continue; + + if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key) + { + 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; + + KCPUnit = MakeShared(ClientPass.ID, FString::Printf(TEXT("Client-%i"), ClientPass.ID)); + KCPUnit->SetTurboMode(); + KCPUnit->GetKCPCB().logmask = KCPLogMask; + + KCPUnit->OutputFunc = [this](const uint8* Data, int32 Count)->int32 + { + UDPSend(Data, Count); + return 0; + }; + + OnLogin.Broadcast(); +} + +void URedNetworkClient::HandleKCPRecv() +{ + while (KCPUnit) + { + int32 Size = KCPUnit->PeekSize(); + + if (Size < 0) break; + + RecvBuffer.SetNumUninitialized(Size, false); + + Size = KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num()); + + if (Size < 0) break; + + RecvBuffer.SetNumUninitialized(Size, false); + + OnRecv.Broadcast(RecvBuffer); + } +} + +void URedNetworkClient::HandleTimeout() +{ + if (IsLogged() && NowTime - LastRecvTime > TimeoutLimit) + { + ClientPass.Reset(); + + KCPUnit = nullptr; + + UE_LOG(LogRedNetwork, Warning, TEXT("Red Network Client timeout.")); + + OnUnlogin.Broadcast(); + } } void URedNetworkClient::Tick(float DeltaTime) { if (!IsActive()) return; - ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(); - check(SocketSubsystem); + NowTime = FDateTime::Now(); - const FDateTime NowTime = FDateTime::Now(); - - // update kcp - if (KCPUnit) - { - int32 Current = FPlatformTime::Cycles64() / 1000; - - KCPUnit->Update(Current); - } - - // send heartbeat - { - if (NowTime - LastHeartbeat > Heartbeat) - { - 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; - - int32 BytesSend; - if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr) && BytesSend == SendBuffer.Num()) - { - LastHeartbeat = NowTime; - } - } - } - - // handle socket recv - { - int32 BytesRead; - TSharedRef SourceAddr = SocketSubsystem->CreateInternetAddr(); - - while (SocketPtr) { - - RecvBuffer.SetNumUninitialized(65535, false); - - if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break; - - if (BytesRead < 8) continue; - RecvBuffer.SetNumUninitialized(BytesRead, false); - - FRedNetworkPass SourcePass; - SourcePass.ID = 0; - SourcePass.Key = 0; - - SourcePass.ID |= (int32)RecvBuffer[0] << 0; - 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; - - // is registration request - if (!IsLogged()) - { - ClientPass = SourcePass; - - KCPUnit = MakeShared(ClientPass.ID, FString::Printf(TEXT("Client-%i"), ClientPass.ID)); - KCPUnit->SetTurboMode(); - KCPUnit->GetKCPCB().logmask = KCPLogMask; - - KCPUnit->OutputFunc = [this](const uint8* Data, int32 Count)->int32 - { - return UDPSend(Data, Count); - }; - - OnLogin.Broadcast(); - } - - if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key) - { - 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) - { - int32 Size = KCPUnit->PeekSize(); - - if (Size <= 0) break; - - RecvBuffer.SetNumUninitialized(Size, false); - - Size = KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num()); - - if (Size <= 0) break; - - RecvBuffer.SetNumUninitialized(Size, false); - - OnRecv.Broadcast(RecvBuffer); - } - } - - // handle timeout - { - if (IsLogged() && NowTime - LastRecvTime > TimeoutLimit) - { - ClientPass.ID = 0; - ClientPass.Key = 0; - - KCPUnit = nullptr; - - UE_LOG(LogRedNetwork, Warning, TEXT("Red Network Client timeout.")); - - OnUnlogin.Broadcast(); - } - } + UpdateKCP(); + SendHeartbeat(); + HandleSocketRecv(); + HandleKCPRecv(); + HandleTimeout(); } void URedNetworkClient::Activate(bool bReset) @@ -215,8 +187,7 @@ void URedNetworkClient::Activate(bool bReset) return; } - ClientPass.ID = 0; - ClientPass.Key = 0; + ClientPass.Reset(); LastRecvTime = FDateTime::Now(); LastHeartbeat = FDateTime::MinValue(); UE_LOG(LogRedNetwork, Log, TEXT("Red Network Client activate.")); @@ -239,10 +210,8 @@ void URedNetworkClient::Deactivate() SendBuffer.SetNum(0); RecvBuffer.SetNum(0); - DataBuffer.SetNum(0); - ClientPass.ID = 0; - ClientPass.Key = 0; + ClientPass.Reset(); KCPUnit = nullptr; diff --git a/Source/RedNetwork/Private/RedNetworkServer.cpp b/Source/RedNetwork/Private/RedNetworkServer.cpp index bc973e9..2bfebcc 100644 --- a/Source/RedNetwork/Private/RedNetworkServer.cpp +++ b/Source/RedNetwork/Private/RedNetworkServer.cpp @@ -6,289 +6,233 @@ #include "IPAddress.h" #include "SocketSubsystem.h" #include "HAL/UnrealMemory.h" +#include "..\Public\RedNetworkServer.h" bool URedNetworkServer::Send(int32 ClientID, const TArray& 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[0] = Info.Pass.ID >> 0; - SendBuffer[1] = Info.Pass.ID >> 8; - SendBuffer[2] = Info.Pass.ID >> 16; - SendBuffer[3] = Info.Pass.ID >> 24; + Info.Pass.ToBytes(SendBuffer.GetData()); - SendBuffer[4] = Info.Pass.Key >> 0; - SendBuffer[5] = Info.Pass.Key >> 8; - SendBuffer[6] = Info.Pass.Key >> 16; - SendBuffer[7] = Info.Pass.Key >> 24; - - SendBuffer.Append(Data, Count); + if (Count != 0) SendBuffer.Append(Data, Count); int32 BytesSend; SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *Info.Addr); - return 0; +} + +void URedNetworkServer::UpdateKCP() +{ + int32 Current = FPlatformTime::Cycles64() / 1000; + + for (auto Info : Connections) + { + Info.Value.KCPUnit->Update(Current); + } +} + +void URedNetworkServer::SendHeartbeat() +{ + for (auto Info : Connections) + { + UDPSend(Info.Key, nullptr, 0); + } +} + +void URedNetworkServer::HandleSocketRecv() +{ + ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(); + check(SocketSubsystem); + check(SocketPtr); + int32 BytesRead; + + while (SocketPtr) { + + TSharedRef SourceAddr = SocketSubsystem->CreateInternetAddr(); + + RecvBuffer.SetNumUninitialized(65535, false); + + if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break; + + if (RecvBuffer.Num() < 8) continue; + RecvBuffer.SetNumUninitialized(BytesRead, false); + + FRedNetworkPass SourcePass(RecvBuffer.GetData()); + + if (!SourcePass.IsValid()) + { + SendReadyPass(SourceAddr); + continue; + } + + 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& 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); + + Pass.ToBytes(SendBuffer.GetData()); + + int32 BytesSend; + SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *SourceAddr); + + UE_LOG(LogRedNetwork, Log, TEXT("Send ready pass %i to %s."), Pass.ID, *SourceAddrStr); +} + +void URedNetworkServer::RedirectConnection(const FRedNetworkPass& SourcePass, const TSharedRef& 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& SourceAddr) +{ + FString SourceAddrStr = SourceAddr->ToString(true); + + if (!ReadyPass.Contains(SourceAddrStr)) return; + if (ReadyPass[SourceAddrStr].Pass.ID != SourcePass.ID || ReadyPass[SourceAddrStr].Pass.Key != SourcePass.Key) return; + + FConnectionInfo NewConnections; + NewConnections.Pass = SourcePass; + NewConnections.RecvTime = NowTime; + NewConnections.Heartbeat = FDateTime::MinValue(); + NewConnections.Addr = SourceAddr; + + NewConnections.KCPUnit = MakeShared(NewConnections.Pass.ID, FString::Printf(TEXT("Server-%i"), NewConnections.Pass.ID)); + NewConnections.KCPUnit->SetTurboMode(); + NewConnections.KCPUnit->GetKCPCB().logmask = KCPLogMask; + + NewConnections.KCPUnit->OutputFunc = [this, ID = NewConnections.Pass.ID](const uint8* Data, int32 Count)->int32 + { + UDPSend(ID, Data, Count); + return 0; + }; + + Connections.Add(SourcePass.ID, NewConnections); + + ReadyPass.Remove(SourceAddrStr); + + UE_LOG(LogRedNetwork, Log, TEXT("Register connection %i."), SourcePass.ID); + + OnLogin.Broadcast(SourcePass.ID); +} + +void URedNetworkServer::HandleKCPRecv() +{ + for (auto Info : Connections) + { + while (Info.Value.KCPUnit) + { + 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); + } + } +} + +void URedNetworkServer::HandleExpiredReadyPass() +{ + TArray ReadyPassAddr; + ReadyPass.GetKeys(ReadyPassAddr); + + for (const FString& Addr : ReadyPassAddr) + { + if (NowTime - ReadyPass[Addr].Time > TimeoutLimit) + { + UE_LOG(LogRedNetwork, Log, TEXT("Ready pass %i timeout."), ReadyPass[Addr].Pass.ID); + + ReadyPass.Remove(Addr); + } + } +} + +void URedNetworkServer::HandleExpiredConnection() +{ + TArray ConnectionsAddr; + Connections.GetKeys(ConnectionsAddr); + + for (int32 ID : ConnectionsAddr) + { + if (NowTime - Connections[ID].RecvTime > TimeoutLimit) + { + UE_LOG(LogRedNetwork, Log, TEXT("Connections connection %i timeout."), Connections[ID].Pass.ID); + + Connections.Remove(ID); + + OnUnlogin.Broadcast(ID); + } + } } void URedNetworkServer::Tick(float DeltaTime) { if (!IsActive()) return; + NowTime = FDateTime::Now(); - ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(); - check(SocketSubsystem); - - const FDateTime NowTime = FDateTime::Now(); - - // update kcp - { - TArray RegistrationAddr; - Registration.GetKeys(RegistrationAddr); - - int32 Current = FPlatformTime::Cycles64() / 1000; - - for (int32 ID : RegistrationAddr) - { - Registration[ID].KCPUnit->Update(Current); - } - } - - // send heartbeat - { - TArray RegistrationAddr; - 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 - { - int32 BytesRead; - TSharedRef SourceAddr = SocketSubsystem->CreateInternetAddr(); - - while (SocketPtr) { - - RecvBuffer.SetNumUninitialized(65535, false); - - if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break; - - if (BytesRead < 8) continue; - RecvBuffer.SetNumUninitialized(BytesRead, false); - - FRedNetworkPass SourcePass; - SourcePass.ID = 0; - SourcePass.Key = 0; - - SourcePass.ID |= (int32)RecvBuffer[0] << 0; - 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)) - { - 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; - - SendBuffer.SetNum(8, false); - - SendBuffer[0] = Pass.ID >> 0; - 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; - if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *SourceAddr) && BytesSend == SendBuffer.Num()) - { - 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); - } - - } - - // register connection - { - bool bIsValidRegistration = false; - if (PreRegistration.Contains(SourceAddrStr)) - { - if (PreRegistration[SourceAddrStr].Pass.ID == SourcePass.ID && PreRegistration[SourceAddrStr].Pass.Key == SourcePass.Key) - { - bIsValidRegistration = true; - } - } - - if (bIsValidRegistration) - { - FRegistrationInfo NewRegistration; - NewRegistration.Pass = SourcePass; - NewRegistration.RecvTime = NowTime; - NewRegistration.Heartbeat = FDateTime::MinValue(); - NewRegistration.Addr = SourceAddr; - - NewRegistration.KCPUnit = MakeShared(NewRegistration.Pass.ID, FString::Printf(TEXT("Server-%i"), NewRegistration.Pass.ID)); - NewRegistration.KCPUnit->SetTurboMode(); - NewRegistration.KCPUnit->GetKCPCB().logmask = KCPLogMask; - - NewRegistration.KCPUnit->OutputFunc = [this, ID = NewRegistration.Pass.ID](const uint8* Data, int32 Count) -> int32 - { - return UDPSend(ID, Data, Count); - }; - - Registration.Add(SourcePass.ID, NewRegistration); - - PreRegistration.Remove(SourceAddrStr); - - UE_LOG(LogRedNetwork, Log, TEXT("Register connection %i."), SourcePass.ID); - - OnLogin.Broadcast(SourcePass.ID); - } - } - } - - if (Registration.Contains(SourcePass.ID)) - { - Registration[SourcePass.ID].RecvTime = NowTime; - } - - // 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); - } - } - } - - // handle pre-registration timeout - { - TArray PreRegistrationAddr; - PreRegistration.GetKeys(PreRegistrationAddr); - - for (const FString& Addr : PreRegistrationAddr) - { - if (NowTime - PreRegistration[Addr].Time > TimeoutLimit) - { - UE_LOG(LogRedNetwork, Log, TEXT("Pre-registration pass %i timeout."), PreRegistration[Addr].Pass.ID); - - PreRegistration.Remove(Addr); - } - } - } - - // handle running timeout - { - TArray RegistrationAddr; - Registration.GetKeys(RegistrationAddr); - - for (int32 ID : RegistrationAddr) - { - if (NowTime - Registration[ID].RecvTime > TimeoutLimit) - { - UE_LOG(LogRedNetwork, Log, TEXT("Registration connection %i timeout."), Registration[ID].Pass.ID); - - Registration.Remove(ID); - - OnUnlogin.Broadcast(ID); - } - } - } - - // handle kcp recv - { - TArray RegistrationAddr; - Registration.GetKeys(RegistrationAddr); - - for (int32 ID : RegistrationAddr) - { - while (Registration[ID].KCPUnit) - { - int32 Size = Registration[ID].KCPUnit->PeekSize(); - - 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); - } - } - } + UpdateKCP(); + SendHeartbeat(); + HandleSocketRecv(); + HandleKCPRecv(); + HandleExpiredReadyPass(); + HandleExpiredConnection(); } void URedNetworkServer::Activate(bool bReset) @@ -331,7 +275,7 @@ void URedNetworkServer::Activate(bool bReset) return; } - NextRegistrationID = 1; + NextReadyID = 1; UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server activate.")); @@ -342,10 +286,10 @@ void URedNetworkServer::Deactivate() { if (!bIsActive) return; - TArray RegistrationAddr; - Registration.GetKeys(RegistrationAddr); + TArray ConnectionsAddr; + Connections.GetKeys(ConnectionsAddr); - for (int32 ID : RegistrationAddr) + for (int32 ID : ConnectionsAddr) { OnUnlogin.Broadcast(ID); } @@ -356,10 +300,9 @@ void URedNetworkServer::Deactivate() SendBuffer.SetNum(0); RecvBuffer.SetNum(0); - DataBuffer.SetNum(0); - PreRegistration.Reset(); - Registration.Reset(); + ReadyPass.Reset(); + Connections.Reset(); UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server deactivate.")); diff --git a/Source/RedNetwork/Private/RedNetworkType.cpp b/Source/RedNetwork/Private/RedNetworkType.cpp index 18bc0a8..bcd9704 100644 --- a/Source/RedNetwork/Private/RedNetworkType.cpp +++ b/Source/RedNetwork/Private/RedNetworkType.cpp @@ -1 +1,62 @@ #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; +} diff --git a/Source/RedNetwork/Public/RedNetworkClient.h b/Source/RedNetwork/Public/RedNetworkClient.h index c3edf79..ee4ba4a 100644 --- a/Source/RedNetwork/Public/RedNetworkClient.h +++ b/Source/RedNetwork/Public/RedNetworkClient.h @@ -43,7 +43,7 @@ public: void Deactivate(); UFUNCTION(BlueprintCallable, Category = "Red|Network") - bool IsLogged() const { return ClientPass.ID | ClientPass.Key; } + bool IsLogged() const { return ClientPass.IsValid(); } UFUNCTION(BlueprintCallable, Category = "Red|Network") bool Send(const TArray& Data); @@ -72,7 +72,6 @@ private: TArray SendBuffer; TArray RecvBuffer; - TArray DataBuffer; FRedNetworkPass ClientPass; @@ -81,7 +80,16 @@ private: TSharedPtr 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: diff --git a/Source/RedNetwork/Public/RedNetworkServer.h b/Source/RedNetwork/Public/RedNetworkServer.h index c73545d..641febf 100644 --- a/Source/RedNetwork/Public/RedNetworkServer.h +++ b/Source/RedNetwork/Public/RedNetworkServer.h @@ -8,6 +8,7 @@ class FSocket; class FKCPWrap; +class FInternetAddr; UCLASS(BlueprintType) class REDNETWORK_API URedNetworkServer : public UObject, public FTickableGameObject @@ -67,19 +68,18 @@ private: TArray SendBuffer; TArray RecvBuffer; - TArray DataBuffer; - int32 NextRegistrationID; + int32 NextReadyID; - struct FPreRegistrationInfo + struct FReadyInfo { FDateTime Time; FRedNetworkPass Pass; }; - TMap PreRegistration; + TMap ReadyPass; - struct FRegistrationInfo + struct FConnectionInfo { FRedNetworkPass Pass; FDateTime RecvTime; @@ -88,9 +88,21 @@ private: TSharedPtr KCPUnit; }; - TMap Registration; + TMap 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& SourceAddr); + void RedirectConnection(const FRedNetworkPass& SourcePass, const TSharedRef& SourceAddr); + void RegisterConnection(const FRedNetworkPass& SourcePass, const TSharedRef& SourceAddr); + void HandleKCPRecv(); + void HandleExpiredReadyPass(); + void HandleExpiredConnection(); public: diff --git a/Source/RedNetwork/Public/RedNetworkType.h b/Source/RedNetwork/Public/RedNetworkType.h index dc36313..3303d1f 100644 --- a/Source/RedNetwork/Public/RedNetworkType.h +++ b/Source/RedNetwork/Public/RedNetworkType.h @@ -6,4 +6,15 @@ struct REDNETWORK_API FRedNetworkPass { int32 ID; int32 Key; + + FRedNetworkPass(); + FRedNetworkPass(uint8* Data); + + void FromBytes(const uint8* Data); + void ToBytes(uint8* Data) const; + + void RandKey(); + void Reset(); + + bool IsValid() const; };