-
Notifications
You must be signed in to change notification settings - Fork 0
Web Socket
CefWebSocketServer is the WebUserInterface plugin's local WebSocket server module. It exposes named servers through a UGameInstanceSubsystem, keeps one Unreal server object per name, supports multiple clients, and provides Blueprint and C++ APIs for messaging and lifecycle control.
Source: Source/CefWebSocketServer
Use this module when browser JavaScript, an external tool, or another local process needs a live bidirectional connection to Unreal. Typical uses include:
- sending UI actions from a CEF page to game code;
- pushing game state, settings, or notifications to one or many browser clients;
- connecting an editor/debug dashboard to a running Unreal instance;
- carrying JSON or text during development and switching to binary/protobuf messages later;
- keeping networking and payload encoding separate from gameplay objects.
The module is designed for local UI and tooling bridges. It is not a replacement for a production internet-facing service, authentication layer, or gameplay replication system. Add your own authorization and message validation before exposing a server beyond a trusted local client.
Choose CefWebSocketServer when the connection should be long-lived, two-way, and event-driven. It is a good fit when the browser needs to send commands and receive asynchronous updates without polling an HTTP endpoint.
Use the CefContentHttpServer module instead when the browser only needs request/response access to Unreal assets such as images. Use normal Unreal networking or an external service when the connection must support remote players, authentication, or internet deployment.
Each named server has a four-stage pipeline:
socket read -> inbound queue -> decode/handle queue -> send queue -> per-client write queue -> socket write
- Read receives WebSocket frames and applies message-size and receive-rate limits.
- Handle decodes the selected payload format and invokes the server/client handlers.
- Send encodes outbound requests and routes them to a client or to all clients.
- Write flushes queued frames to each socket in bounded batches.
The pipeline prevents socket I/O from blocking the game thread and exposes queue depth and throughput statistics for diagnosis. Server lifecycle objects live with the UGameInstanceSubsystem, so servers remain available until explicitly stopped or the game instance deinitializes.
Set FCefWebSocketPipelineConfig::InPayloadFormat to one of the built-in formats:
| Format | Use when |
|---|---|
Binary |
The protocol is already encoded as bytes, such as protobuf. |
Utf8String |
The protocol is plain UTF-8 text. |
JsonString |
Browser-facing messages are JSON strings. |
XmlString |
An existing integration requires XML. |
Custom |
The application owns both encode and decode rules. |
JsonString is usually the easiest starting point for a browser UI. Binary or Custom is preferable for compact, schema-driven protocols; pair it with the CefProtobuf and CefDispatch modules when appropriate.
- Get
CefWebSocketSubsystemfrom the currentGameInstance. - Build
FCefWebSocketServerCreateOptions:- set a unique
NameId, such asUiBridge; - set
RequestedPortto a fixed port, or0to let the module choose; - set the pipeline payload format, for example
JsonString.
- set a unique
- Call
CreateOrGetServerwith a server class and client class. The module returns the server object and aFCefWebSocketServerCreateResult. - Check the result and use
BoundPortwhen the requested port was unavailable and auto-adjustment occurred. - Bind
OnClientConnected,OnClientDisconnected,OnServerError, andOnClientError. - Send with
SendToClientString,SendToClientBytes,BroadcastString, orBroadcastBytes. - Stop with
StopServer(NameId)orStopAllServers()during explicit shutdown.
Each connected client receives a stable ClientId for the lifetime of that connection. Use GetClients, GetClient, and GetStats on the server to inspect connected clients and health.
#include "Data/CefWebSocketEnums.h"
#include "Data/CefWebSocketStructs.h"
#include "Server/CefWebSocketClientBase.h"
#include "Server/CefWebSocketServerBase.h"
#include "Subsystems/CefWebSocketSubsystem.h"
void UMyGameInstance::StartUiBridge()
{
UCefWebSocketSubsystem* subsystem = GetSubsystem<UCefWebSocketSubsystem>();
if (!subsystem)
{
return;
}
FCefWebSocketServerCreateOptions options;
options.NameId = FName(TEXT("UiBridge"));
options.RequestedPort = 7001;
options.InPipelineConfig.InPayloadFormat = ECefWebSocketPayloadFormat::JsonString;
UCefWebSocketServerBase* server = nullptr;
const FCefWebSocketServerCreateResult result = subsystem->CreateOrGetServer(
options,
UCefWebSocketServerBase::StaticClass(),
UCefWebSocketClientBase::StaticClass(),
server);
if (!server || result.Result == ECefWebSocketCreateResult::Failed)
{
return;
}
server->BroadcastString(TEXT("{\"type\":\"server-online\"}"));
}The browser can connect to the bound port with a normal WebSocket client:
const socket = new WebSocket("ws://127.0.0.1:7001");
socket.onmessage = (event) => console.log("UE:", event.data);
socket.onopen = () => socket.send(JSON.stringify({ type: "ui-ready" }));The actual port should come from FCefWebSocketServerCreateResult::BoundPort if port auto-adjustment is allowed.
For a small integration, subclass UCefWebSocketServerBase and override:
-
HandleClientString(UCefWebSocketClientBase*, const FString&); -
HandleClientBytes(UCefWebSocketClientBase*, const TArray<uint8>&).
You can also subclass UCefWebSocketClientBase and override its HandleStringFromClient or HandleBytesFromClient methods. The base client object provides GetClientId, GetRemoteAddress, SendString, SendBytes, and Disconnect.
The default handlers are empty. The module invokes them from its handling pipeline, not as a general game-thread event dispatcher. If a handler needs to mutate actors, UObjects, widgets, or other game-thread state, copy/validate the message and enqueue a small command to the game thread before touching that state.
Implement ICefWebSocketPacketCodec when built-in formats are not enough. The codec must provide:
bool DecodeInbound(
const FCefWebSocketInboundPacket& input,
FCefWebSocketInboundPacket& decoded,
FString& error);
bool EncodeSendRequest(
const FCefWebSocketSendRequest& request,
TArray<FCefWebSocketWritePacket>& output,
FString& error);
ECefWebSocketPayloadFormat GetPayloadFormat() const;Install it with SetPacketCodec from C++. Keep codec ownership and thread safety in mind: encode/decode work happens in the pipeline, so shared mutable state must be protected or avoided.
Available server operations include:
-
SendToClientString/SendToClientBytesfor one client; -
BroadcastString/BroadcastBytesfor every client; -
BroadcastStringExcept/BroadcastBytesExceptfor every client except one; -
DisconnectClientto close one connection with a reason; -
StopServerto stop the server and clear its client objects.
CreateOrGetServer is idempotent by NameId: calling it again returns the existing server and does not create a second listener for that name. Requested ports may auto-adjust to the next available port. Treat BoundPort as authoritative.
Send methods return ECefWebSocketSendResult. Important failure cases include InvalidClient, Disconnected, QueueFull, TooLarge, SerializeFailed, and InvalidUtf8.
The pipeline has bounded queues. Monitor GetStats and decide how the application should behave when a queue fills: drop/coalesce transient UI updates, reject a command, or report an error. Do not assume every send is immediately written to the socket.
Relevant limits include:
| CVar | Purpose |
|---|---|
cefws.max_message_bytes |
Maximum inbound message size. |
cefws.max_text_message_bytes |
Maximum text-frame size. |
cefws.max_outbound_message_bytes |
Maximum outbound payload size. |
cefws.max_rx_bytes_per_sec_per_client |
Per-client receive bandwidth cap. |
cefws.max_tx_bytes_per_sec_per_client |
Per-client send bandwidth cap. |
cefws.max_queue_messages_per_client |
Global per-client outbound message limit. |
cefws.max_queue_bytes_per_client |
Global per-client outbound byte limit. |
cefws.queue_drop_policy |
0 drops oldest; 1 rejects new messages. |
cefws.heartbeat_interval_sec |
Heartbeat interval; <=0 disables it. |
cefws.idle_timeout_sec |
Client idle timeout; <=0 disables it. |
cefws.validate_utf8 |
Validates text payloads when enabled. |
cefws.log_traffic |
Enables payload-flow logging. |
Adjust limits for the application rather than disabling safety checks by default.
Use the Unreal console commands:
ws.list
ws.stats UiBridge
ws.kick UiBridge <clientId>
ws.stop UiBridge
ws.list and ws.stats expose active clients, traffic, dropped messages, and queue depths for the inbound, handle, send, and write stages. Start with cefws.log_traffic 1 for a short diagnostic session, then turn it off when finished.
- Using a port that is already occupied and ignoring
BoundPortafter auto-adjustment. - Creating multiple servers with different names when one bridge would be sufficient.
- Calling game-thread-only Unreal APIs directly from a message handler.
- Sending large or high-frequency updates without considering queue limits.
- Using JSON for large/high-rate binary data when protobuf or a custom codec would be more appropriate.
- Exposing the local listener to untrusted clients without authentication and message validation.