我的mqtt协议和emqttd开源项目个人理解(20) - 如果客户端clientid为空,emq会随机帮忙生成

简介: 我的mqtt协议和emqttd开源项目个人理解(20) - 如果客户端clientid为空,emq会随机帮忙生成

mqtt v3.1.1协议有规定clientid可以为空,所以当客户端clientid为空,emq会随机帮忙生成。



一、源码emq 1.1.3 -- emqttd_protocol.erl


客户端经过TCP三次握手建立连接之后,会发起mqtt connect packet,服务器接收到后开始处理这个数据包,入口函数就是如下的源文件,process函数:


https://github.com/emqx/emqx/blob/1.1.3/src/emqttd_protocol.erl


process(Packet = ?CONNECT_PACKET(Var), State0) ->
    #mqtt_packet_connect{proto_ver  = ProtoVer,
                         proto_name = ProtoName,
                         username   = Username,
                         password   = Password,
                         clean_sess = CleanSess,
                         keep_alive = KeepAlive,
                         client_id  = ClientId} = Var,
    State1 = State0#proto_state{proto_ver  = ProtoVer,
                                proto_name = ProtoName,
                                username   = Username,
                                client_id  = ClientId,
                                clean_sess = CleanSess,
                                keepalive  = KeepAlive,
                                will_msg   = willmsg(Var),
                                connected_at = os:timestamp()},
    trace(recv, Packet, State1),
    {ReturnCode1, SessPresent, State3} =
    case validate_connect(Var, State1) of
        ?CONNACK_ACCEPT ->
            case emqttd_access_control:auth(client(State1), Password) of
                ok ->
                    %% Generate clientId if null
                    State2 = maybe_set_clientid(State1),
validate_connect(Connect = #mqtt_packet_connect{}, ProtoState) ->
    case validate_protocol(Connect) of
        true -> 
            case validate_clientid(Connect, ProtoState) of
                true -> 
                    ?CONNACK_ACCEPT;
                false -> 
                    ?CONNACK_INVALID_ID
            end;
        false -> 
            ?CONNACK_PROTO_VER
    end.
%% MQTT3.1.1 allow null clientId.
validate_clientid(#mqtt_packet_connect{proto_ver =?MQTT_PROTO_V311,
                                       client_id = ClientId}, _ProtoState)
    when size(ClientId) =:= 0 ->
    true;
1、validate_connect(Var, State1)

先检查客户端使用的mqtt协议版本,检查clientid是否为空,如果是mqtt v3.1.1版本,可以为空。


https://github.com/emqx/emqx/blob/1.1.3/include/emqttd_protocol.hrl 源文件有定义validate_connect函数的返回值:

%%--------------------------------------------------------------------
%% MQTT Connect Return Codes
%%--------------------------------------------------------------------
-define(CONNACK_ACCEPT,      0).    %% Connection accepted
-define(CONNACK_PROTO_VER,   1).    %% Unacceptable protocol version
-define(CONNACK_INVALID_ID,  2).    %% Client Identifier is correct UTF-8 but not allowed by the Server
-define(CONNACK_SERVER,      3).    %% Server unavailable
-define(CONNACK_CREDENTIALS, 4).    %% Username or password is malformed
-define(CONNACK_AUTH,        5).    %% Client is not authorized to connect


2、emqttd_access_control:auth(client(State1), Password)


再做clientid和username的合法性校验,是否在用户的内存数据库或者mysql等地方。这个步骤可有可无,完全由用户自己使能决定。在emq2.3.11版本,这个函数是通过插件来实现的,分别是emq_auth_clientid和emq_auth_username。插件是选配件。


3、%% Generate clientId if null


State2 = maybe_set_clientid(State1),


如果clientid为空,随机生成clientid。例如'emqttd_105789339469322'。


4、模块emqttd_guid:new()负责生成。

%% Generate a client if if nulll
maybe_set_clientid(State = #proto_state{client_id = NullId})
        when NullId =:= undefined orelse NullId =:= <<>> ->
    {_, NPid, _} = emqttd_guid:new(),
    ClientId = iolist_to_binary(["emqttd_", integer_to_list(NPid)]),
    State#proto_state{client_id = ClientId};
maybe_set_clientid(State) ->
    State.


5、Process函数的最末尾,服务器会发送connack数据包给到客户端,里面的reruncode就是前面第1条提到的宏定义返回值。


%% Send connack

   send(?CONNACK_PACKET(ReturnCode1, sp(SessPresent)), State3);

注意:如果服务器发送了一个非零返回值的CONNACK报文,那么客户端就必须关闭网络连接。



二、源码emq 2.3.11 -- emqttd_protocol.erl


https://github.com/emqx/emqx/blob/v2.3.11/src/emqttd_protocol.erl


情况类似,不赘述


%% MQTT3.1.1 allow null clientId.

validate_clientid(#mqtt_packet_connect{proto_ver =?MQTT_PROTO_V4,

                                      client_id = ClientId}, _ProtoState)

   when byte_size(ClientId) =:= 0 ->

   true;

要注意的是,emq2.3.11使用了宏MQTT_PROTO_V4,其实和emq1.1.3版本的宏MQTT_PROTO_V311,数值是一样的,都代表mqtt协议3.1.1版本。


