Mosquitto TLS设置自动有效负载大小限制

时间:2018-04-05 02:55:47

标签: ssl mqtt mosquitto paho

我已经实施了一个无担保的蚊子经纪人,可以通过端口1883定期发送大量数据(每分钟大约200kb文件)。

由于我已经实施了TLS,尽管设置了message_size_limit = 0,但经纪人似乎通过端口8883自动拒绝了大于128kb的数据。

继承我的mosquitto.conf:

listener 1883 localhost

listener 8883
certfile /etc/letsencrypt/live/example.com/cert.pem
cafile /etc/letsencrypt/live/example.com/chain.pem
keyfile /etc/letsencrypt/live/example.com/privkey.pem

继承我的脚本,用于测试经纪人在1883年没有TLS的情况下正常工作

client = mqtt.Client("test")
client.tls_set(certfile="./mqtt/cert.pem", keyfile="./mqtt/key.pem")
client.connect("example.com", 8883)

#publish file as zip
with open("./mqtt/20180319171000.gz", 'rb') as f:
    byte_array = f.read()
    m.update(byte_array)
    file_hash = m.hexdigest()
    payload_json = {'byte_array': byte_array, 'md5': file_hash}
    client.publish("topic", pickle.dumps(payload_json), 0)
time.sleep(1)
client.disconnect()

TLS的有效负载大小是否有限制,或者我的设置/脚本有问题?

2 个答案:

答案 0 :(得分:0)

一个老问题,但我在处理大消息 (>500kb) 时遇到了同样的问题。我的解决方案是将客户端的 keepalive 从(默认)60 秒增加到 300 秒。

这可能与 TLS 加密超时有关,大消息的时间比 keepalive 时间长。

编辑:为连接添加了python代码:

client.connect(
    host="example.com",
    port=8883,
    keepalive=300)

更新: 我发现这个问题正在寻找与我的问题相似的问题的答案,即使用 MQTT TLS 时,MQTT 发布对于大型(> 500kb)有效载荷失败。正如@hardillb 在他的回答中指出的那样,OP 缺少 client.loop_start()。然而,这并不能解决我的问题。

keepalive 应该没有影响,但事实并非如此。增加值肯定会解决问题。我的理论是,代理在超时时连接失败,因为它尝试 PING 客户端,但客户端拒绝响应 {​​{1}},因为它正忙于尝试加密消息。不过,这只是一种理论。

我已经创建了一些测试代码来说明问题。我还包含了一个“最后的遗嘱”来检查连接是否在没有正确断开连接的情况下丢失(),这似乎符合我的理论。使用太小的 keepalive 肯定会激活经纪人的最后一个遗嘱,表明“超时”。

增加 keepalive 不会激活经纪人的“最后遗嘱”。

这是我用来测试不同 keepalive 值和有效负载大小的代码。

keepalive

使用上面的代码 (import paho.mqtt.client as mqtt_client import time from datetime import datetime password = 'somepassword' user = 'someuser' address = 'somebroker.no' connected = False def on_connect(client, userdata, flags, rc): global connected connected = True print("Connected!") def on_disconnect(client, userdata, rc): global connected connected = False print("Disconnected!") client = mqtt_client.Client() client.username_pw_set(user, password) client.on_connect = on_connect client.on_disconnect = on_disconnect client.tls_set() client.will_set(topic='tls_test/connected', payload='False', qos=0, retain=True) client.connect(host=address, port=8883, keepalive=100) client.loop_start() while not connected: time.sleep(1) topic = 'tls_test/abc' payload = 'a'*1000000 start = time.time() print('Start: {}'.format(datetime.fromtimestamp(start).strftime('%H:%M:%S'))) result = client.publish(topic='tls_test/connected', payload='True', qos=0, retain=True) result = client.publish(topic=topic, payload=payload) if result.rc != 0: print("MQTT Publish failed: {}".format(result.rc)) exit() client.loop_stop() client.disconnect() stop = time.time() print('Stop: {}, delta: {} sec'.format(datetime.fromtimestamp(stop).strftime('%H:%M:%S'), stop-start)) ),它发送 1000.000 字节并且 keepalive=100 在完成后在代理上具有值 tls_test/connected。 数据传输成功,控制台输出为:

True

减少keepalive(python3 .\mqtt_tls.py Connected! Start: 10:51:16 Disconnected! Stop: 10:53:01, delta: 105.57992386817932 sec ),传输失败,完成后keepalive=10在broker上的值为tls_test/connected。 数据传输失败,控制台输出:

False

在代理上拖尾 python3 .\mqtt_tls.py Connected! Start: 11:08:23 Disconnected! Disconnected! Stop: 11:08:43, delta: 19.537118196487427 sec 会给出以下错误消息:

/var/log/mosquitto/mosquitto.log

我的结论是:1612346903: New client connected from x.x.x.x as xxx (c1, k10, u'someuser'). 1612346930: Socket error on client xxx, disconnecting. 确实在使用 TLS 时对大型负载有影响

答案 1 :(得分:0)

这里的问题是 MQTT 客户端循环没有运行。

当负载大于单个 TCP 数据包的容量时,对 client.publish() 的调用需要将消息的其余部分排队,然后将其分解为多个数据包并通过客户端循环发送。< /p>

正确的反应是不要增加keepalive时间。使用 python Paho 库有两种方法可以解决这个问题。

首先,您可以使用 Publish 类而不是 Client 类。这包括一个处理所有后台任务的函数,以确保传递整个消息。

import paho.mqtt.publish as publish

tls_opt = {
  'certfile':"./mqtt/cert.pem", 
  'keyfile':"./mqtt/key.pem"
}

with open("./mqtt/20180319171000.gz", 'rb') as f:
    byte_array = f.read()
    m.update(byte_array)
    file_hash = m.hexdigest()
    payload_json = {'byte_array': byte_array, 'md5': file_hash}
    publish.single("topic", payload=pickle.dumps(payload_json), qos=0, hostname="example.com", port=8883, tls=tls_opt)

二是开始网络循环如下:

client = mqtt.Client("test")
client.tls_set(certfile="./mqtt/cert.pem", keyfile="./mqtt/key.pem")
client.connect("example.com", 8883)
client.loop_start()

#publish file as zip
with open("./mqtt/20180319171000.gz", 'rb') as f:
    byte_array = f.read()
    m.update(byte_array)
    file_hash = m.hexdigest()
    payload_json = {'byte_array': byte_array, 'md5': file_hash}
    client.publish("topic", pickle.dumps(payload_json), 0)
time.sleep(1)
client.loop_stop()
client.disconnect()