Backend Development 19 min read

Netty TCP Long‑Connection Demo for IoT Messaging with Redis and Spring Boot

This article presents a complete Netty‑based TCP client/server demo for IoT long‑connection messaging, explains the project architecture, module layout, business flow, and provides detailed Java code for a local message queue, multithreaded processing, client creation, handler logic, and testing endpoints.

Top Architect
Top Architect
Top Architect
Netty TCP Long‑Connection Demo for IoT Messaging with Redis and Spring Boot

Project Background

The author needed a reliable long‑connection solution for an IoT project that uses socket communication; after encountering many bugs, they created an open‑source demo that strips away business‑specific code and focuses on the core networking logic.

Architecture

The demo combines netty , redis and springboot 2.2.0 . The main modules are:

netty-tcp-core : utility classes shared by client and server.

netty-tcp-server : a simple server used only for testing.

netty-tcp-client : the focus of the article, implementing the client side.

Business Flow

In production the system would use RocketMQ; the demo replaces it with a local BlockingQueue . The flow is: Producer → Message Queue → Consumer (client) → TCP channel → Server → TCP channel → Client. When a message arrives, the consumer checks whether a TCP channel for the device already exists; if not, it creates one, otherwise it reuses the existing channel.

Code Details

1. Message Queue

A static ArrayBlockingQueue holds NettyMsgModel objects. A dedicated thread continuously takes messages from the queue and hands them to MessageProcessor for asynchronous handling.

package org.example.client;

import org.example.client.model.NettyMsgModel;
import java.util.concurrent.ArrayBlockingQueue;
/**
 * Local queue demo (replace with RocketMQ or RabbitMQ in production)
 */
public class QueueHolder {
    private static final ArrayBlockingQueue<NettyMsgModel> queue = new ArrayBlockingQueue<>(100);
    public static ArrayBlockingQueue<NettyMsgModel> get() { return queue; }
}

2. Execution Class

The LoopThread creates a thread pool and repeatedly pulls messages from the queue, invoking MessageProcessor.process() . It uses take() to block when the queue is empty.

public class LoopThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < MAIN_THREAD_POOL_SIZE; i++) {
            executor.execute(() -> {
                while (true) {
                    try {
                        NettyMsgModel nettyMsgModel = QueueHolder.get().take();
                        messageProcessor.process(nettyMsgModel);
                    } catch (InterruptedException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            });
        }
    }
}

3. Client

The NettyClient is a prototype‑scoped Spring bean. It receives the device IMEI, business data map, an EventLoopGroup , and a handler class. The client builds a Bootstrap , configures decoders, encoders, idle‑state handling, and connects to the server with a retry mechanism (max 2 retries). After a successful connection it stores the instance in NettyClientHolder and sends the pending message.

public class NettyClient implements Runnable {
    @Value("${netty.server.port}") private int port;
    @Value("${netty.server.host}") private String host;
    private String imei;
    private Map
bizData;
    private EventLoopGroup workGroup;
    private Class<BaseClientHandler> clientHandlerClass;
    private ChannelFuture channelFuture;
    // constructor, run(), init(), connect() etc.
}

4. Handler

DemoClientHandler extends a base handler, holds a reference to its NettyClient , and implements lifecycle callbacks:

channelActive : notifies the waiting thread that the channel is ready.

channelRead : logs incoming messages and processes business logic; a special "shutdown" message triggers client closure.

userEventTriggered : monitors idle events and closes the channel after three consecutive idle periods.

public class DemoClientHandler extends BaseClientHandler {
    private final String imei;
    private final Map
bizData;
    private final NettyClient nettyClient;
    private int allIdleCounter = 0;
    private static final int MAX_IDLE_TIMES = 3;
    // constructor, channelActive(), channelRead(), userEventTriggered(), exceptionCaught()
}

5. Client Cache

NettyClientHolder stores active client instances in a ConcurrentHashMap<String, NettyClient> keyed by IMEI, allowing quick lookup without persisting Netty channels.

public class NettyClientHolder {
    private static final ConcurrentHashMap<String, NettyClient> clientMap = new ConcurrentHashMap<>();
    public static ConcurrentHashMap<String, NettyClient> get() { return clientMap; }
}

Testing

A Spring‑Boot controller exposes three endpoints:

/demo/testOne : sends two messages with a 5‑second pause, demonstrating client creation and reuse.

/demo/testTwo : allows arbitrary IMEI and message parameters.

/demo/testThree : sends two messages for the same device back‑to‑back, showing the lock‑based re‑queueing when the client is already processing.

@RestController
@RequestMapping("/demo")
public class DemoController {
    @GetMapping("testOne")
    public void testOne() { /* ... */ }
    @GetMapping("testTwo")
    public void testTwo(@RequestParam String imei, @RequestParam String msg) { /* ... */ }
    @GetMapping("testThree")
    public void testThree() { /* ... */ }
}

Log screenshots show the first message triggering client creation, the second message being sent through the existing channel, and the idle‑requeue behavior for the third test.

Source Code

The full project is available at https://gitee.com/jaster/netty-tcp-demo .

Conclusion

The demo is intended for learning and can be extended for production use; readers are encouraged to ask questions or contribute improvements.

JavaRedisNettyTCPSpringBootIoTMessageQueue
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login 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.