https://github.com/emqx/emqx/blob/v2.3.11/include/emqttd_protocol.hrl


%%--------------------------------------------------------------------

%% MQTT Protocol Version and Levels

%%--------------------------------------------------------------------

-define(MQTT_PROTO_V3, 3).

-define(MQTT_PROTO_V4, 4).

-define(MQTT_PROTO_V5, 5).

-define(PROTOCOL_NAMES, [

   {?MQTT_PROTO_V3, <<"MQIsdp">>},

   {?MQTT_PROTO_V4, <<"MQTT">>},

   {?MQTT_PROTO_V5, <<"MQTT">>}]).

 


相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
20天前
|
消息中间件 运维 Serverless
商业版vs开源版:一图看懂云消息队列 RocketMQ 版核心优势
自建开源 RocketMQ 集群,为保证业务稳定性,往往需要按照业务请求的峰值去配置集群资源。云消息队列 RocketMQ 版 Serverless 实例通过资源快速伸缩,实现资源使用量与实际业务负载贴近,并按实际使用量计费,有效降低企业的运维压力和使用成本。
|
10天前
|
数据采集 传感器 监控
多协议网关BL110钡铼6路RS485转MQTT协议云网关
BL110钡铼6路RS485转MQTT协议云网关是一款高性能、易配置的工业级设备,适用于各种需要远程监控和数据采集的物联网应用场景。通过将传统RS485设备的数据转换为MQTT协议并上传至云平台,实现了设备的远程管理和智能控制,极大地提升了系统的管理效率和响应速度。
20 2
|
1月前
|
消息中间件 弹性计算 运维
一图看懂云消息队列 RabbitMQ 版对比开源优势
一张图带您快速了解云消息队列 RabbitMQ 版对比开源版本的显著优势。
|
18天前
|
存储 算法 安全
FreeMQTT:一款Python语言实现的开源MQTT Server
FreeMQTT 是一款用 Python 语言并基于 Tornado 开发的开源 MQTT 服务器,支持 MQTT3.1.1 和 MQTT5.0 协议,提供多租户安全隔离、高效 Topic 匹配算法及实时上下线通知等功能,适用于 IoT 场景。快速启动仅需克隆仓库、安装依赖并运行服务。
|
2月前
|
网络协议 物联网 网络性能优化
物联网协议比较 MQTT CoAP RESTful/HTTP XMPP
【10月更文挑战第18天】本文介绍了物联网领域中四种主要的通信协议:MQTT、CoAP、RESTful/HTTP和XMPP,分别从其特点、应用场景及优缺点进行了详细对比,并提供了简单的示例代码。适合开发者根据具体需求选择合适的协议。
62 5
|
3月前
|
消息中间件 监控 物联网
MQTT协议对接及RabbitMQ的使用记录
通过合理对接MQTT协议并利用RabbitMQ的强大功能,可以构建一个高效、可靠的消息通信系统。无论是物联网设备间的通信还是微服务架构下的服务间消息传递,MQTT和RabbitMQ的组合都提供了一个强有力的解决方案。在实际应用中,应根据具体需求和环境进行适当的配置和优化,以发挥出这两个技术的最大效能。
197 0
|
4月前
|
消息中间件 存储 传感器
RabbitMQ 在物联网 (IoT) 项目中的应用案例
【8月更文第28天】随着物联网技术的发展,越来越多的设备被连接到互联网上以收集和传输数据。这些设备可以是传感器、执行器或其他类型的硬件。为了有效地管理这些设备并处理它们产生的大量数据,需要一个可靠的消息传递系统。RabbitMQ 是一个流行的开源消息中间件,它提供了一种灵活的方式来处理和转发消息,非常适合用于物联网环境。
187 1
|
4月前
|
物联网 C# 智能硬件
智能家居新篇章:WPF与物联网的智慧碰撞——通过MQTT协议连接与控制智能设备,打造现代科技生活的完美体验
【8月更文挑战第31天】物联网(IoT)技术的发展使智能家居设备成为现代家庭的一部分。通过物联网,家用电器和传感器可以互联互通,实现远程控制和状态监测等功能。本文将探讨如何在Windows Presentation Foundation(WPF)应用中集成物联网技术,通过具体示例代码展示其实现过程。文章首先介绍了MQTT协议及其在智能家居中的应用,并详细描述了使用Wi-Fi连接方式的原因。随后,通过安装Paho MQTT客户端库并创建MQTT客户端实例,演示了如何编写一个简单的WPF应用程序来控制智能灯泡。
136 0
|
4月前
|
物联网 网络性能优化 Python
"掌握MQTT协议,开启物联网通信新篇章——揭秘轻量级消息传输背后的力量!"
【8月更文挑战第21天】MQTT是一种轻量级的消息传输协议,以其低功耗、低带宽的特点在物联网和移动应用领域广泛应用。基于发布/订阅模型,MQTT支持三种服务质量级别,非常适合受限网络环境。本文详细阐述了MQTT的工作原理及特点,并提供了使用Python `paho-mqtt`库实现的发布与订阅示例代码,帮助读者快速掌握MQTT的应用技巧。
93 0
|
4月前
|
安全 网络性能优化
MQTT 客户端 MQTT.fx 使用说明
MQTT 客户端 MQTT.fx 使用说明
378 0