IOT MQTT 消息队列遥测传输收发 Message Queuing Telemetry Transport Quick Start

GitHub的官方中有文档和使用的例子代码
http://www.eclipse.org/paho/

Quick Start

pypi.org

pip install paho-mqtt
  • MQTT主要由3部分组成,服务器,发送器,接收器(订阅器)
  • Quick Start :
  • 将官方界文档中的”The full code“中的”The code of publishing messages“和”The code of subscribing“的代码分别拷贝到两个py文件中,分别运行即可在控制台中看到发送与接收的过程
  • 如果无法运行可能是网络代理的问题(有时只开启接收也能收到消息,因为是使用相同的代码)
EMQ官方文档官方的翻译
brokern. 经纪人; 掮客; vt. 安排,协商(协议的细节,尤指在两国间);在此指服务器
客户端client = paho.mqtt.client.Client(client_id) # 创建
client.on_connect = on_connect # 需要编写回调函数
client.connect(broker, port)# 链接,连接后调用回调函数
发送功能result = client.publish(topic, payload = msg)
订阅功能client.subscribe(topic)
收到消息的处理函数 client.on_message = on_message
消息服务器的创建
MQTT-Explorer-Setup-0.4.0(辅助设备), mosquitto-2.0.12-install-windows-x64(服务器)安装后设置ip:port,点击连接即可启动(如果失败区控制面板的服务开启Mosquitto Broker服务)
EMQ(云设备)开源云原生分布式物联网 MQTT 消息服务器免费试用的链接
thingsboard(云设备)https://thingsboard.io/ ,B站教程,包含二次开发

一般使用流程:

  • 使用connect()/connect_async()连接到代理
  • 频繁调用loop()以维护与代理的网络通信流
  • 或者使用loop_start()设置一个正在运行的线程,以便为您调用loop()。
  • 或者使用loop_forever()在阻塞中为您处理调用loop()
    client = connect_mqtt()
    client.loop_start()
    publish(client)

    client = connect_mqtt()
    subscribe(client)
    client.loop_forever()

*功能。

  • 使用subscribe()订阅主题并接收消息
  • 使用publish()发送消息
  • 使用disconnect()断开与代理的连接

可以使用以下的回调函数获取服务器的信息:

on_connect, on_connect_fail, on_disconnect, on_message, on_publish,on_subscribe, on_unsubscribe, on_log, on_socket_open, on_socket_close,on_socket_register_write, on_socket_unregister_write 比如:

def on_connect(client, userdata, flags, rc):
        print("Connection returned " + str(rc))


def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")

    client.subscribe(topic)
    client.on_message = on_message

所以一般情况下,开发人员需要些两部分的代码,一部分是

请求的发出

    client = connect_mqtt() # 返回一个链接:使用函数on_connect(client, userdata, flags, rc)链接服务器,client.connect(broker, port)
    client.loop_start()
    publish(client)# 发送消息:client.publish(topic_publish, **, qos=2, retain=False)

一部分是请求的接受并处理

    client.on_message=on_message#  回调函数主要是实现当订阅的topic来消息时动作处理
    client.on_connect=on_connect # 回调函数主要是实现订阅一个tipic client.subscribe(TASK_TOPIC, qos=2)
    client.connect(mqttip,mqttport,mqttkeepalive)  

参考部分

