YunaiV/ruoyi-vue-pro · critical · RuntimeException
[startTcpServer][TCP Server 启动失败]
Error message
[startTcpServer][TCP Server 启动失败]
What it means
Thrown by startTcpServer() when netServer.listen().get() fails. Unlike the EMQX HTTP server (which uses a 10s timeout), this call has NO timeout on .get(), so a stuck listen could block indefinitely, though bind failures normally resolve quickly. It wraps any Vert.x bind/listen error. Because IotModbusTcpServerProtocol.start() calls this in its try block, the exception aborts protocol startup and triggers stop0() cleanup.
Source
Thrown at yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java:259
log.info("[stop][IoT Modbus TCP Server 协议 {} 已停止]", getId());
}
/**
* 启动 TCP Server
*/
private void startTcpServer() {
// 1. 创建 TCP Server
NetServerOptions options = new NetServerOptions()
.setPort(properties.getPort());
netServer = vertx.createNetServer(options);
// 2. 设置连接处理器
netServer.connectHandler(this::handleConnection);
try {
netServer.listen().toCompletionStage().toCompletableFuture().get();
log.info("[startTcpServer][TCP Server 启动成功, port={}]", properties.getPort());
} catch (Exception e) {
throw new RuntimeException("[startTcpServer][TCP Server 启动失败]", e);
}
}
/**
* 处理新连接
*/
private void handleConnection(NetSocket socket) {
log.info("[handleConnection][新连接, remoteAddress={}]", socket.remoteAddress());
// 1. 创建 RecordParser 并设置为数据处理器
RecordParser recordParser = frameDecoder.createRecordParser((frame, frameFormat) -> {
// 【重要】帧处理分发,即消息处理
upstreamHandler.handleFrame(socket, frame, frameFormat);
});
socket.handler(recordParser);
// 2.1 连接关闭处理
socket.closeHandler(v -> {View on GitHub (pinned to 0418084e22)
Solutions
- Check the port is free: ss -ltnp | grep <port> / lsof -i:<port>, kill the holder or change properties.port.
- Use a port >=1024 unless the gateway has CAP_NET_BIND_SERVICE / runs privileged.
- Ensure only one gateway instance / one protocol instance binds the port.
- If a previous process left the port in TIME_WAIT, wait or set SO_REUSEADDR (Vert.x enables it by default on NetServer).
- Add a timeout to .get() to fail fast instead of hanging: netServer.listen().toCompletionStage().toCompletableFuture().get(10, TimeUnit.SECONDS).
Example fix
// before (no timeout, can hang) netServer.listen().toCompletionStage().toCompletableFuture().get(); // after (fail fast) netServer.listen().toCompletionStage().toCompletableFuture().get(10, TimeUnit.SECONDS);
Defensive patterns
Strategy: validation
Validate before calling
// before start(), confirm the TCP port is free
try (java.net.ServerSocket probe = new java.net.ServerSocket(properties.getPort())) {
// port is free
} catch (IOException e) {
throw new IllegalStateException("Modbus TCP Server 端口被占用: " + properties.getPort(), e);
} Try / catch
// isolate per-protocol startup so one bind failure doesn't abort the whole gateway // (in IotProtocolManager.start, wrap each protocol.start() in try/catch)
Prevention
- Allocate a fixed port per protocol instance and document it; detect conflicts at deploy time.
- Use ports >=1024 or grant CAP_NET_BIND_SERVICE.
- Ensure the supervisor prevents duplicate gateway processes on the same port.
- Add a timeout to listen().get() to fail fast instead of hanging.
When it happens
Trigger: properties.getPort() already bound by another process; privileged port (<1024) bound without OS permission; NetServerOptions invalid; another protocol instance or a previous unclean gateway shutdown still holds the port.
Common situations: Port conflict with another Modbus TCP Server instance or service; duplicate gateway process; OS-level bind permission; previous process did not release the port (TIME_WAIT).
Related errors
- HTTP Hook 服务启动失败
- MQTT Client 启动失败: 连接 Broker 失败
- Modbus 读取失败 [slaveId=%d, identifier=%s, functionCode=%d, add
- Modbus 写入失败 [slaveId=%d, identifier=%s, address=%d]
- AreaUtils 初始化失败
AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14).
Data as JSON: /api/errors/980c1fdf45d0831e.
Report an issue: GitHub.