我已经实施了一个无担保的蚊子经纪人,可以通过端口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的有效负载大小是否有限制,或者我的设置/脚本有问题?
答案 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()