{"record":{"id":"980c1fdf45d0831e","repo":"YunaiV/ruoyi-vue-pro","slug":"starttcpserver-tcp-server","errorCode":null,"errorMessage":"[startTcpServer][TCP Server 启动失败]","messagePattern":"\\[startTcpServer\\]\\[TCP Server 启动失败\\]","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java","lineNumber":259,"sourceCode":"        log.info(\"[stop][IoT Modbus TCP Server 协议 {} 已停止]\", getId());\n    }\n\n    /**\n     * 启动 TCP Server\n     */\n    private void startTcpServer() {\n        // 1. 创建 TCP Server\n        NetServerOptions options = new NetServerOptions()\n                .setPort(properties.getPort());\n        netServer = vertx.createNetServer(options);\n\n        // 2. 设置连接处理器\n        netServer.connectHandler(this::handleConnection);\n        try {\n            netServer.listen().toCompletionStage().toCompletableFuture().get();\n            log.info(\"[startTcpServer][TCP Server 启动成功, port={}]\", properties.getPort());\n        } catch (Exception e) {\n            throw new RuntimeException(\"[startTcpServer][TCP Server 启动失败]\", e);\n        }\n    }\n\n    /**\n     * 处理新连接\n     */\n    private void handleConnection(NetSocket socket) {\n        log.info(\"[handleConnection][新连接, remoteAddress={}]\", socket.remoteAddress());\n\n        // 1. 创建 RecordParser 并设置为数据处理器\n        RecordParser recordParser =  frameDecoder.createRecordParser((frame, frameFormat) -> {\n            // 【重要】帧处理分发，即消息处理\n            upstreamHandler.handleFrame(socket, frame, frameFormat);\n        });\n        socket.handler(recordParser);\n\n        // 2.1 连接关闭处理\n        socket.closeHandler(v -> {","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/YunaiV/ruoyi-vue-pro/blob/0418084e222612af2fc1141f566af454f9236ab1/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java#L241-L277","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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)."],"exampleFix":"// before (no timeout, can hang)\nnetServer.listen().toCompletionStage().toCompletableFuture().get();\n\n// after (fail fast)\nnetServer.listen().toCompletionStage().toCompletableFuture().get(10, TimeUnit.SECONDS);","handlingStrategy":"validation","validationCode":"// before start(), confirm the TCP port is free\ntry (java.net.ServerSocket probe = new java.net.ServerSocket(properties.getPort())) {\n    // port is free\n} catch (IOException e) {\n    throw new IllegalStateException(\"Modbus TCP Server 端口被占用: \" + properties.getPort(), e);\n}","typeGuard":null,"tryCatchPattern":"// isolate per-protocol startup so one bind failure doesn't abort the whole gateway\n// (in IotProtocolManager.start, wrap each protocol.start() in try/catch)","preventionTips":["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."],"tags":["tcp-server","vertx","network","startup","modbus"],"backgroundTag":null,"analyzedSha":"0418084e222612af2fc1141f566af454f9236ab1","analyzedAt":"2026-08-14T00:56:18.412Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}