# MQTT相关
[MQTT 客户端工具之 MQTT Explorer 介绍](https://www.iotschool.com/topics/552)
[如何快速了解MQTT协议?一篇就够了](https://bbs.huaweicloud.com/blogs/196152)
[MQTT协议介绍](https://www.runoob.com/w3cnote/mqtt-intro.html)
[加入线程](https://www.cnblogs.com/countryboy666/p/14076831.html)
[MQTT主题通配符](https://blog.csdn.net/zsm180/article/details/123736316)
# 服务器设置
[https://www.emqx.com/en/cloud](https://www.emqx.com/en/cloud)
[树莓派教程](https://www.bilibili.com/video/BV1E44y1B7yr/?spm_id_from=pageDriver)
[树莓派代码](http://www.yoyolife.fun/article/97)
[3行代码搭建简易mqtt服务器,简单到没朋友。mosquitto支持websocket小程序](https://www.bilibili.com/video/BV19R4y147h3/?spm_id_from=autoNext)
[阿里云物联网平台](https://help.aliyun.com/document_detail/73728.html)
[阿里云物联网平台的教程](https://www.bilibili.com/video/BV1NE411e7oa?)

注:官方中提供了未良好实现的功能:clean_session 为 False 和 True的细节,当 clean_session 为 False 时,会话只存储在内存中而不是持久化。客户端重新启动时会话丢失,导致消息丢失。当 clean_session 为 True 时,此库将通过网络重新连接重新发布 QoS > 0 消息,可能造成信息的重发。

  • 客户端创建的部分官方代码:
class Client(object):
    """MQTT version 3.1/3.1.1/5.0 client class.

    This is the main class for use communicating with an MQTT broker.

    General usage flow:

    * Use connect()/connect_async() to connect to a broker
    * Call loop() frequently to maintain network traffic flow with the broker
    * Or use loop_start() to set a thread running to call loop() for you.
    * Or use loop_forever() to handle calling loop() for you in a blocking
    * function.
    * Use subscribe() to subscribe to a topic and receive messages
    * Use publish() to send messages
    * Use disconnect() to disconnect from the broker

    Data returned from the broker is made available with the use of callback
    functions as described below.

    Callbacks
    =========

    A number of callback functions are available to receive data back from the
    broker. To use a callback, define a function and then assign it to the
    client:

    def on_connect(client, userdata, flags, rc):
        print("Connection returned " + str(rc))

    client.on_connect = on_connect

    Callbacks can also be attached using decorators:

    client = paho.mqtt.Client()

    @client.connect_callback()
    def on_connect(client, userdata, flags, rc):
        print("Connection returned " + str(rc))


    **IMPORTANT** the required function signature for a callback can differ
    depending on whether you are using MQTT v5 or MQTT v3.1.1/v3.1. See the
    documentation for each callback.

    All of the callbacks as described below have a "client" and an "userdata"
    argument. "client" is the Client instance that is calling the callback.
    "userdata" is user data of any type and can be set when creating a new client
    instance or with user_data_set(userdata).

    If you wish to suppress exceptions within a callback, you should set
    `client.suppress_exceptions = True`

    The callbacks are listed below, documentation for each of them can be found
    at the same function name:

    on_connect, on_connect_fail, on_disconnect, on_message, on_publish,
    on_subscribe, on_unsubscribe, on_log, on_socket_open, on_socket_close,
    on_socket_register_write, on_socket_unregister_write
    """

    def __init__(self, client_id="", clean_session=None, userdata=None,
                 protocol=MQTTv311, transport="tcp", reconnect_on_failure=True):
        """client_id is the unique client id string used when connecting to the
        broker. If client_id is zero length or None, then the behaviour is
        defined by which protocol version is in use. If using MQTT v3.1.1, then
        a zero length client id will be sent to the broker and the broker will
        generate a random for the client. If using MQTT v3.1 then an id will be
        randomly generated. In both cases, clean_session must be True. If this
        is not the case a ValueError will be raised.

        clean_session is a boolean that determines the client type. If True,
        the broker will remove all information about this client when it
        disconnects. If False, the client is a persistent client and
        subscription information and queued messages will be retained when the
        client disconnects.
        Note that a client will never discard its own outgoing messages on
        disconnect. Calling connect() or reconnect() will cause the messages to
        be resent.  Use reinitialise() to reset a client to its original state.
        The clean_session argument only applies to MQTT versions v3.1.1 and v3.1.
        It is not accepted if the MQTT version is v5.0 - use the clean_start
        argument on connect() instead.

        userdata is user defined data of any type that is passed as the "userdata"
        parameter to callbacks. It may be updated at a later point with the
        user_data_set() function.

        The protocol argument allows explicit setting of the MQTT version to
        use for this client. Can be paho.mqtt.client.MQTTv311 (v3.1.1),
        paho.mqtt.client.MQTTv31 (v3.1) or paho.mqtt.client.MQTTv5 (v5.0),
        with the default being v3.1.1.

        Set transport to "websockets" to use WebSockets as the transport
        mechanism. Set to "tcp" to use raw TCP, which is the default.
        """

        if transport.lower() not in ('websockets', 'tcp'):
            raise ValueError(
                'transport must be "websockets" or "tcp", not %s' % transport)
        self._transport = transport.lower()
        self._protocol = protocol
        self._userdata = userdata
        self._sock = None
        self._sockpairR, self._sockpairW = (None, None,)
        self._keepalive = 60
        self._connect_timeout = 5.0
        self._client_mode = MQTT_CLIENT
  • 发送订阅两个函数的官方实现:
    def subscribe(self, topic):
        """Subscribe to a topic

        Only for SUB sockets.

        .. versionadded:: 15.3
        """
        if isinstance(topic, unicode):
            topic = topic.encode('utf8')
        self.set(zmq.SUBSCRIBE, topic)
    def publish(self, topic, payload=None, qos=0, retain=False, properties=None):
        """Publish a message on a topic.

        This causes a message to be sent to the broker and subsequently from
        the broker to any clients subscribing to matching topics.

        topic: The topic that the message should be published on.
        payload: The actual message to send. If not given, or set to None a
        zero length message will be used. Passing an int or float will result
        in the payload being converted to a string representing that number. If
        you wish to send a true int/float, use struct.pack() to create the
        payload you require.
        qos: The quality of service level to use.
        retain: If set to true, the message will be set as the "last known
        good"/retained message for the topic.
        properties: (MQTT v5.0 only) the MQTT v5.0 properties to be included.
        Use the Properties class.

        Returns a MQTTMessageInfo class, which can be used to determine whether
        the message has been delivered (using info.is_published()) or to block
        waiting for the message to be delivered (info.wait_for_publish()). The
        message ID and return code of the publish() call can be found at
        info.mid and info.rc.

        For backwards compatibility, the MQTTMessageInfo class is iterable so
        the old construct of (rc, mid) = client.publish(...) is still valid.

        rc is MQTT_ERR_SUCCESS to indicate success or MQTT_ERR_NO_CONN if the
        client is not currently connected.  mid is the message ID for the
        publish request. The mid value can be used to track the publish request
        by checking against the mid argument in the on_publish() callback if it
        is defined.

        A ValueError will be raised if topic is None, has zero length or is
        invalid (contains a wildcard), except if the MQTT version used is v5.0.
        For v5.0, a zero length topic can be used when a Topic Alias has been set.

        A ValueError will be raised if qos is not one of 0, 1 or 2, or if
        the length of the payload is greater than 268435455 bytes."""
        if self._protocol != MQTTv5:
            if topic is None or len(topic) == 0:
                raise ValueError('Invalid topic.')

        topic = topic.encode('utf-8')

        if self._topic_wildcard_len_check(topic) != MQTT_ERR_SUCCESS:
            raise ValueError('Publish topic cannot contain wildcards.')

        if qos < 0 or qos > 2:
            raise ValueError('Invalid QoS level.')

        if isinstance(payload, unicode):
            local_payload = payload.encode('utf-8')
        elif isinstance(payload, (bytes, bytearray)):
            local_payload = payload
        elif isinstance(payload, (int, float)):
            local_payload = str(payload).encode('ascii')
        elif payload is None:
            local_payload = b''
        else:
            raise TypeError(
                'payload must be a string, bytearray, int, float or None.')

        if len(local_payload) > 268435455:
            raise ValueError('Payload too large.')

        local_mid = self._mid_generate()

        if qos == 0:
            info = MQTTMessageInfo(local_mid)
            rc = self._send_publish(
                local_mid, topic, local_payload, qos, retain, False, info, properties)
            info.rc = rc
            return info
        else:
            message = MQTTMessage(local_mid, topic)
            message.timestamp = time_func()
            message.payload = local_payload
            message.qos = qos
            message.retain = retain
            message.dup = False
            message.properties = properties

            with self._out_message_mutex:
                if self._max_queued_messages > 0 and len(self._out_messages) >= self._max_queued_messages:
                    message.info.rc = MQTT_ERR_QUEUE_SIZE
                    return message.info

                if local_mid in self._out_messages:
                    message.info.rc = MQTT_ERR_QUEUE_SIZE
                    return message.info

                self._out_messages[message.mid] = message
                if self._max_inflight_messages == 0 or self._inflight_messages < self._max_inflight_messages:
                    self._inflight_messages += 1
                    if qos == 1:
                        message.state = mqtt_ms_wait_for_puback
                    elif qos == 2:
                        message.state = mqtt_ms_wait_for_pubrec

                    rc = self._send_publish(message.mid, topic, message.payload, message.qos, message.retain,
                                            message.dup, message.info, message.properties)

                    # remove from inflight messages so it will be send after a connection is made
                    if rc is MQTT_ERR_NO_CONN:
                        self._inflight_messages -= 1
                        message.state = mqtt_ms_publish

                    message.info.rc = rc
                    return message.info
                else:
                    message.state = mqtt_ms_queued
                    message.info.rc = MQTT_ERR_SUCCESS
                    return message.info

回调函数:作为其他函数的参数的函数
高阶函数:使用其他函数作为参数的函数

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值