Implementing a Custom PipelineFilter in SuperSocket 2.0

This article walks through the implementation of a custom PipelineFilter in SuperSocket 2.0. The development environment is Windows 10, Visual Studio 2019, .NET Core 3.1, and SuperSocket 2.0.0-beta.8.

1. Project Creation

Create a .NET Core console application using Visual Studio 2019 targeting .NET Core 3.1, and add the SuperSocket (2.0.0-beta.8) NuGet package.

2. Configuration File

Add an appsettings.json configuraton file too the project root and set its file property to 'Copy if newer'. The configuration content is standard and omitted here for brevity.

3. PipelineFilter

Define a package type that implements IKeyedPackageInfo<short>:

using SuperSocket.ProtoBase;

namespace SuperSocketV2Sample.PipelineFilter.Server
{
    public class DataPackage : IKeyedPackageInfo<short>
    {
        public short Identifier { get; set; }
        public byte[] Content { get; set; }
    }
}

Create a custom pipeline filter by extending FixedHeaderPipelineFilter<DataPackage>:

using System.Buffers;
using SuperSocket.ProtoBase;

namespace SuperSocketV2Sample.PipelineFilter.Server
{
    public class CustomPipelineFilter : FixedHeaderPipelineFilter<DataPackage>
    {
        /// +-------+---+----------------------+
        /// | msg   | l |                      |
        /// | type  | e |     payload          |
        /// |  (2)  | n |                      |
        /// |       |(2)|                      |
        /// +-------+---+----------------------+

        private const int TotalHeaderLength = 4; // Total fixed header length
        private const int BodyLengthOffset = 2;  // Offset where body length starts

        public CustomPipelineFilter()
            : base(TotalHeaderLength)
        {
        }

        // Extract body length from the header
        protected override int GetBodyLengthFromHeader(ref ReadOnlySequence<byte> buffer)
        {
            var reader = new SequenceReader<byte>(buffer);
            reader.Advance(BodyLengthOffset);
            reader.TryReadBigEndian(out short bodyLength);
            return bodyLength;
        }

        protected override DataPackage DecodePackage(ref ReadOnlySequence<byte> buffer)
        {
            var reader = new SequenceReader<byte>(buffer);
            reader.TryReadBigEndian(out short msgType);

            var payload = buffer.Slice(TotalHeaderLength).ToArray();
            return new DataPackage
            {
                Identifier = msgType,
                Content = payload
            };
        }
    }
}

4. Test Code

using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SuperSocket;
using SuperSocketV2Sample.PipelineFilter.Server;

namespace SuperSocketV2Sample.PipelineFilter
{
    class Program
    {
        static async Task Main()
        {
            var host = SuperSocketHostBuilder.Create<DataPackage, CustomPipelineFilter>()
                .ConfigureLogging((hostCtx, logging) =>
                {
                    logging.AddConsole();
                })
                .Build();

            await host.RunAsync();
        }
    }
}

5. Important Notes

To process incoming data using the DataPackage type, it must implement IKeyedPackageInfo<T>. This is necessary because IAsyncCommand<T> expects the package type to implement this interface. The Command attribute on a command class will then work correctly, e.g.:

[Command(Key = (short)100)]
public class CustomCommand : IAsyncCommand<DataPackage>

Additionally, the Key value type in the Command attribute must match the generic type of the IKeyedPackageInfo interface implemented by the package.

Tags: SuperSocket PipelineFilter .NET Core Socket Programming SuperSocket 2.0

Posted on Thu, 28 May 2026 18:30:21 +0000 by trippyd