这次,分析处理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的不同,决定是

  1. 自己调用后续函数完成处理
  2. 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消息了)的更多相关文章

  1. (转)RabbitMQ消息队列(九):Publisher的消息确认机制

    在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...

  2. RabbitMQ消息队列(九):Publisher的消息确认机制

    在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...

  3. NATS—消息通信模型

    消息通信模型 NATS的消息通信是这样的:应用程序的数据被编码为一条消息,并通过发布者发送出去:订阅者接收到消息,进行解码,再处理.订阅者处理NATS消息可以是同步的或异步的. * 异步处理  异步处 ...

  4. MQTT-SN协议乱翻之消息格式

    前言 紧接着上篇初步介绍,本文为第二篇,主要梳理MQTT-SN 1.2协议中定义的消息格式. 通用消息格式 消息头 其它可变部分 2/4字节表示 N字节组成 消息头部 长度 消息类型 1或3个字节 1 ...

  5. MQTT协议笔记之消息流

    前言 前面的笔记已把所有消息类型都过了一遍,这里从消息流的角度尝试解读一下. 网络故障 在任何网络环境下,都会出现一方连接失败,比如离开公司大门那一刻没有了WIFI信号.但持续连接的另一端-服务器可能 ...

  6. RabbitMQ---9、消息确认机制(事务+Confirm)

    转载至:https://blog.csdn.net/u013256816/article/details/55515234 参考资料:https://www.cnblogs.com/520playbo ...

  7. RabbitMQ 之消息确认机制(事务+Confirm)

    概述 在 Rabbitmq 中我们可以通过持久化来解决因为服务器异常而导致丢失的问题,除此之外我们还会遇到一个问题:生产者将消息发送出去之后,消息到底有没有正确到达 Rabbit 服务器呢?如果不错得 ...

  8. php redis pub/sub(Publish/Subscribe,发布/订阅的信息系统)之基本使用

    一.场景介绍 最近的一个项目需要用到发布/订阅的信息系统,以做到最新实时消息的通知.经查找后发现了redis pub/sub(发布/订阅的信息系统)可以满足我的开发需求,而且学习成本和使用成本也比较低 ...

  9. 【RabbitMQ学习记录】- 消息队列存储机制源码分析

    本文来自 网易云社区 . RabbitMQ在金融系统,OpenStack内部组件通信和通信领域应用广泛,它部署简单,管理界面内容丰富使用十分方便.笔者最近在研究RabbitMQ部署运维和代码架构,本篇 ...

随机推荐

  1. LuManager升级php5.6.27方法

    LuManager自带的PHP在FastCGI模式是 5.2.17版,非FastCGI模式是 5.3.14版.由于360网盘的停服,已不敢再用那些免费的网盘,干脆自己搭个私有云.查了下相关资料准备先试 ...

  2. JS 闭包应用

    1. 代替全局变量 //闭包应用1:代替全局变量的使用 //多个函数都用到一个变量,通常我们会定义一个全局变量,然后在各函数中应用它,//为了避免使用全局变量,可以通过使用立即执行函数定义临时变量,子 ...

  3. JAR_给别人使用

    1. http://zhidao.baidu.com/link?url=Ru2tGNV5iRsuRYlEdWzmKDRz88aYqHAqQBQy8sCaHWhjJpaJpbTGibEk-zyxegNJ ...

  4. linux rpm 卸载,简单说明

    平时Linux卸载文件总是遇到卸载不干净,各种依赖什么的,今天又是搞这玩意,就记录下一个比较常规的方法. 一.查询包括某关键字的软件(这里以卸载openoffice为例) 查询包括office的软件 ...

  5. selenium学习笔记(selenium下载安装)

    博主自己捣鼓的接口框架先到这里 等工作上正式开始使用再后续完善需求 还是继续学习python.学编程就直接动手写 就想看看python+selenium的组合 什么都不多说.先下载安装 博主这里已经安 ...

  6. spring3: 对JDBC的支持 之 Spring提供的其它帮助 SimpleJdbcInsert/SimpleJdbcCall/SqlUpdate/JdbcTemplate 生成主键/批量处理

    7.4  Spring提供的其它帮助 7.4.1  SimpleJdbc方式 Spring JDBC抽象框架提供SimpleJdbcInsert和SimpleJdbcCall类,这两个类通过利用JDB ...

  7. 使用Monkey对apk做稳定性测试

    认识Monkey 官方文档:https://developer.android.com/studio/test/monkey.html 什么是Monkey? Monkey是Android中的一个命令行 ...

  8. LightOJ - 1248 期望

    题意:有一个n面筛子,每次扔一下,每面概率相同,要求扔出n面的期望次数 题解:和第三篇论文里的例题一样,算从第i个到第i+1个的概率是(n-i)/n,n面中找n-i个没有扔到过的,期望是n/(n-i) ...

  9. *android判断手机号的运营商

    TextView tv=(TextView)findViewById(R.id.tv); TelephonyManager telManager = (TelephonyManager) getSys ...

  10. 深度学习(六十五)移动端网络MobileNets