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部署运维和代码架构,本篇 ...
随机推荐
- HBase 协处理器编程详解第一部分:Server 端代码编写
Hbase 协处理器 Coprocessor 简介 HBase 是一款基于 Hadoop 的 key-value 数据库,它提供了对 HDFS 上数据的高效随机读写服务,完美地填补了 Hadoop M ...
- Spring 静态注入讲解(MethodInvokingFactoryBean)
/* * Copyright (c) 2017 4PX Information Technology Co.,Ltd. All rights reserved. */package com.fpx.o ...
- dataframe 列名重新排序
在用list包含多个dict的模式生成dataframe时,由于dict的无序性,而uci很多数据的特征名直接是1,2,3...,生成的dataframe和原生的不一样, 为了方便观看和使用,我们将其 ...
- scala学习手记30 - 闭包
首先要弄白闭包的概念. 教材中的说法是:闭包是一种特殊的函数值,闭包中封闭或绑定了在另一个作用域或上下文中定义的变量.这里说闭包是一种特殊的函数值. 维基百科中的说法是:在计算机科学中,闭包(英语:C ...
- 新东方雅思词汇---8.1、reckon
新东方雅思词汇---8.1.reckon 一.总结 一句话总结:reck(注意,留心)+on 英 ['rek(ə)n] 美 ['rɛkən] vt. 测算,估计:认为:计算 vi. 估计:计算:猜 ...
- 从Activity中返回数据
从Activity中返回数据 一.简介 这里也就是使用intent方式返回数据. 二.具体步骤 在MainActivity通过一个button访问Activity01页面,然后将Activity01页 ...
- CSS颜色表示法、颜色表(调色板)
1.CSS 颜色使用组合了红绿蓝颜色值 (RGB) 的十六进制 (hex) 表示法进行定义.对光源进行设置的最低值可以是 0(十六进制 00).最高值是 255(十六进制 FF). 2.十六进制值使用 ...
- Cassandra 数据模型设计,根据你的查询来制定设计——反范式设计本质:空间换时间
转自:http://www.infoq.com/cn/articles/best-practice-of-cassandra-data-model-design 不要把Cassandra model想 ...
- ionic2常见问题——启动后白屏问题
问题描述 app启动后大概有几秒白屏,才会显示首页. 解决方案 图 1-最初config.xml配置 图 2-更改后的splash配置 代码: <preference name="Sh ...
- 【poj1195】Mobile phones(二维树状数组)
题目链接:http://poj.org/problem?id=1195 [题意] 给出一个全0的矩阵,然后一些操作 0 S:初始化矩阵,维数是S*S,值全为0,这个操作只有最开始出现一次 1 X Y ...