emqtt 4 (我要publish消息了)
这次,分析处理publish msg的流程。
由protocol开始
publish 类型的packet的处理是:
process(Packet = ?PUBLISH_PACKET(_Qos, Topic, _PacketId, _Payload), State) ->
%% ACL check
...
publish(Packet, State);
...
publish(Packet = ?PUBLISH_PACKET(?QOS_0, _PacketId),
#proto_state{client_id = ClientId, username = Username, session = Session}) ->
%% 处理packet 获得msg
Msg = emqttd_message:from_packet(Username, ClientId, Packet),
%% 调用emqttd_session module的publish/2 函数
%% subscribe的时候,也是由protocol 进入的emqttd_session module
emqttd_session:publish(Session, Msg);
1、ACL 检查
2、处理packet 获得msg
3、调用session module进行处理
emqttd_session 模块处理
和subscribe的处理流程类似,emqttd_session:publish/2 也只是一个接口函数,该函数要根据QoS的不同,决定是
- 自己调用后续函数完成处理
- call session process 完成后续处理
%% @doc Publish message
-spec(publish(pid(), mqtt_message()) -> ok | {error, any()}).
publish(_SessPid, Msg = #mqtt_message{qos = ?QOS_0}) ->
%% publish qos0 directly
emqttd:publish(Msg);
publish(_SessPid, Msg = #mqtt_message{qos = ?QOS_1}) ->
%% publish qos1 directly, and client will puback automatically
emqttd:publish(Msg);
publish(SessPid, Msg = #mqtt_message{qos = ?QOS_2}) ->
%% publish qos2 by session
gen_server2:call(SessPid, {publish, Msg}, ?PUBSUB_TIMEOUT).
直接处理
如果是自己调用后续函数完成处理的话,则继续调用emqttd:publish/2,则在emqttd module 中继续调用emqttd_server:publish/1:
%% @doc Publish a Message
-spec(publish(Msg :: mqtt_message()) -> any()).
publish(Msg = #mqtt_message{from = From}) ->
...
%% 处理topic
...
%% pulish
emqttd_pubsub:publish(Topic, Msg2),
...
还是subscribe处理套路:
emqttd_protocol ---> emqttd_session ---> emqttd ---> emqttd_server ---> emqttd_pubsub
在emqttd_pubsub module中的处理是:
%% @doc Publish message to Topic.
-spec(publish(binary(), any()) -> any()).
publish(Topic, Msg) ->
lists:foreach(
fun(#mqtt_route{topic = To, node = Node}) when Node =:= node() ->
?MODULE:dispatch(To, Msg);
(#mqtt_route{topic = To, node = Node}) ->
rpc:cast(Node, ?MODULE, dispatch, [To, Msg])
end, emqttd_router:lookup(Topic)). dispatch(Topic, Msg) ->
case subscribers(Topic) of
[] ->
dropped(Topic);
[SubPid] ->
SubPid ! {dispatch, Topic, Msg};
SubPids ->
lists:foreach(fun(SubPid) ->
SubPid ! {dispatch, Topic, Msg}
end, SubPids)
end.
%% @private
%% @doc Find all subscribers
subscribers(Topic) ->
case ets:member(subscriber, Topic) of
true -> %% faster then lookup?
try ets:lookup_element(subscriber, Topic, 2) catch error:badarg -> [] end;
false ->
[]
end.
至此,msg 就已经以{dispatch, Topic, Msg}的形式发送给 clientid 对应的session process了。
那么,就需要在emqttd_session module中的handle_info callback 函数处进行处理:
%% Dispatch Message
handle_info({dispatch, Topic, Msg}, Session = #session{subscriptions = Subscriptions})
when is_record(Msg, mqtt_message) ->
dispatch(tune_qos(Topic, Msg, Subscriptions), Session); %% Deliver qos0 message directly to client
dispatch(Msg = #mqtt_message{qos = ?QOS0}, Session = #session{client_pid = ClientPid}) ->
ClientPid ! {deliver, Msg},
hibernate(Session);
dispatch(Msg = #mqtt_message{qos = QoS}, Session = #session{message_queue = MsgQ})
when QoS =:= ?QOS1 orelse QoS =:= ?QOS2 ->
case check_inflight(Session) of
true ->
noreply(deliver(Msg, Session));
false ->
hibernate(Session#session{message_queue = emqttd_mqueue:in(Msg, MsgQ)})
end.
继而,将信息发送给socket controlling process,然后根据QoS的不同,判断是否需要等待ack。
总结
(流程示意图待补)
emqtt 4 (我要publish消息了)的更多相关文章
- (转)RabbitMQ消息队列(九):Publisher的消息确认机制
在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...
- RabbitMQ消息队列(九):Publisher的消息确认机制
在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...
- NATS—消息通信模型
消息通信模型 NATS的消息通信是这样的:应用程序的数据被编码为一条消息,并通过发布者发送出去:订阅者接收到消息,进行解码,再处理.订阅者处理NATS消息可以是同步的或异步的. * 异步处理 异步处 ...
- MQTT-SN协议乱翻之消息格式
前言 紧接着上篇初步介绍,本文为第二篇,主要梳理MQTT-SN 1.2协议中定义的消息格式. 通用消息格式 消息头 其它可变部分 2/4字节表示 N字节组成 消息头部 长度 消息类型 1或3个字节 1 ...
- MQTT协议笔记之消息流
前言 前面的笔记已把所有消息类型都过了一遍,这里从消息流的角度尝试解读一下. 网络故障 在任何网络环境下,都会出现一方连接失败,比如离开公司大门那一刻没有了WIFI信号.但持续连接的另一端-服务器可能 ...
- RabbitMQ---9、消息确认机制(事务+Confirm)
转载至:https://blog.csdn.net/u013256816/article/details/55515234 参考资料:https://www.cnblogs.com/520playbo ...
- RabbitMQ 之消息确认机制(事务+Confirm)
概述 在 Rabbitmq 中我们可以通过持久化来解决因为服务器异常而导致丢失的问题,除此之外我们还会遇到一个问题:生产者将消息发送出去之后,消息到底有没有正确到达 Rabbit 服务器呢?如果不错得 ...
- php redis pub/sub(Publish/Subscribe,发布/订阅的信息系统)之基本使用
一.场景介绍 最近的一个项目需要用到发布/订阅的信息系统,以做到最新实时消息的通知.经查找后发现了redis pub/sub(发布/订阅的信息系统)可以满足我的开发需求,而且学习成本和使用成本也比较低 ...
- 【RabbitMQ学习记录】- 消息队列存储机制源码分析
本文来自 网易云社区 . RabbitMQ在金融系统,OpenStack内部组件通信和通信领域应用广泛,它部署简单,管理界面内容丰富使用十分方便.笔者最近在研究RabbitMQ部署运维和代码架构,本篇 ...
随机推荐
- Spring Cloud 与 Spring boot - 转载
微服务是这样一个结构吗? 前端或二方 - > ng集群 -> zuul集群 -> eureka-server集群 -> service provider集群 (二方指其他业务部 ...
- java 枚举类型 enum
在java SE5中添加了枚举类型,即enum关键字.在这之前,当你需要创建一个整形常量集时,但是这些枚举值并不会必然的将其自身的取值限制在这个常量集的范围之内,因此这样做的显得不安全,也不方便使用. ...
- 配置Nginx作为反向代理服务器
最近在实习公司的开发一个项目,项目是前后端彻底分离的项目,前端项目和后端项目各监听着特定的端口号,显然不是80的通用端口,为了不在地址栏上输入IP+端口号的形式,我们可以使用Nginx作为反向代理服务 ...
- FMDB官方使用文档 G-C-D的使用 提高性能(翻译)
由于FMDB是建立在SQLite的之上的,所以你至少也该把这篇文章从头到尾读一遍.与此同时,把SQLite的文档页 加到你的书签中.自动引用计数(APC)还是手动内存管理呢? 两种都行,FMDB会 ...
- neutron二层网络实现
一.基本概念 1.tap设备 比如vnet0,是虚拟化技术和KVM和XEN用来实现虚拟网卡的,当一个以太网帧发送给TAP设备时,这个以太网帧就会被虚拟机操作系统所接手,命名空间用于隔离虚拟网络设备. ...
- Oracle Package
(转自:http://blog.csdn.net/bbliutao/article/details/9016947) 一.概述包可将一些有联系的对象放在其内部.任何能在块定义部分出现的对象都可以在包中 ...
- 限流之令牌桶算法——RateLimiter官方文档
原文链接 作者:Dimitris Andreou 译者:魏嘉鹏 校对:方腾飞 RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证.如果必要的话,每个acquire() 会阻 ...
- lzugis——Arcgis Server for JavaScript API之POI
POI(Point Of Interest),感兴趣点,其实呢,严格意义上说应该不是POI,但是单位就这样叫了,我也就这样叫了,其实现的功能大致是这样的:用过百度地图的朋友们都知道你在百度地图时,当鼠 ...
- iOS开发之最近开发遇到的问题总结
1.Cannot create __weak reference in file using manual reference counting 解决办法: 点击工程-------->Build ...
- Android 进阶7:进程通信之 AIDL 的使用
读完本文你将了解: AIDL 是什么 AIDL 支持的数据类型 AIDL 如何编写 AIDL 实例 创建 AIDL 编写服务端代码 编写客户端代码 运行结果 总结 代码地址 Thanks 记得 201 ...