我的mqtt协议和emqttd开源项目个人理解(1)

来源:互联网 发布:python 条件循环 编辑:程序博客网 时间:2024/06/03 06:59

学习mqtt协议和emqttd开源项目http://emqtt.com/

emqttd源码版本号是v1.1.3。http://emqtt.com/downloads/1113

官方文档有定义:

MQTT会话(Clean Session)
MQTT客户端向服务器发起CONNECT请求时,可以通过’Clean Session’标志设置会话。
‘Clean Session’设置为0,表示创建一个持久会话,在客户端断开连接时,会话仍然保持并保存离线消息,直到会话超时注销。
‘Clean Session’设置为1,表示创建一个新的临时会话,在客户端断开时,会话自动销毁。

MQTT保留消息(Retained Message)
MQTT客户端向服务器发布(PUBLISH)消息时,可以设置保留消息(Retained Message)标志。保留消息(Retained Message)会驻留在消息服务器,后来的订阅者订阅主题时仍可以接收该消息。


究竟如何来理解?我们来看实例:

图1 emqttd ets一览


图2 emqttd Mnesia一览

一、关于clean session的说明

ets:mqtt_persistent_session
ets:subscribed
ets:subscriber
Mnesia:session
Mnesia:subscription
Mnesia:topic
当clean session的值为false,即保留会话,那么
该客户端上线,并订阅了主题"r",那么该主题会一直存在,即使客户端离线,该主题也仍然会记忆在EMQ服务器内存。
当客户端离线又上线时,仍然会接收到离线期间别人发来的publish消息(QoS=0,1,2)。类似即时通讯软件,终端可以接收离线消息。
除非客户端主动取消订阅主题,否则主题一直存在。另外,Mnesia本地不会持久化session,subscription和topic,服务器重启则丢失。


ets:mqtt_transient_session
当clean session的值为true,即不保留会话,那么
该客户端上线,并订阅了主题"r",那么该主题会随着客户端离线而删除。
当客户端离线又上线时,接收不到离线期间别人发来的publish消息。


不管clean session的值是什么,当终端设备离线时,QoS=0,1,2的消息一律接收不到。
当clean session的值为true,当终端设备离线再上线时,离线期间发来QoS=0,1,2的消息一律接收不到。
当clean session的值为false,当终端设备离线再上线时,离线期间发来QoS=0,1,2的消息仍然可以接收到。如果同个主题发了多条就接收多条,一条不差,照单全收。


我们来看emqttd服务器程序,客户端每发起一个tcp连接就会新建一个client connection和一次会话,后台会新建一个相应的connection进程和一个session进程。如图1所示,client connection的进程id是<11370.4114.0>。如图2所示,session的进程id是<11370.3126.0>。

如果终端设备离线之后,client connection的进程将销毁。

如果终端设备的clean session的值为true,那么它离线之后,会话将销毁,相应的session进程也会销毁。

如果终端设备的clean session的值为false,那么它离线之后,会话将得以保留,相应的session进程也仍然存在。也就是说,同一topic下,当设备A离线时,设备B在publish消息时,仍然可以匹配topic,进而找到这个session A进程,把消息发给设备A,缓存在消息队列里。设备A上线就可以收到离线消息。

emqttd v1.1.3-module(emqttd_session).%% Queue message if client disconnecteddispatch(Msg, Session = #session{client_pid = undefined, message_queue = Q}) ->    hibernate(Session#session{message_queue = emqttd_mqueue:in(Msg, Q)});

图3 esockd进程

图4 session进程

图5 ets关于订阅主题


二、关于retain的说明
Mnesia:retained_message
终端设备publish消息时,如果retain值是true,则服务器会一直记忆,哪怕是服务器重启。因为Mnesia会本地持久化。

如果服务器接收到终端publish某主题的消息,payload为空且retain值是true,则会删除这条持久化的消息。

如果服务器接收到终端publish某主题的消息,payload为空且retain值是false,则不会删除这条持久化的消息。

emqttd v1.1.3-module(emqttd_retainer).%% RETAIN flag set to 1 and payload containing zero bytesretain(#mqtt_message{retain = true, topic = Topic, payload = <<>>}) ->    emqttd_backend:delete_message(Topic);


原创粉丝点击