Wrapping SuperSocket within a dedicated class library enables broader application compatibility, extending functionality beyond simple console utilities to support diverse deployment scenarios. The following guide demonstrates how to implement a reusable Telnet server wrapper.
Project Initialization
Create a new C# Class Libray project named ModularSocketLib. Integrate the necessary SuperSocket dependencies (SuperSocket.Common, SuperSocket.SocketBase, SuperSocket.SocketEngine) and a logging framework such as log4net. Ensure the log4net.config file is configured in the build process: set Build Action to "Content" and Copy Behavior to "Copy if newer". Place the config file in a directory designated for configurations.
Core Service Components
To define the communication logic, create the session handler and server implementations. These classes manage connection states and request processing.
namespace ModularSocketLib.Sockets { public class CustomSession : AppSession<CustomSession> { protected override void OnSessionStarted() { Console.WriteLine($"New Connection Established: {RemoteEndPoint.Address} : {RemoteEndPoint.Port}."); Send("Welcome to the Modular Socket Service."); }
protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
{
Console.WriteLine($"Received unrecognized command key: {requestInfo.Key}.");
Send("Request not recognized.");
}
protected override void HandleException(Exception e)
{
Console.WriteLine($"Runtime error detected: {e.Message}.");
Send($"Error encountered: {e.Message}.");
}
protected override void OnSessionClosed(CloseReason reason)
{
Console.WriteLine($"Connection terminated: {RemoteEndPoint.Address}:{RemoteEndPoint.Port} Reason: {reason}.");
base.OnSessionClosed(reason);
}
}
}
</div><div>```
<code>using System;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
namespace ModularSocketLib.Sockets
{
public class TcpServerInstance : AppServer<CustomSession>
{
protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
{
Console.WriteLine("Initializing Server Instance...");
return base.Setup(rootConfig, config);
}
protected override void OnStarted()
{
Console.WriteLine("Server instance active.");
base.OnStarted();
}
protected override void OnStopped()
{
Console.WriteLine("Server instance terminated.");
base.OnStopped();
}
}
}</code>
Implement specific commands to process incoming data strings. Here we define two commands: one for calculation and another for response.
namespace ModularSocketLib.Commands { public class SumCommand : CommandBase<CustomSession, StringRequestInfo> { public override string Name => "TOTAL";
public override void ExecuteCommand(CustomSession session, StringRequestInfo requestInfo)
{
Console.WriteLine($"Executing TOTAL: {requestInfo.Body}.");
var numbers = requestInfo.Parameters.Select(p => Convert.ToInt32(p)).ToList();
session.Send(numbers.Sum().ToString());
}
}
}
</div><div>```
<code>using System;
using SuperSocket.SocketBase.Command;
using SuperSocket.SocketBase.Protocol;
using ModularSocketLib.Sockets;
namespace ModularSocketLib.Commands
{
public class MirrorCommand : CommandBase<CustomSession, StringRequestInfo>
{
public override string Name => "REPLY";
public override void ExecuteCommand(CustomSession session, StringRequestInfo requestInfo)
{
Console.WriteLine($"Processing REPLY: {requestInfo.Body}.");
session.Send(requestInfo.Body);
}
}
}</code>
The most critical element for packaging is the manager class controlling the Bootstrap lifecycle. Using the Singleton pattern ensures a single active instance across the application domain.
namespace ModularSocketLib { public class SocketHostManager { private readonly IBootstrap _hostBootstrap;
public bool Initialize(int targetPort)
{
if (!_hostBootstrap.Initialize())
{
Console.WriteLine("Bootstrap initialization failed.");
return false;
}
var status = _hostBootstrap.Start();
Console.WriteLine($"Startup Status: {status}.");
return status == StartResult.Success;
}
public void Terminate()
{
_hostBootstrap.Stop();
}
#region Singleton Implementation
private static SocketHostManager _singleton;
private static readonly object SyncRoot = new object();
private SocketHostManager()
{
var assemblyPath = Assembly.GetExecutingAssembly().Location;
var configPath = $"{assemblyPath}.config";
_hostBootstrap = BootstrapFactory.CreateBootstrapFromConfigFile(configPath);
}
public static SocketHostManager GetInstance()
{
if (_singleton != null)
return _singleton;
lock (SyncRoot)
{
_singleton ??= new SocketHostManager();
}
return _singleton;
}
#endregion
}
}
</div>Configuration Settings
----------------------
Include an `App.config` file in the library to define server bindings and type mappings.
<div>```
<code><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="superSocket"
type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/>
</configSections>
<!-- Root superSocket node -->
<superSocket>
<!-- Server instances -->
<servers>
<server name="CustomTelnet" serverTypeName="ServerTypeMap" ip="Any" port="2021"></server>
</servers>
<!-- Registered Server Types -->
<serverTypes>
<add name="ServerTypeMap" type="ModularSocketLib.Sockets.TcpServerInstance, ModularSocketLib" />
</serverTypes>
</superSocket>
</configuration></code>
In a separate console application, reference ModularSocketLib. Use the manager to start and stop the service.
namespace SocketDemoApp { class Program { static void Main(string[] args) { try { // Launch service if (!SocketHostManager.GetInstance().Initialize(2021)) { Console.WriteLine("Service launch failure."); Console.ReadLine(); return; }
Console.WriteLine("Listening on port 2021.");
Console.WriteLine("Press 'q' to exit.");
char input;
do
{
input = Console.ReadKey().KeyChar;
} while (input.ToString().ToUpper() != "Q");
// Stop service
SocketHostManager.GetInstance().Terminate();
}
catch (Exception ex)
{
Console.WriteLine($"Fatal error: {ex.Message}");
}
Console.WriteLine("Process completed.");
Console.ReadLine();
}
}
}
</div>