Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Extending Connection Handlers and Server Services in SuperSocket 2.0

Tech May 12 2

In SuperSocket 2.0, connection lifecycle management is divided between two core components. The AppSession class handles individual client connections, while SuperSocketService<TPackage> operates at the server level, orchestrating session pooling, startup routines, and shutdown sequences. Customizing these base classes allows developers to inject connection-specific logic, maintain active client registries, and execute background server tasks.

Custom Session Implementation

Deriving from AppSession enables direct interaction with client endpoints. Override connection events to handle greetings, cleanup, or state initialization.

using System;
using System.Text;
using System.Threading.Tasks;
using SuperSocket;
using SuperSocket.Channel;

namespace SuperSocketExtensions.Demo
{
    public class CustomClientSession : AppSession
    {
        protected override async ValueTask OnSessionConnectedAsync()
        {
            var endpoint = RemoteEndPoint?.ToString() ?? "Unknown";
            Console.WriteLine($"[{DateTime.UtcNow:O}] Client connected: {endpoint}");

            var welcomeBytes = Encoding.UTF8.GetBytes($"Server ready. Your endpoint: {endpoint}\r\n");
            await SendAsync(welcomeBytes);
        }

        protected override async ValueTask OnSessionClosedAsync(CloseEventArgs e)
        {
            var endpoint = RemoteEndPoint?.ToString() ?? "Unknown";
            Console.WriteLine($"[{DateTime.UtcNow:O}] Client disconnected: {endpoint} | Reason: {e.Reason}");
            await base.OnSessionClosedAsync(e);
        }
    }
}

Server Service and Session Tracking

The service layer manages the overall server lifecycle. By overriding session hooks, you can maintain a thread-safe collection of active connections and run periodic background jobs, such as connection monitoring or metrics collection.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using SuperSocket;
using SuperSocket.Server;

namespace SuperSocketExtensions.Demo
{
    public class NetworkServerService<TPackage> : SuperSocketService<TPackage>
        where TPackage : class
    {
        private readonly List<IAppSession> _activeConnections;
        private readonly CancellationTokenSource _monitorCts;

        public NetworkServerService(IServiceProvider serviceProvider, IOptions<ServerOptions> serverOptions)
            : base(serviceProvider, serverOptions)
        {
            _activeConnections = new List<IAppSession>();
            _monitorCts = new CancellationTokenSource();
        }

        protected override async ValueTask OnSessionConnectedAsync(IAppSession session)
        {
            Console.WriteLine($"[{DateTime.UtcNow:O}] [Service] Tracking new session: {session.RemoteEndPoint}");
            lock (_activeConnections)
            {
                _activeConnections.Add(session);
            }
            await base.OnSessionConnectedAsync(session);
        }

        protected override async ValueTask OnSessionClosedAsync(IAppSession session, CloseEventArgs e)
        {
            Console.WriteLine($"[{DateTime.UtcNow:O}] [Service] Removing session: {session.RemoteEndPoint}");
            lock (_activeConnections)
            {
                _activeConnections.Remove(session);
            }
            await base.OnSessionClosedAsync(session, e);
        }

        protected override async ValueTask OnStartedAsync()
        {
            Console.WriteLine($"[{DateTime.UtcNow:O}] Server service initialized.");
            _ = RunConnectionMonitorAsync(_monitorCts.Token, 4000);
            await base.OnStartedAsync();
        }

        protected override async ValueTask OnStopAsync()
        {
            _monitorCts.Cancel();
            Console.WriteLine($"[{DateTime.UtcNow:O}] Server service shutting down.");
            await base.OnStopAsync();
        }

        private async Task RunConnectionMonitorAsync(CancellationToken ct, int delayMs)
        {
            while (!ct.IsCancellationRequested)
            {
                try
                {
                    await Task.Delay(delayMs, ct);
                }
                catch (TaskCanceledException)
                {
                    break;
                }

                List<string> endpoints;
                lock (_activeConnections)
                {
                    endpoints = _activeConnections.Select(s => s.RemoteEndPoint?.ToString() ?? "N/A").ToList();
                }

                if (endpoints.Count == 0)
                {
                    Console.WriteLine($"[{DateTime.UtcNow:O}] Monitor: No active connections.");
                    continue;
                }

                Console.WriteLine($"[{DateTime.UtcNow:O}] Monitor: {endpoints.Count} active connection(s):");
                foreach (var ep in endpoints)
                {
                    Console.WriteLine($"  - {ep}");
                }
            }
        }
    }
}

Host Configuraton and Startup

The host builder wires the custom session and service types into the dependency injection container. Session handlers can be registered alongside command routing and logging configurations.

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SuperSocket;
using SuperSocket.Command;
using SuperSocket.ProtoBase;

namespace SuperSocketExtensions.Demo
{
    internal static class ServerEntryPoint
    {
        public static async Task Main()
        {
            var hostBuilder = SuperSocketHostBuilder.Create<StringPackageInfo, CommandLinePipelineFilter>()
                .UseHostedService<NetworkServerService<StringPackageInfo>>()
                .UseSession<CustomClientSession>()
                .UseSessionHandler(
                    onConnected: async (s) =>
                    {
                        Console.WriteLine($"[{DateTime.UtcNow:O}] [Handler] Connection established: {s.RemoteEndPoint}");
                        await Task.CompletedTask;
                    },
                    onClosed: async (s, e) =>
                    {
                        Console.WriteLine($"[{DateTime.UtcNow:O}] [Handler] Connection terminated: {s.RemoteEndPoint} | {e.Reason}");
                        await Task.CompletedTask;
                    })
                .UseCommand(cmdCfg =>
                {
                    // Register protocol commands here
                    // cmdCfg.AddCommand<CustomAddCommand>();
                    // cmdCfg.AddCommand<CustomEchoCommand>();
                })
                .ConfigureLogging((ctx, logBuilder) =>
                {
                    logBuilder.AddConsole();
                    logBuilder.SetMinimumLevel(LogLevel.Warning);
                });

            var host = hostBuilder.Build();

            try
            {
                await host.RunAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Host startup failed: {ex.Message}");
            }
        }
    }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.