Protocol Design Basics in smart-socket: Handling Half‑Packet and Sticky‑Packet Issues

This article explains the design of the Protocol interface in the smart-socket framework, covering data integrity, half‑packet and sticky‑packet handling, performance considerations, and provides concrete IntegerProtocol and StringProtocol implementations with best‑practice guidelines.

Three Knives
Three Knives
Three Knives
Protocol Design Basics in smart-socket: Handling Half‑Packet and Sticky‑Packet Issues

Protocol Interface Overview

In the smart-socket framework, the Protocol<T> interface is the core component for parsing network byte streams into business messages. It defines a single method decode(ByteBuffer readBuffer, AioSession session) that receives a ByteBuffer containing raw bytes and the current session object. Returning a non‑null value indicates a complete message has been decoded; returning null signals that more data is needed.

Design Principles

Data Integrity – the protocol must reliably identify message boundaries, using fixed‑length messages, length‑field prefixes, or special delimiters.

Half‑Packet and Sticky‑Packet Handling – the design must correctly process fragmented messages (half‑packet) and combined messages (sticky‑packet).

Performance Optimization – parsing is a high‑frequency operation, so object creation and memory copying should be minimized.

Simple Protocol Example: IntegerProtocol

public class IntegerProtocol implements Protocol<Integer> {
    @Override
    public Integer decode(ByteBuffer data, AioSession session) {
        // Check if there are enough bytes for an integer
        if (data.remaining() < Integer.BYTES)
            return null;
        // Read and return the integer
        return data.getInt();
    }
}

Working Process

Check that the ByteBuffer contains at least Integer.BYTES (4) bytes.

If fewer bytes are available, return null to wait for more data.

When enough bytes exist, call getInt() to read the integer and return it.

Usage Example

// Server side
MessageProcessor<Integer> serverProcessor = (session, msg) -> {
    int respMsg = msg + 1;
    System.out.println("Received from client: " + msg + ", response: " + respMsg);
    session.writeBuffer().writeInt(respMsg);
    session.writeBuffer().flush();
};
AioQuickServer<Integer> server = new AioQuickServer<>(8888, new IntegerProtocol(), serverProcessor);

// Client side
MessageProcessor<Integer> clientProcessor = (session, msg) ->
    System.out.println("Received from server: " + msg);
AioQuickClient<Integer> client = new AioQuickClient<>("localhost", 8888, new IntegerProtocol(), clientProcessor);
AioSession session = client.start();
session.writeBuffer().writeInt(1);
session.writeBuffer().flush();

Complex Protocol Example: StringProtocol

The string protocol handles variable‑length messages using a length‑field prefix.

Design Idea

Message format: [length (4 bytes)][string bytes] Read the length field first to determine the actual string length.

Read the specified number of bytes and convert them to a UTF‑8 string.

Core Implementation

public class StringProtocol implements Protocol<String> {
    private final Map<AioSession, FixedLengthFrameDecoder> decoderMap = new ConcurrentHashMap<>();

    @Override
    public String decode(ByteBuffer readBuffer, AioSession session) {
        FixedLengthFrameDecoder decoder = decoderMap.get(session);
        if (decoder != null) {
            String content = bigContent(readBuffer, decoder);
            if (content != null) {
                decoderMap.remove(session);
            }
            return content;
        }
        if (readBuffer.remaining() < Integer.BYTES) {
            return null;
        }
        readBuffer.mark();
        int length = readBuffer.getInt();
        // Handle messages larger than the buffer capacity
        if (length + Integer.BYTES > readBuffer.capacity()) {
            FixedLengthFrameDecoder fixedLengthFrameDecoder = new FixedLengthFrameDecoder(length);
            decoderMap.put(session, fixedLengthFrameDecoder);
            return null;
        }
        // Half‑packet: not enough bytes for the whole message
        if (length > readBuffer.remaining()) {
            readBuffer.reset();
            return null;
        }
        return convert(readBuffer, length);
    }

    private String convert(ByteBuffer byteBuffer, int length) {
        byte[] b = new byte[length];
        byteBuffer.get(b);
        return new String(b, StandardCharsets.UTF_8);
    }
}

Half‑Packet and Sticky‑Packet Handling

Half‑packet handling: When the buffer lacks enough bytes for a full message, mark() and reset() preserve the read position and wait for more data.

Long‑message handling: For messages exceeding the buffer capacity, a FixedLengthFrameDecoder is created and stored in decoderMap to accumulate data across reads.

Sticky‑packet handling: If multiple complete messages are present, the framework repeatedly invokes decode until it returns null.

Protocol Design Best Practices

Avoid storing session‑specific state inside a Protocol implementation because a single instance is shared across sessions.

Use auxiliary decoders such as FixedLengthFrameDecoder or DelimiterFrameDecoder to simplify complex protocol implementations.

Release temporary resources (e.g., decoders created for a specific session) promptly to prevent memory leaks.

Chapter Summary

The chapter detailed the design principles and usage of the Protocol interface in smart-socket, demonstrating both a simple integer protocol and a more complex string protocol. Key points include proper handling of half‑packet and sticky‑packet scenarios, performance‑aware parsing, and best practices such as avoiding stateful protocol instances and leveraging auxiliary decoders.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendJavaProtocolsticky-packetsmart-sockethalf-packet
Three Knives
Written by

Three Knives

Every line of code you contribute to open source could help make the future better.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.