Mqttx read econnreset exception troubleshooting

mqtt session read econnreset
Insert image description here

Troubleshooting READ ECONNRESET when using mqttx to connect to the mqtt server
The company added a new mqtt server some time ago. There was no problem during our initial test, but as the number of connections increased, READ ECONNRESET appeared at intervals in the following days, causing the project to be unable to be used normally, so I checked the problem.
Based on the answers on the Internet, I found the following article
https:/ /blog.csdn.net/slxz001/article/details/123368088

  1. The analysis may be that the mqtt session queue is full, and then the mqtt session queue parameters are modified.
  2. It is also possible that there are too many connections in the project code. This requires modifying the connection logic of the project code. Use the same mqtt client to connect to mqtt, and then monitor multiple topics at the same time. This can avoid too many connections. Connect to mqtt to avoid this problem
    It is recommended to test a certain number of connections before formal deployment to avoid problems

The following is a little test code

/**
* 需要自己添加application.yml配置
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@ConfigurationProperties(prefix = "mqtt")
@Component
public class MqttProperties {
    
    
	// mqtt服务器url
    private String uri;
	//登录用户名
    private String username;
	// 密码
    private String password;
	// 暂时没用,主题会在代码里动态获取
    private String topic;

}
@RunWith(SpringRunner.class)
@SpringBootTest
@Log
public class MqttProducerTest {
    
    

    @Autowired
    private MqttProperties mqttProperties;

    private static final String WATCH_PREFIX = "TEST";

    /**
     * 设备心跳客户端列表
     */
    static Map<String, MqttClient> clientMap;

    private static final ThreadPoolExecutor POOL_EXECUTOR;

    static {
    
    
        POOL_EXECUTOR = new ThreadPoolExecutor(2, 2, 30 * 1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(10000),
                new CustomizableThreadFactory("pool"));
        clientMap = new HashMap<>();
    }

    @Test
    public void testConnect() {
    
    
        int count = 10000;
        int success = 0;
        AtomicInteger fail = new AtomicInteger();
        for (int i = 0; i < count; i++) {
    
    
            log.info(String.format("准备创建第%d个client", i + 1));
            // MQTT
            String urlFrontSuffix = mqttProperties.getUri();
            String clientId = "CLIENT-" + (System.currentTimeMillis() + "").substring(6);
            /* TOPIC:TEST */
            String watchTopic = WATCH_PREFIX + (i * 100);
            System.out.println("clientId: " + clientId + " watchTopic: " + watchTopic);
            try {
    
    
                MemoryPersistence memoryPersistence = new MemoryPersistence();
                MqttClient client = new MqttClient(urlFrontSuffix, clientId, memoryPersistence);

                MqttConnectOptions options = getOptions();
                // 设置回调函数,当订阅到信息时调用此方法
                client.setCallback(new MqttCallback() {
    
    
                    @Override
                    public void connectionLost(Throwable throwable) {
    
    
                        System.out.println(watchTopic + " Connection Lost.");
                        fail.incrementAndGet();
                    }

                    @Override
                    public void messageArrived(String str, MqttMessage mqttMessage) throws Exception {
    
    
                        // 订阅成功,并接受信息时调用
                        String payload = new String(mqttMessage.getPayload()); // 获取消息内容
                        log.info(String.format("accepted: %s channel:%s", payload, watchTopic));
                    }

                    @Override
                    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
    
    
                        System.out.println("deliveryComplete" + iMqttDeliveryToken);
                    }
                });
                client.connect(options);
                client.subscribe(watchTopic);

                log.info("connected the mqtt client" + clientId);

                // mqtt客户端
                clientMap.put(watchTopic, client);

                if (client.isConnected()) {
    
    
                    success++;
                    log.info(String.format("第%d个client连接成功", success));
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
        log.info(String.format("总共启动%d, 成功%d, 失败%d", count, success, fail.get()));
    }

    private MqttConnectOptions getOptions() {
    
    
        MqttConnectOptions options = new MqttConnectOptions();
        // 设置客户端和服务器是否应在重新启动和重新连接期间记住状态 默认false
        options.setCleanSession(true);
        // 设置超时时间
        options.setConnectionTimeout(10);
        // 设置会话心跳时间
        options.setKeepAliveInterval(20);
        // 设置超时时间
        options.setConnectionTimeout(10);
        // 设置会话心跳时间
        options.setKeepAliveInterval(20);
        options.setUserName(mqttProperties.getUsername());
        options.setPassword(mqttProperties.getPassword().toCharArray());
        return options;
    }
}

operation result:

控制台- 10:35:55.099 [main]  INFO   c.f.a.c.m.MqttProducerTest - [testConnect,58] -准备创建第700个client
clientId: JAVA-CLIENT-4155099 watchTopic: xxx
已断开连接 (32109) - java.io.EOFException
	at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:197)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.EOFException
	at java.io.DataInputStream.readByte(DataInputStream.java:267)
	at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:92)
	at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:137)
	... 1 more
控制台- 10:35:55.119 [main]  INFO   c.f.a.c.m.MqttProducerTest - [testConnect,58] -准备创建第701个client
clientId: JAVA-CLIENT-4155119 watchTopic: xxx
已断开连接 (32109) - java.io.EOFException

Created a test case using Java code. Running the test found that when the number of connections was established to about 700, the problem occurred and a java.io.EOFException error message was thrown
java.io.EOFException

EOFException: This exception is thrown when the end of the file or stream is unexpectedly reached during input.

This exception is primarily used by data input streams to indicate that the end of the stream has been reached. Note that many other input operations return a special value to indicate that the end of the stream has been reached, rather than throwing an exception.

cause:

  1. The order in which data is written in the data stream is inconsistent with the order in which it is read.
  2. UTF is a double-byte encoding, and the writeChars method writes according to the character format, and the space occupied in the file is smaller than the same string encoded in Unicode. Therefore, when using the readUTF method to read, an EOF error will occur.

Guess you like

Origin blog.csdn.net/qq_27577113/article/details/130084304