Skip to content

NTDLS.StreamFraming Usage

Stream extension methods that give any TCP stream reliable message framing, compression and async query/reply.

Published Jul 25, 2026

NTDLS.StreamFraming

What it is. A set of extension methods for Stream (typically a TCP NetworkStream) that solve the classic byte-stream problem: messages arriving fragmented or concatenated. It adds reliable framing with optional compression and encryption, two-way communication, and asynchronous query/reply - every message is guaranteed to be received in its entirety and in the order sent.

When to reach for it. You are building a custom protocol over raw TCP sockets and do not want to hand-roll length prefixes, reassembly buffers and serialization. Skip it if you can use an existing transport library; this gives you the plumbing pieces rather than a full connection manager.

Getting started

Your payload classes implement one of three interfaces:

internal class MyMessage : IFrameNotification
{
    public string Text { get; set; }

    public MyMessage(string text)
    {
        Text = text;
    }
}

Sending a fire-and-forget notification is one call on the stream:

using var tcpStream = tcpClient.GetStream();

string text = $"This is a message sent at {DateTime.Now.ToLongTimeString()}";
tcpStream.WriteNotification(new MyMessage(text));

Receiving runs a read loop. ReadAndProcessFrames takes a FrameBuffer, splits out complete frames from whatever bytes arrived, deserializes them, and invokes your callback for each one. It returns false when the peer disconnects:

var frameBuffer = new FrameBuffer();

using var tcpStream = tcpClient.GetStream();

while (tcpClient.Connected)
{
    if (tcpStream.ReadAndProcessFrames(frameBuffer, ProcessFrameNotificationCallback) == false)
    {
        break; // Disconnected.
    }
}

private void ProcessFrameNotificationCallback(IFrameNotification payload)
{
    if (payload is MyMessage myMessage)
    {
        Console.WriteLine($"Received: '{myMessage.Text}'");
    }
}

For request/reply semantics, send with WriteQuery<TReply> and return a reply from your query callback - the response is routed back to the waiting task automatically:

tcpStream.WriteQuery<MyQueryReply>(new MyQuery("Hello client!"))
    .ContinueWith(o =>
    {
        if (o.IsCompletedSuccessfully && o.Result != null)
        {
            Console.WriteLine($"Reply: '{o.Result.Text}'");
        }
    });

NuGet: NTDLS.StreamFraming

An unhandled error has occurred. Reload 🗙