Hello, I couldn’t seem to find a good example of a TCP health check, so I figured I would make one myself. Hope this helps others!
Just add this actor to the map your dedicated server is running, and add this to your DefaultGame.ini file:
[/Script/<YOUR_GAME>.HealthCheckListener]
HealthCheckIp="0.0.0.0"
HealthCheckPort=7787
HealthCheckListener.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "HealthCheckListener.generated.h"
struct FIPv4Endpoint;
class FTcpListener;
UCLASS(Config=Game, Blueprintable, meta=(BlueprintSpawnableComponent))
class YOURGAME_API AHealthCheckListener : public AActor
{
GENERATED_BODY()
public:
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void FinishDestroy() override;
protected:
virtual void BeginPlay() override;
private:
UPROPERTY(Config)
FString HealthCheckIp;
UPROPERTY(Config)
int HealthCheckPort;
TSharedPtr<FRunnableThread> Thread;
TSharedPtr<FTcpListener> Listener;
bool OnConnectionAccepted(FSocket* Socket, const FIPv4Endpoint& Endpoint);
};
HealthCheckListener.cpp
#include "HealthCheckListener.h"
#include "Common/TcpListener.h"
#include "Common/TcpSocketBuilder.h"
#include "Interfaces/IPv4/IPv4Address.h"
void AHealthCheckListener::BeginPlay()
{
Super::BeginPlay();
// if we aren't running a dedi exit
if (!IsRunningDedicatedServer()) return;
FIPv4Address IPAddress;
FIPv4Address::Parse(HealthCheckIp, IPAddress);
const FIPv4Endpoint Endpoint(IPAddress, HealthCheckPort);
if(const auto& ListenSocket = FTcpSocketBuilder(TEXT("HealthCheckSocket"))
.AsReusable()
.BoundToEndpoint(Endpoint)
.Listening(10)
.Build())
{
ListenSocket->SetNoDelay(true);
ListenSocket->SetLinger(true, 0);
ListenSocket->SetNonBlocking(false);
Listener = MakeShared<FTcpListener>(*ListenSocket);
Listener->OnConnectionAccepted().BindUObject(this, &AHealthCheckListener::OnConnectionAccepted);
if (Listener->Init())
{
Thread = TSharedPtr<FRunnableThread>( FRunnableThread::Create(Listener.Get(), TEXT("HealthCheckThread"), 0, TPri_BelowNormal));
}
}
}
void AHealthCheckListener::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if(Listener)
{
Listener->Stop();
}
}
void AHealthCheckListener::FinishDestroy()
{
Super::FinishDestroy();
if(Listener)
{
Listener->Exit();
Listener = nullptr;
}
if (Thread)
{
Thread->Kill(true);
Thread = nullptr;
}
}
bool AHealthCheckListener::OnConnectionAccepted(FSocket* Socket, const FIPv4Endpoint& Endpoint)
{
// can handle the incoming socket here if needed
// close the socket before finishing
Socket->Close();
return true;
}