学习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 disconnected dispatch(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 bytes retain(#mqtt_message{retain = true, topic = Topic, payload = <<>>}) -> emqttd_backend:delete_message(Topic);