Building a WebSocket Server with SuperSocket 2.0
This implementation targets a development environment utilizing Windows 10, Visual Studio 2019, and .NET Core 3.1, relying on the SuperSocket.WebSocket.Server version 2.0.0-beta.8 library.
To instantiate a WebSocket server, the WebSocketHostBuilder class is employed. This builder allows for the configuration of message handlers, WebSocket parameters, and logging via a fluent API. When integrating custom command logic, it is necessary to transform the raw WebSocketPackage into a StringPackageInfo object. This transformation is handled by a custom mapper, such as the MessageStringMapper detailed below.
It is important to note that command classes must inherit from IAsyncCommand<WebSocketSession, StringPackageInfo>. Furthermore, the priority lies with the command registration; if UseCommand is utilized to register specific commands, the fallback handler defined in UseWebSocketMessageHandler will be bypassed.
MessageStringMapper Implementation
using System;
using System.Linq;
using SuperSocket.ProtoBase;
using SuperSocket.WebSocket;
namespace WebSocketServerExample.Core
{
public class MessageStringMapper : IPackageMapper<WebSocketPackage, StringPackageInfo>
{
public StringPackageInfo Map(WebSocketPackage sourcePackage)
{
var packageInfo = new StringPackageInfo();
if (string.IsNullOrEmpty(sourcePackage.Message))
{
return packageInfo;
}
var segments = sourcePackage.Message.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
packageInfo.Key = segments[0];
// Use range operator to extract parameters efficiently
packageInfo.Parameters = segments.Length > 1 ? segments[1..] : Array.Empty<string>();
packageInfo.Body = segments.Length > 1 ? string.Join(" ", segments[1..]) : string.Empty;
return packageInfo;
}
}
}
Server Configuration and Startup
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SuperSocket.Command;
using SuperSocket.ProtoBase;
using SuperSocket.WebSocket.Server;
using WebSocketServerExample.Commands;
namespace WebSocketServerExample
{
internal class ServerBootstrap
{
public static async Task Main()
{
var hostBuilder = WebSocketHostBuilder.Create()
.ConfigureAppConfiguration((ctx, configBuilder) =>
{
configBuilder.AddInMemoryCollection(new Dictionary<string, string>
{
{"serverOptions:name", "PrimaryWebSocketHost"},
{"serverOptions:listeners:0:ip", "Any"},
{"serverOptions:listeners:0:port", "8080"}
});
})
.ConfigureLogging((ctx, loggingBuilder) =>
{
loggingBuilder.AddConsole();
})
.UseCommand<StringPackageInfo, MessageStringMapper>(commandConfig =>
{
// Register specific command implementations
commandConfig.AddCommand<AddCommand>();
commandConfig.AddCommand<DivCommand>();
commandConfig.AddCommand<MulCommand>();
commandConfig.AddCommand<SubCommand>();
commandConfig.AddCommand<EchoCommand>();
})
// Fallback handler (ignored if UseCommand processes the message)
.UseWebSocketMessageHandler(async (session, message) =>
{
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var response = $"[{timestamp}] Server received: {message.Message}";
await session.SendAsync(response);
})
.Build();
await hostBuilder.RunAsync();
}
}
}