mqtt长连接报错32000

背景

项目需要使用mqtt协议建立长连接,我是客户端,需要连上服务端同学的提供的地址;客户端使用的是paho提供的客户端sdk,如下:

<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>1.2.5</version>
</dependency>

建立连接代码也十分简单,和github上demo差不多:

public void createMqttConnection(){
        try {
            String ts = System.currentTimeMillis() + "";
            String password = "password";
            String clientId = "server_" + InetAddress.getLocalHost().getHostAddress() + "_" + ts;
            String broker = mqttConfig.getMqttHost();

            MemoryPersistence persistence = new MemoryPersistence();
            mqttClient = new MqttClient(broker, clientId, persistence);
            mqttClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    System.out.println("连接断开");
                    cause.printStackTrace();
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {

                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {

                }
            });
            MqttConnectOptions connectOptions = new MqttConnectOptions();
            connectOptions.setUserName("server");
            connectOptions.setPassword(password.toCharArray());
            connectOptions.setAutomaticReconnect(true);
            connectOptions.setCleanSession(true);
            connectOptions.setKeepAliveInterval(20);

            log.info("Mqtt connection Initialization begin!");
            mqttClient.connect(connectOptions);
            log.info("Mqtt connection success!");
        } catch (Exception e) {
            log.error("Mqtt connection initialization error ", e);
        }
    }

问题

服务启动,并成功连接上过后,总是报错:等待来自服务器的响应超时(32000),如下图
问题

排查

打开wireshark抓包,结果如下,时间顺序是从下到上,发现,TCP三次握手建立连接后(362,363,364),并成功验证了username,password后(392,393,395,396),的确20s后(keepAliveInterval设置的20),客户端向服务器发送了心跳包(3456【PSH, ACK】),这个发送,是被【ACK】(3458)了,但是在接下来的20s内,服务器都没有返回心跳给客户端,在客户端看来,那么服务器就是挂了,所以断开连接,产生了接下来的【FIN ACK】(6136),四次挥手(6137,6138)断开了TCP连接(至于为什么四次挥手只抓到3个包,后文有补充);由于设置了setAutomaticReconnect=true,又开始三次握手建立连接了。

wireshark第一次抓包

结论

服务器没有返回心跳给客户端,客户端以为服务器挂了,就断开连接报错。需要让服务器端同学,修复一下心跳发送相关代码。

为什么四次挥手只有3个包
参考:Linux之TCP的实现,四次挥手
大概意思就是Linux中支持TCP的延迟ACK机制,发送ack的条件不能满足立即发送ack的条件,导致ack的发送被延时了,于是和下一个FIN合在一起发;包括本文中问题修复正常后,服务器端(Linux)返回的心跳也有这个ACK延迟

posted @   rachel_aoao  阅读(1574)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示