Python Paho MQTT客户端自签名证书的websockets,如何?
在Python中使用Paho与websockets和自签名证书进行https:// websocket连接有一些隐患,所以我在这里用一些示例代码解决这个问题。
输入ssl
进口时间
输入paho.mqtt.client作为mqttclass PCPMQTTClient:
def on_connect(self, client, userdata, flags, rc):
self.connection_status = rc
如果rc == 0。
self.connected_flag = True
self.connection_error_flag = False
否则。
self.connected_flag = False
self.connection_error_flag = True当一个要用publish()发送的信息被调用时,#被调用。
#已完成向经纪人的传输
# for qos=0 -> 信息已离开客户端
# for qos=1 & 2 -> 握手已经完成。
#中间变量与publish()返回的中间变量相匹配。
def on_publish(self, client, userdata, mid):
如果self.verbose。
print("publish callback mid:" + str(mid))def on_log(client, userdata, level, buf):
print(buf)def testconnection(self):
返回 self.connect(test=True)def connect(self, test=False):
如果测试。
print("Connecting to MQTT", end=")
self.connection_status = -1 # 尚无连接尝试
self.connection_error_flag = False
self.mqttc.connect_async(
host=self.connectiondata['host']。
port=self.connectiondata['port']。
keepalive=60。
bind_address="")self.mqttc.loop_start() # 根据Steve的说法,最好是在连接之后。
continue_flag = False
keep_connection_flag = not test
timeout_counter = 0
而不是continue_flag。
时间.睡眠(1)
timeout_counter += 1
如果测试。
print(".", end=") # end="将抑制换行。
如果self.connected_flag。
continue_flag = True
如果timeout_counter>6。
continue_flag = True
keep_connection_flag = False
code = self.connection_status
success = False
如果代码==0。
成功 = 真
message = "连接成功!"
self.connected_flag = True
if not keep_connection_flag: #有必要这样做,以检测我们是否能够连接上!
self.disconnect() #干净地从服务器断开连接
elif code == -1:
message = "连接超时 - 服务器不在线?证书错误(尝试-selfsigned)?"
elif code == 1:
message = "连接拒绝 - 协议版本不正确"
elif code == 2:
message = "Connection refused - invalid client identifier"
elif code == 3:
message = "拒绝连接 - 服务器不可用"
elif code == 4:
message = "连接被拒绝 - 用户名或密码错误"
elif code == 5:
message = "连接被拒绝 - 未授权"
否则。
message = "另一个错误" + str(code) + " 发生了,请检查Paho文档"
print(")
返回 {"success": 成功, "code": 代码, "message": 消息}。def publish(self, topic, message, qos=0, retain=False):
success = False
code = 'PCP_WRONG_INPUTFORMAT' 。
error_message = '错误的数据输入格式(例如,主题不能为空)' 。
如果有话题。
pubresult = self.mqttc.publish(
topic=topic,
payload=message。
qos=qos。
retain=retain)
#进程公布结果
如果pubresult.rc == mqtt.MQTT_ERR_SUCCESS。
code = 'MQTT_ERR_SUCCESS'。
error_message = 'Successfully sent message to broker.
成功 = 真
elif pubresult.rc == mqtt.MQTT_ERR_NO_CONN:
code = 'MQTT_ERR_NO_CONN' 。
error_message = '没有连接到MQTT服务器,尝试重新连接' 。
elif pubresult.rc == mqtt.MQTT_ERR_QUEUE_SIZE:
code = 'MQTT_ERR_QUEUE_SIZE' 。
error_message = '消息既没有排队,也没有发送。返回 {"success": 成功, "code": 代码, "message": 错误信息, "mid": pubresult.mid}.
def disconnect(self):
#按照Steve的说法 http://www.steves-internet-guide.com/client-connections-python-mqtt/
self.mqttc.loop_stop()
self.mqttc.disconnect()
self.connected_flag = Falsedef __init__(self, connectiondata, verbose=False, insecure=False):
self.verbose = verbose
clean_session = True
self.mqttc = mqtt.Client(
client_id=connectiondata['client_id']。
clean_session=clean_session。
userdata=None。
protocol=mqtt.MQTTv311,
transport=connectiondata['transport'])
self.connectiondata = connectiondata
self.connected_flag = False
self.mqttc.on_connect = self.on_connect
self.mqttc.on_publish = self.on_publish
如果self.verbose。
print("### enabling logging for MQTT Client ##")
self.mqttc.on_log = self.on_log
self.mqttc.username_pw_set(
username=connectiondata['username']。
password=connectiondata['password'])
如果connectiondata['transport'] == "websockets"。
self.mqttc.ws_set_options(path=self.connectiondata['path'] )
如果self.verbose。
print("###连接,参数如下 ###" )
print("* client_id: " + connectiondata['client_id'] )
print("* clean_session:" + str(clean_session))
print("* transport: " + connectiondata['transport'] )
print("* path: " + connectiondata['path'] )
print("* username: " + connectiondata['username'] )
print("*密码:(不显示!)")
# self.mqttc.tls_set_context()。
如果不安全。
self.mqttc.tls_set(cert_reqs=ssl.CERT_NONE)
如果self.verbose。
print("###不安全操作模式(-selfsigned)设置!#1T3T1T3T")
self.mqttc.tls_insecure_set(True)
否则。
self.mqttc.tls_set()
正如你所看到的,对于不安全的连接,做两件事情是很重要的。
- tls_set(cert_reqs=ssl.CERT_NONE)
- tls_insecure_set(True)
tls_insecure_set(True)调用将允许你省略证书名称匹配。它仍然会尝试确保证书是 有效 按照证书链的规定!
因此,我想这是一个有点错误的名称。
上面显示的示例代码是picockpit-client的开发的一部分,用于 picockpit.com平台
Paho / Websockets
connectiondata['transport'] 在代码的其他地方设置。它可以是(一个字符串)"tcp "或 "websockets"。
如果你指定了websockets,你可以另外使用ws_set_options来设置一个路径,例如"/mqtt"。
host=self.connectiondata['host']。
port=self.connectiondata['port']。
主机是你的网络主机 - 没有http/https前缀。例如,对于本地开发,我使用 "picockpit.local"(通过envoy代理,见我其他文章)。
端口,在TLS/SSL连接的情况下,默认HTTPS端口为443。
为方便调试而提出的建议。
为了更好地进行调试,将异步连接代码切换到同步连接(替换connect_async)。
self.mqttc.connect(
host=self.connectiondata['host']。
port=self.connectiondata['port']。
keepalive=60。
bind_address="")
参考文献。
- https://github.com/eclipse/paho.mqtt.python/issues/85
- https://github.com/eclipse/paho.mqtt.python/issues/148
- https://aws.amazon.com/blogs/iot/how-to-implement-mqtt-with-tls-client-authentication-on-port-443-from-client-devices-python/
- https://www.eclipse.org/paho/clients/python/docs/ - Paho Python官方文档