Awesome
WebSocket Client for Unity
WebSocketConnection
is an easy-to-use WebSocket client for Unity that Just Works
Features
- Easy to use
WebSocketConnection
is just aMonoBehaviour
- Using
async/await
is optional: event listeners, coroutines, and polling are supported - Doesn't force
#if
for WebGL: no conditional-compilation required - Public API prevents you from corrupting an active connection
- Reusable: connect, disconnect, change URL, connect again from one
WebSocketConnection
- Flexible config
- URL is the only required config
- Sane defaults
- Optionally set subprotocols, max send, and max receive bytes
- Wide platform support
- No external install requirements or dependencies
string
is treated as text andbyte[]
as binary (some servers care)- Customizable ping-pong support for servers that enforce idle timeouts
- Includes support for
WebAssembly.Table
(Unity 2023.2+) - Web uses a
.jslib
JavaScript library, other platforms use the built-inSystem.Net.WebSockets
Install
See official instructions for how to Install a Package from a Git URL. The URL is
https://github.com/mikerochip/unity-websocket.git
⚠️ Known Limitations ⚠️
- Headers aren't supported in WebGL because the JavaScript WebSocket API doesn't support them
- See this StackOverflow issue for more.
- You can't bypass server certificate validation when connecting to a secure websocket endpoint (
wss
). That means the endpoint must have a CA-verifiable SSL certificate, it can't have no certs installed or only self-signed certs.- For WebGL, this is due to a limitation in the JavaScript WebSocket API
- For .NET, this is due to a bug in Unity's mono runtime
- There is an active issue to address this, but no timeframe for resolution, currently.
Samples
Assume we have a class like this for the following samples:
using MikeSchweitzer.WebSocket;
public class Tester : MonoBehaviour
{
public WebSocketConnection _Connection;
public string _Url = "wss://ws.postman-echo.com/raw";
}
Connect
// inline style
public void Connect()
{
_Connection.Connect(_Url);
}
// property style
public void Connect()
{
_Connection.DesiredConfig = new WebSocketConfig
{
Url = _Url,
};
_Connection.Connect();
}
Disconnect
public void Disconnect()
{
_Connection.Disconnect();
}
State Querying
Update Style
private WebSocketState _oldState;
private void Update()
{
var newState = WebSocketConnection.State;
if (_oldState != newState)
{
Debug.Log($"OnStateChanged oldState={_oldState}|newState={newState}");
_oldState = newState;
}
}
Event Style
private void Awake()
{
_Connection.StateChanged += OnStateChanged
}
private void OnDestroy()
{
_Connection.StateChanged -= OnStateChanged;
}
private void OnStateChanged(WebSocketConnection connection, WebSocketState oldState, WebSocketState newState)
{
Debug.Log($"OnStateChanged oldState={oldState}|newState={newState}");
}
Reconnect
Coroutine Style
public IEnumerator Reconnect()
{
Disconnect();
yield return new WaitUntil(_Connection.State == WebSocketState.Disconnected);
// you may change the desired url now, if you want
Connect();
}
Event Style
private void OnStateChanged(WebSocketConnection connection, WebSocketState oldState, WebSocketState newState)
{
switch (newState == WebSocketState.Disconnected)
{
// you may change the desired url now, if you want
_Connection.Connect();
}
}
Error Messages
NOTE: These are just error messages, not states. See the State Querying section.
Error messages are generally derived from platform-specific WebSocket errors.
private void Awake()
{
_Connection.ErrorMessageReceived += OnErrorMessageReceived;
}
private void OnDestroy()
{
_Connection.ErrorMessageReceived -= OnErrorMessageReceived;
}
private void OnErrorMessageReceived(WebSocketConnection connection, string errorMessage)
{
Debug.LogError(errorMessage);
// you can also use _Connection.ErrorMessage
}
Send Messages
⚠️ You must be Connected
to send messages, otherwise you will get an error
public void SendString()
{
_Connection.AddOutgoingMessage("hello");
}
public void SendBinary()
{
var bytes = Encoding.UTF8.GetBytes("hello");
_Connection.AddOutgoingMessage(bytes);
}
Receive Messages
Update Style
private void Update()
{
while (_Connection.TryRemoveIncomingMessage(out string message))
Debug.Log(message);
}
Event Style
private void Awake()
{
_Connection.MessageReceived += OnMessageReceived;
}
private void OnDestroy()
{
_Connection.MessageReceived -= OnMessageReceived;
}
private void OnMessageReceived(WebSocketConnection connection, WebSocketMessage message)
{
Debug.Log(message.String);
}
Coroutine Style
private void Awake()
{
StartCoroutine(ReceiveMessages());
}
private IEnumerator ReceiveMessages()
{
while (true)
{
if (_Connection.TryRemoveIncomingMessage(out string message))
Debug.Log(message);
yield return null;
}
}
Async/Await Style
private CancellationTokenSource _cts;
private async void Awake()
{
_cts = new CancellationTokenSource();
await ReceiveMessagesAsync();
}
private void OnDestroy()
{
_cts.Cancel();
}
private async Task ReceiveMessagesAsync()
{
while (!_cts.IsCancellationRequested)
{
if (_Connection.TryRemoveIncomingMessage(out string message))
Debug.Log(message);
await Task.Yield();
}
}
Customizable Ping-Pong Support
This package has a custom ping-pong system that you can use regardless of platform.
⚠️ Your server must be configured to echo messages of the same message type (text or binary) and content.
⚠️ This package has custom ping-pong support because the JavaScript WebSocket client does not implement the WebSocket Ping Pong spec even though .NET's WebSocketClient
does implement the spec.
private void ConfigureStringPings()
{
_Connection.DesiredConfig = new WebSocketConfig
{
PingInterval = TimeSpan.FromSeconds(30),
PingMessage = new WebSocketMessage("ping"),
};
}
private byte[] _pingBytes = Encoding.UTF8.GetBytes("ping");
private void ConfigureBinaryPings()
{
_Connection.DesiredConfig = new WebSocketConfig
{
PingInterval = TimeSpan.FromSeconds(30),
PingMessage = new WebSocketMessage(_pingBytes),
};
}
Attribution
Based on this repo by Endel Dreyer, which was
Based on this repo by Jiri Hybek
See license and third party notices for full attribution.