TCP Health Check

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;
}

1 Like