基于EMQ2.0的学习和使用简单分享

简介: EMQ介绍   EMQ (Erlang/Enterprise/Elastic MQTT Broker) 是基于 Erlang/OTP 平台开发的开源物联网 MQTT 消息服务器。Erlang/OTP 是出色的软实时(Soft-Realtime)、低延时(Low-Latency)、分布式(Distributed) 的语言平台。

EMQ介绍

  EMQ (Erlang/Enterprise/Elastic MQTT Broker) 是基于 Erlang/OTP 平台开发的开源物联网 MQTT 消息服务器。Erlang/OTP 是出色的软实时(Soft-Realtime)、低延时(Low-Latency)、分布式(Distributed) 的语言平台。MQTT 是轻量的(Lightweight)、发布订阅模式(PubSub) 的物联网(IoT)消息协议。
 
订阅(pub)/发布(sub)模式
 
消息队列中的广播(fanout)模式
 
 
轻量化:docker镜像都才88.4MB
 
 

一些关于常用EMQTT的快速链接:

官网API地址: http://www.emqtt.com/docs/v2/
开源项目地址: https://github.com/emqtt
MQTT介绍和场景: https://www.mqtt.com/
 

安装过程

假如你的centos上已经安装了Docker,并pull了devicexx/emqttd这个镜像,输入如下命令
docker run -dit --name=sample_emqtt --restart=always -p 18083:18083 -p 1883:1883 -p 8083:8083 -p 8883:8883 998429a869e8

 

 
确保映射如下几个端口
1883、8083、8883:这三个是基于EMQTT传输通讯的端口
18083:这个是EMQTT Web控制台的端口
 
我的虚拟机IP网段是153.132,直接输入http://192.168.153.132:18083进入Web控制台,默认用户名和密码是admin, public
至此EMQTT已经顺利安装完成。
 

在NET Core中使用EMQ:

emqtt官网没有提供.net的客户端,在nuget和github上找到了实现了MQTT协议的公共组件。
 
 

MQTTnet Client的几个主要事件:

ApplicationMessageReceived:MQTTnet中主要方法事件,当接收到消息的时候,该事件触发。包含Topic,Payload,Qos,Retain主要成员。
Connected:客户端成功连接时触发。
Disconnected:客户端丢失连接时触发。
 

创建一个发布者

先创建一个发布者Publisher的配置类,代码简单:
    public static class PublisherConfig
    {
        /// <summary>
        /// 创建mqtt的客户端接口实例
        /// </summary>
        public static readonly IMqttClient Client = new MqttFactory().CreateMqttClient();

        /// <summary>
        /// 创建mqtt配置选项
        /// </summary>
        public static readonly MqttClientOptions ClientOptions = new MqttClientOptions
        {
            // 通道选项
            ChannelOptions = new MqttClientTcpOptions
            {
                Server = "192.168.153.132"
            },
            
            /*
             * 客户端ID
             * 在MQTTnet框架中,当ClientId未赋值,将使用默认的GUID生成默认的ClientId
             */
            ClientId = "Client_publisher",
            
            // 客户端认证
            Credentials = new MqttClientCredentials
            {
                Username = "clientUser_01",
                Password = "123123"
            }
        };

        public const string Topic = MQTT_Common.Config.Topic.Name;
    }

 

 为了测试方便,创建了一个全局固定的Topic名称

    public static class Topic
    {
        public const string Name = "/WorldTopic";
    }

 

