Secure WSS Connections in Unreal Engine
Overview
BlueprintWebSocket is an advanced asynchronous networking plugin for Unreal Engine. It enables real-time duplex data transfers with external servers using the WebSocket network architecture, specifically optimized for establishing production-grade TLS/SSL handshake configurations over secure network layers requiring strict authorization.
Download the plugin from the Fab Marketplace to initialize real-time networking elements in your current workspace.
- Blueprints and C++: Native support inside visual script node trees as well as raw C++ source modules.
- Asynchronous Threading: Non-blocking background workers preserve main render thread frame pacing.
- Garbage Collection Lifecycle: Leverages Unreal Engine's standard reference routing to manage object allocation safety automatically.
- Data Payloads: Flexible interfaces handle text-based UTF-8 serialization or custom uint8 payload byte arrays.
Blueprints
Connecting to a WebSocket server
Using the latency-helper node, you can connect to an active network socket and run automated execution chains immediately:
For custom logic structures, create an explicit socket instance to hook up callback events directly into event graph dispatchers:
Sending Data
Automatically Reconnect on Error
Handle dropouts automatically by defining retry parameters within your baseline node sequence:
C++
Adding the Module
Open your source build configuration file (<ProjectName>.Build.cs) and add the module dependency into your compile instruction lists:
PublicDependencyModuleNames.Add("BlueprintWebSocket");
Include
Expose the interface types by placing the wrapper header in your class file:
#include "BlueprintWebSocketWrapper.h"
Creating a new WebSocket
Instantiate a heap allocation using the plugin factory method:
UBlueprintWebSocket* const WebSocket = UBlueprintWebSocket::CreateWebSocket();
Configuring the WebSocket
Modify transport metadata structures and authentication headers prior to invoking the connection handshake routine:
// Merges the provided map with the current header list.
WebSocket->SetHeaders(const TMap<FString, FString> & InHeaders);
// Adds a pair Key / Value to the list of headers.
WebSocket->AddHeader(const FString & Header, const FString & Value);
// Removes the header from the header list
WebSocket->RemoveHeader(const FString & HeaderToRemove);
Listening to events with Callbacks
Bind functional targets to the asynchronous delegates to receive network responses state modifications safely:
| Event Name | Signature | Description |
|---|---|---|
OnConnectedEvent |
void Func() |
Called when we are successfully connected to the WebSocket Server. |
OnConnectionErrorEvent |
void Func(const FString & Error) |
Called when we failed to connect to the WebSocket server. |
OnCloseEvent |
void Func(int64 StatusCode, const FString & Reason, bool bWasClean) |
Called when the connection with the server has been closed. |
OnMessageEvent |
void Func(const FString & Message) |
Called when we received a string message. |
OnRawMessageEvent |
void Func(const TArray<uint8> & Data, int32 BytesRemaining) |
Called when we received a binary message. |
OnMessageSentEvent |
void Func(const FString & Message) |
Called just after we sent a message. |
Because these hooks utilize Dynamic Multicast Delegates, any bound listener function must carry the UFUNCTION() decoration macro to remain visible within the engine invocation stack:
UCLASS()
class MYGAME_API UMyClass : public UObject
{
GENERATED_BODY()
public:
// The function we use to bind the events
void BindEvents();
private:
// Callbacks
UFUNCTION() void OnConnected();
UFUNCTION() void OnConnectionError(const FString & Error);
UFUNCTION() void OnClosed(int64 StatusCode, const FString & Reason, bool bWasClean);
UFUNCTION() void OnMessage(const FString & Message);
UFUNCTION() void OnRawMessage(const TArray<uint8> & Data, int32 BytesRemaining);
UFUNCTION() void OnMessageSent(const FString & Message);
private:
UPROPERTY()
UBlueprintWebSocket* WebSocket;
};
void UMyClass::BindEvents()
{
// Bind the events so our functions are called when the event is triggered.
WebSocket->OnConnectedEvent .AddDynamic(this, &UMyClass::OnConnected);
WebSocket->OnConnectionErrorEvent.AddDynamic(this, &UMyClass::OnConnectionError);
WebSocket->OnCloseEvent .AddDynamic(this, &UMyClass::OnClosed);
WebSocket->OnMessageEvent .AddDynamic(this, &UMyClass::OnMessage);
WebSocket->OnRawMessageEvent .AddDynamic(this, &UMyClass::OnRawMessage);
WebSocket->OnMessageSentEvent .AddDynamic(this, &UMyClass::OnMessageSent);
}
Notice: It is recommended to bind all events you will use before connecting.
Connecting to the WebSocket Server
Pass the explicit endpoint URI and communication protocol sub-strings directly into the connection processing loop:
WebSocket->Connect(TEXT("wss://secure.yourserver.com:443/"), TEXT("ws"));
Query state frames inline via the functional status checkers:
if (WebSocket->IsConnected())
{
// We are connected.
}
else
{
// We are not connected.
}
Notice: You shouldn't rely on IsConnected() to handle connection but on the OnConnectedEvent callback.
Sending Messages
Transmit information downstream using structured strings or direct memory buffers:
void SendMessage(const FString & Message): For passing textual/JSON data formats.void SendRawMessage(const TArray<uint8> & Message, const bool bIsBinary): For pushing compressed structures or asset files.
Implementation sample:
// The data we want to send, you can get it programmatically.
const FString StringMessage = TEXT("Hello Server");
const TArray<uint8> BinaryMessage = { 0, 1, 2, 3, 4, 5 };
// Send it through our WebSocket.
WebSocket->SendMessage (StringMessage);
WebSocket->SendRawMessage(BinaryMessage);
Full Example
MyClass.h
#pragma once
#include "CoreMinimal.h"
#include "MyClass.generated.h"
class UBlueprintWebSocket;
/**
* Our custom class that uses a WebSocket.
**/
UCLASS()
class MYGAME_API UMyClass : public UObject
{
GENERATED_BODY()
public:
void InitializeAndConnectSocket();
private:
UFUNCTION()
void OnConnected();
UFUNCTION()
void OnConnectionError(const FString & Error);
UFUNCTION()
void OnClosed(int64 StatusCode, const FString & Reason, bool bWasClean);
UFUNCTION()
void OnMessage(const FString & Message);
UFUNCTION()
void OnRawMessage(const TArray<uint8> & Data, int32 BytesRemaining);
UFUNCTION()
void OnMessageSent(const FString & Message);
private:
UPROPERTY()
UBlueprintWebSocket* WebSocket;
};
MyClass.cpp
#include "MyClass.h"
#include "BlueprintWebSocketWrapper.h"
void UMyClass::InitializeAndConnectSocket()
{
WebSocket = UBlueprintWebSocket::CreateWebSocket();
WebSocket->OnConnectedEvent .AddDynamic(this, &UMyClass::OnConnected);
WebSocket->OnConnectionErrorEvent.AddDynamic(this, &UMyClass::OnConnectionError);
WebSocket->OnCloseEvent .AddDynamic(this, &UMyClass::OnClosed);
WebSocket->OnMessageEvent .AddDynamic(this, &UMyClass::OnMessage);
WebSocket->OnRawMessageEvent .AddDynamic(this, &UMyClass::OnRawMessage);
WebSocket->OnMessageSentEvent .AddDynamic(this, &UMyClass::OnMessageSent);
WebSocket->AddHeader(TEXT("SomeHeader"), TEXT("SomeValue"));
WebSocket->Connect(TEXT("wss://secure.yourserver.com:443/"), TEXT("ws"));
}
void UMyClass::OnConnected()
{
UE_LOG(LogTemp, Log, TEXT("We are connected!"));
WebSocket->SendMessage(TEXT("Hello Server!"));
}
void UMyClass::OnConnectionError(const FString & Error)
{
UE_LOG(LogTemp, Error, TEXT("Failed to connect: %s."), *Error);
}
void UMyClass::OnClosed(int64 StatusCode, const FString & Reason, bool bWasClean)
{
UE_LOG(LogTemp, Warning, TEXT("Connection closed: %d:%s. Clean: %d"), StatusCode, *Reason, bWasClean);
}
void UMyClass::OnMessage(const FString & Message)
{
UE_LOG(LogTemp, Log, TEXT("New message: %s"), *Message);
}
void UMyClass::OnRawMessage(const TArray<uint8> & Data, int32 BytesRemaining)
{
UE_LOG(LogTemp, Log, TEXT("New binary message: %d bytes and %d bytes remaining."), Data.Num(), BytesRemaining);
}
void UMyClass::OnMessageSent(const FString & Message)
{
UE_LOG(LogTemp, Log, TEXT("We just sent %s to the server."), *Message);
}
Troubleshooting
Failed to connect: SSL error: unable to get local issuer certificate
This network security issue arises because public validation root authorities are omitted from the platform bundle inside fully cooked game distributions. Resolve the distribution package integrity via these steps:
- Stage your active authorization certificate authority file (
.pemformat) to your project source path:<Project>/Content/Certificates/cacert.pem. - Expose the target subdirectory to the platform packager via Project Settings > Packaging > Additional Non-Assets Directories To Copy list arrays.
Support
For feature recommendations or functional support updates, open a developer request ticket directly with our core engineering desk at: pandores.marketplace@gmail.com.