我的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版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
5月前
|
数据采集 传感器 监控
Modbus 与 MQTT 协议兼容:MyEMS 的泛在能源数据采集技术实现
MyEMS深度融合Modbus与MQTT协议,破解能源数据采集中协议碎片化、网络异构、数据孤岛等难题。通过Modbus接入95%以上工业设备,实现现场数据精准“拉取”;依托MQTT构建高效物联网传输通道,支持多源数据主动“推送”与云端集成。边缘侧采集规整,中心侧汇聚分析,形成统一、可靠、低延迟的数据流。该架构兼具高兼容性、强扩展性与低运维成本,广泛应用于工业园区、商业楼宇及集团型企业,支撑实时监控、AI分析与跨系统融合,打造泛在互联的能源数据底座,助力企业实现全面智慧能源管理。
410 6
|
数据可视化 关系型数据库 MySQL
嵌入式C++、STM32、MySQL、GPS、InfluxDB和MQTT协议数据可视化
通过本文的介绍,我们详细讲解了如何结合嵌入式C++、STM32、MySQL、GPS、InfluxDB和MQTT协议,实现数据的采集、传输、存储和可视化。这种架构在物联网项目中非常常见,可以有效地处理和展示实时数据。希望本文能帮助您更好地理解和应用这些技术,构建高效、可靠的数据处理和可视化系统。
717 82
|
8月前
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
1660 0
|
11月前
|
消息中间件 存储 Apache
恭喜 Apache RocketMQ 荣获 2024 开源创新榜单“年度开源项目”
恭喜 Apache RocketMQ 荣获 2024 开源创新榜单“年度开源项目”
280 1
|
7月前
|
消息中间件 数据管理 Serverless
阿里云消息队列 Apache RocketMQ 创新论文入选顶会 ACM FSE 2025
阿里云消息团队基于 Apache RocketMQ 构建 Serverless 消息系统,适配多种主流消息协议(如 RabbitMQ、MQTT 和 Kafka),成功解决了传统中间件在可伸缩性、成本及元数据管理等方面的难题,并据此实现 ApsaraMQ 全系列产品 Serverless 化,助力企业提效降本。
|
5月前
|
消息中间件 Java Kafka
消息队列比较:Spring 微服务中的 Kafka 与 RabbitMQ
本文深入解析了 Kafka 和 RabbitMQ 两大主流消息队列在 Spring 微服务中的应用与对比。内容涵盖消息队列的基本原理、Kafka 与 RabbitMQ 的核心概念、各自优势及典型用例,并结合 Spring 生态的集成方式,帮助开发者根据实际需求选择合适的消息中间件,提升系统解耦、可扩展性与可靠性。
371 1
消息队列比较:Spring 微服务中的 Kafka 与 RabbitMQ
|
消息中间件 JSON Java
开发者如何使用轻量消息队列MNS
【10月更文挑战第19天】开发者如何使用轻量消息队列MNS
957 88
|
消息中间件 安全 Java
云消息队列RabbitMQ实践解决方案评测
一文带你详细了解云消息队列RabbitMQ实践的解决方案优与劣
444 88
|
消息中间件 存储 Kafka
MQ 消息队列核心原理,12 条最全面总结!
本文总结了消息队列的12个核心原理,涵盖消息顺序性、ACK机制、持久化及高可用性等内容。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
消息中间件
解决方案 | 云消息队列RabbitMQ实践获奖名单公布!
云消息队列RabbitMQ实践获奖名单公布!
224 1