再创建一个发布者Publisher,代码简单

    public static class Publisher
    {
        private static readonly IMqttClient Client = PublisherConfig.Client;
        private static readonly MqttClientOptions ClientOptions = PublisherConfig.ClientOptions;
        private static readonly string Topic = PublisherConfig.Topic;

        public static void RunAsync()
        {
            try
            {
                Console.WriteLine("publisher is running");
                CreateConnection();
                LoopInput().Wait();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }
        
        private static void CreateConnection()
        {
            CommonEventHandler.EventHandler(Client, ClientOptions);
            CommonEventHandler.TryConnectionAsync(Client, ClientOptions);
        }
        
        private static async Task LoopInput()
        {
            while (true)
            {
                await Client.SubscribeAsync("/World");

                Console.WriteLine("输入消息数据:");
                var r = Console.ReadLine();

                var applicationMessage = new MqttApplicationMessageBuilder()
                    .WithTopic(Topic)         // 设置主题
                    .WithPayload(r)           // 设置载荷(消息内容)
                    .WithAtLeastOnceQoS()     // 设置质量
                    .WithRetainFlag(false)    // 设置持久化
                    .Build();

                await Client.PublishAsync(applicationMessage);
            }   
        }

 

 创建一个或多个订阅者

    public static class SubscriberConfig01
    {
        public static readonly IMqttClient Client = new MqttFactory().CreateMqttClient();

        public static readonly MqttClientOptions ClientOptions = new MqttClientOptions
        {
            ChannelOptions = new MqttClientTcpOptions
            {
                Server = "192.168.153.132"
            },
            // 唯一需要修改的Client唯一ID
            ClientId = "Client_01",
            Credentials = new MqttClientCredentials
            {
                // 用户可用多个,也可不启用客户端验证
                Username = "clientUser_02",
                Password = "123123"
            }
        };

        public const string Topic = MQTT_Common.Config.Topic.Name;
    }

 

MQTTnet中所有连接端都是Client,所以唯一的变化是ClientID这个值,可使用系统GUID自动生成,也可以使用不同的Client限定名。

    public static class Subscriber01
    {
        private static readonly IMqttClient Client = SubscriberConfig01.Client;
        private static readonly MqttClientOptions ClientOptions = SubscriberConfig01.ClientOptions;
        private static readonly string Topic = SubscriberConfig01.Topic;

        public static async Task RunAsync()
        {
            try
            {
                Console.WriteLine("subscriber 1 is running");
                CreateConnection();
                // 注册/订阅Topic主题
                await Client.SubscribeAsync(Topic);
                Console.ReadKey();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }

        private static void CreateConnection()
        {
            CommonEventHandler.EventHandler(Client, ClientOptions);
            CommonEventHandler.TryConnectionAsync(Client, ClientOptions);
        }
    }

 

公共函数CommonEventHandler,用于公共事件处理和连接尝试

    public static class CommonEventHandler
    {
        /// <summary>
        /// 添加Client相关事件处理函数
        /// </summary>
        /// <param name="client">IMqttClient客户端</param>
        /// <param name="clientOptions">MqttClientOptions配置选项</param>
        /// <param name="subscribe">主题Topic名称</param>
        public static void EventHandler(IMqttClient client, MqttClientOptions clientOptions, string subscribe = "#")
        {
            client.ApplicationMessageReceived += (s, e) =>
            {
                Console.WriteLine("### 收到程序消息 ###");
                Console.WriteLine($"+ [主题]Topic = {e.ApplicationMessage.Topic}");
                Console.WriteLine($"+ [载荷]Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
                Console.WriteLine($"+ [质量]QoS = {e.ApplicationMessage.QualityOfServiceLevel}");
                Console.WriteLine($"+ [持久]Retain = {e.ApplicationMessage.Retain}");
                Console.WriteLine();
            };

            client.Connected += async (s, e) =>
            {
                Console.WriteLine("### 成功连接MQTT ###");
                if (!subscribe.Equals("#")) return;
                await client.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
                Console.WriteLine($"### 成功订阅主题[{subscribe}] ###");
            };

            client.Disconnected += async (s, e) =>
            {
                Console.WriteLine("### 连接丢失 ###");
                await Task.Delay(TimeSpan.FromSeconds(5));
                try
                {
                    await client.ConnectAsync(clientOptions);
                }
                catch
                {
                    Console.WriteLine("### 连接错误 ###");
                }
            };
        }
        
        /// <summary>
        /// 尝试Client连接到EMQTT
        /// </summary>
        /// <param name="client">IMqttClient客户端</param>
        /// <param name="clientOptions">MqttClientOptions配置选项</param>
        public static void TryConnectionAsync(IMqttClient client, MqttClientOptions clientOptions)
        {
            try
            {
                client.ConnectAsync(clientOptions).Wait();
            }
            catch (Exception exception)
            {
                Console.WriteLine("### 连接错误 ###" + Environment.NewLine + exception);
            }
        }
    }

 

配置三个客户端,一个作为发布者,两个作为订阅者,通过发布者输入任意数据,运行结果如下:

其中发布者客户端会收到一个Retain=True的消息,是因为之前有发布过一条持久化的消息,该消息已经存储在EMQTT中,每次启动均会主动向订阅过"/World"的订阅者再次推送该条持久化的消息。
根据生产消费的机制,此处消息理当已经被消费和清除,但不清楚为何EMQ仍然存在。
 

总结

本篇简单介绍使用EMQTT的PubSub模式,并使用MQTTnet客户端连接并订阅和发布消息内容。
 
 
相关实践学习
快速体验阿里云云消息队列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
相关文章
|
2天前
|
云安全 安全 网络安全
|
2天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
1695 1
|
9天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
1444 31
|
3天前
|
安全 应用服务中间件 Go
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
PHP2Shell 双 RCE 已遭在野利用:WordPress、Drupal 全在射程内,nginx 其实另有洞。拆成因与修复顺序
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
|
13天前
|
存储 人工智能 安全
千问办公官网入口网页版登录:qwenwork.cn 注册送2000积分、登录送100积分
阿里云千问办公(QwenWork)是AI智能工作平台,支持一句话生成PPT、表格、网页、视频及数据分析。个人免费版送2000积分+每日登录赠100分,含1GB存储、5个发布页;企业版198元/席/月起。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务
|
10天前
|
安全 Linux 芯片
【万字长文】Ollama下载、安装、配置、使用保姆级教程(2026最新图解)
Ollama 是一款免费开源的本地大模型运行工具,支持 DeepSeek、Qwen 等主流模型,一条命令即可下载运行。2026 最新版 v0.35.1 官方安装包(1.47GB)已提供国内直连下载,纯本地、离线可用、无广告、无隐私泄露风险。
945 2
|
8天前
|
人工智能 开发者
Qoder CN 大使计划正式开启|无限创造,等你一起
全年免费积分、优先内测、活动支持与更多共创机会,邀请用 Qoder 把想法变成现实的你。
644 6
|
1月前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
10154 33
|
8天前
|
存储 弹性计算 双11
2026阿里云双11优惠活动全解析:服务器收费价格、优惠券与代理渠道购买指南
本文由重庆典名科技(阿里云旗舰级代理、钉钉六星级服务商)撰写,详解2026双11阿里云服务器真省钱逻辑:38/99/199元三档锚点价不降,核心优惠在满减券叠加与授权代理渠道折扣(官网价再降15%–35%),并强调“续费同价”锁定长期成本。
644 0

热门文章

最新文章