RxWebSocket is a WebSocket client for Unity and .NET Standard2.0/2.1. Since Unity 2018 supports .NET Standard 2.0, ClientWebSocket can be used. Therefore, WebSocket protocol can be used without an extra library. However, ClientWebSocket is very cumbersome. RxWebSocket is a wrapper of ClientWebSocket for easy handling.
UWP | iOS | Android | Windows10 Standalone | Mac OSX Standalone | |
---|---|---|---|---|---|
IL2CPP | ⭕️ | ⭕️ | |||
Mono (.NET Standard2.0 & .NET 4.x) |
⭕️ | ⭕️ | ⭕️ | ||
.NET Backend | ❌ |
dotnet add package RxWebSocket
The main class is WebSocketClient
.
Various settings can be made in the constructor.
- Logger
- If you are using unity, you can use the
UnityConsoleLogger
class. It is a simple wrapper such as Debug.log (). - if you use
Microsoft.Extensions.Logging.ILogger<T>
in ASP.NET Core or Console environment, it is easy to integrate usingAsWebSocketLogger()
which is extension method.
- If you are using unity, you can use the
- Memory settings for receiving.
- You can set how to use the memory when receiving messages.
- By default, a 64KB buffer is allocated. The buffer is automatically expanded as needed.
- If you know that you will receive large messages, a larger initial memory allocation will reduce wasted allocation.
- Message sending method setting.
- Internally, System.Threading.Channels is run in the background to send messages.
- You can choose various sending methods by using these classes.
- WebSocket Options(KeepAliveInterval, Proxy,...)
- If you want to make detailed settings for WebSocket, use the factory method. This is because the
class ClientWebSocketOptions
constructor is interlnal. You can set like this.
- If you want to make detailed settings for WebSocket, use the factory method. This is because the
#if Unity
var webSocketClient = new WebSocketClient(new Uri("wss://echo.websocket.org/"), logger: new UnityConsoleLogger());
#else
Microsoft.Extensions.Logging.ILogger<T> logger;
var webSocketClient = new WebSocketClient(new Uri("wss://echo.websocket.org/"), logger: logger.AsWebSocketLogger());
#endif
//IObservable<byte[]>
webSocketClient.BinaryMessageReceived
.Subscribe(x => DoSomething(x));
// IObservable<string>
webSocketClient.TextMessageReceived
.Subscribe(x => DoSomething(x));
// IObservable<byte[]>
webSocketClient.RawTextMessageReceived
.Subscribe(x => DoSomething(x));
/// Invoke when a close message is received,
/// before disconnecting the connection in normal system.
webSocketClient.CloseMessageReceived
.Subscribe(x => DoSomething(x));
webSocketClient.OnDispose
.Subscribe(_ => DoSomething());
//Issued when an exception occurs in processing of the background thread(receiving and sending).
webSocketClient.ExceptionHappenedInBackground
.Subscribe(x => DoSomething(x));
try
{
//connect and start listening in background thread.
//await until websocket can connect.
await webSocketClient.ConnectAsync();
//Send() method return bool.
//If you set the channel created by Channel.CreateBounded () when setting the transmission method,
//false may be returned if it is not possible to write to the queue.
//Send() function end as soon as writing is completed in the queue.
//Therefore, it does not matter whether the sending is finished.
byte[] array = MakeSomeArray();
bool check1 = webSocketClient.Send(array);
bool check2 = webSocketClient.Send("string or byte[]");
//The SendInstant function ignores the queue used inside the Send function and sends it immediately.
//await for transmission to complete.
await webSocketClient.SendInstant("string or byte[]");
//You can decide whether to dispose at the same time as Close with the last bool parameter.
await webSocketClient.CloseAsync(WebSocketCloseStatus.NormalClosure, "description", true);
}
catch
{
}
Server Code (ASP.NET Core)
HttpContext context;
Microsoft.Extensions.Logging.ILogger<T> logger;
if (!context.WebSockets.IsWebSocketRequest) return;
WebSocket socket = await context.WebSockets.AcceptWebSocketAsync();
//You can set the connected socket in the constructor.
using var webSocketClient = new WebSocketClient(socket, logger: logger.AsWebSocketLogger());
// subscribe setting...
await webSocketClient.ConnectAsync();
//If you do not wait, the connection will be disconnected.
await webSocketClient.WaitUntilCloseAsync();
Here is sample.
You can set how to use the memory when receiving messages.
By default, a 64KB buffer is allocated. The buffer is automatically expanded as needed.
If you know that you will receive large messages, a larger initial memory allocation will reduce wasted allocation.
You can use ReceiverMemoryConfig
.
// 1024KB
var config = new ReceiverMemoryConfig(1024 * 1024);
var client = new WebSocketClient(uri, receiverConfig: config);
Internally, System.Threading.Channels is run in the background to send messages. You can choose various sending methods by using the following class.
SingleQueueSender
- By using a single queue, the sending order of both Binary type and Text Type is guaranteed.
- It is default.
DoubleQueueSender
- By using two queues, the sending order of Binary type and Text Type is guaranteed separately.
BinaryOnlySender
- Use one queue to send only binary type messages. It is less allocations than SingleQueueSender.
TextOnlySender
- Use one queue to send only text type messages. It is less allocations than SingleQueueSender.
The above class can inject a Channel in its constructor. By default Channel.CreateUnbounded is used, but if you want to limit the capacity you can use Channel.CreateBounded. At that time, it is recommended to set SingleReader = true, SingleWriter = false
in the options of Channel
class.
var client = new WebSocketClient(new Uri(uri), new DoubleQueueSender());
var channel = Channel.CreateBounded<SentMessage>(new BoundedChannelOptions(5) { SingleReader = true, SingleWriter = false });
var client = new WebSocketClient(new Uri(uri), new SingleQueueSender(channel));
If you want to make detailed settings for WebSocket, use the factory method.
var factory = new Func<ClientWebSocket>(() => new ClientWebSocket
{
Options =
{
KeepAliveInterval = TimeSpan.FromSeconds(5),
Proxy = ...
ClientCertificates = ...
}
});
var webSocketClient = new WebSocketClient(url, clientFactory: factory);
WebSocketClient issues all events from thread pool. Therefore, you cannot operate the components on Unity in Subscribe directly. So please handle from the main thread using an operator such as 'ObserveOnMainThread' as follows.
//error will occur.
webSocketClient.TextMessageReceived
.Subscribe(x => unityObj.text = x);
//The following is correct.
webSocketClient.TextMessageReceived
.ObserveOnMainThread()
.Subscribe(x => unityObj.text = x);
I prepared a simple chat app as a sample. When the server starts, connect to ws://ip:port/ws
.
open this scene and run.
Requires .NET Core3.1. First, set your ip here. Then type the following command
$ cd Sample/Server/WebSocketChat/WebSocketChat/
$ dotnet run