C#实现MQTT over WebSocket

news2024/11/27 6:18:59

如何在网页端实现MQTT消息的发布和订阅?

  • 实现MQTT功能,可以发布和订阅主题
  • 通过WebSocket协议将MQTT消息转发给对应的网页端

带着这个实现思路,采用C#控制台程序实现MQTT服务端功能,web端可以直接使用websocket插件与服务端双向通讯。

  1. 新建C#控制台程序,.net framework框架版本4.5.2
  2. 引用Fleck框架,版本1.2.0
  3. 引用MQTTnet框架,版本4.3.1.873

1、WebSocket功能实现

socketDic 字典key值记录每个客户端,value记录每个客户端对应的SN,代表设备的序列号;

每当有网页端客户端连接的时候,自动将客户端套接字加入字典中;

每当网页关闭,服务端自动断开客户端套接字连接,并从缓存字典中移除此客户端套接字;

当网页端客户端套接字发送包含SN:开头的字符,表示网页端发送了设备的SN,服务端接收此消息,并解析设备SN,并与对应的客户端套接字绑定对应关系,在缓存字典中维护对应关系。

class Server
{
    static Dictionary<IWebSocketConnection, string> socketDic = new Dictionary<IWebSocketConnection, string>();
        static void Main()
        {
            FleckLog.Level = LogLevel.Debug;
            var server = new WebSocketServer("ws://0.0.0.0:8181");
            //var socketDic = new Dictionary<IWebSocketConnection, string>();
            server.Start(socket =>
                {
                    socket.OnOpen = () =>
                        {
                            Console.WriteLine("Open!");
                            socketDic.Add(socket, null);
                        };
                    socket.OnClose = () =>
                        {
                            Console.WriteLine("Close!");
                            socketDic.Remove(socket);
                        };
                    socket.OnMessage = message =>
                        {
                            if (message.Contains("SN:") && socketDic.ContainsKey(socket))
                            {
                                socketDic[socket] = message.Replace("SN:", "");
                            }
                        };
                });
            Client();
            var input = Console.ReadLine();
            while (input != "exit")
            {
                foreach (var socket in socketDic.ToList())
                {
                    socket.Key.Send(input);
                }
                input = Console.ReadLine();
            }

        }
}

2、MQTT功能实现

MQTT服务器采用EMQX公共服务器测试,服务器域名:broker.emqx.io,端口:1883,用户名:emqx_test,密码:emqx_test

订阅主题名:123、12345

MQTT接收消息事件ApplicationMessageReceivedAsync,判断消息主题与缓存字典中的套接字是否对应,如消息主题与缓存字典SN存在包含关系,则认为此消息与网页端套接字存在关联关系,则将消息推送给此套接字。

具体实现代码:

static IMqttClient client;
        public static async void Client()
        {
            try
            {
                client = new MqttFactory().CreateMqttClient() as MqttClient;
                var build = new MqttClientOptionsBuilder()
                    .WithClientId(Guid.NewGuid().ToString().Replace("-", "").ToUpper())
                    .WithCredentials("emqx_test", "emqx_test")
                    .WithTcpServer("broker.emqx.io", 1883)
                    .WithCleanSession(true)
                    .WithKeepAlivePeriod(TimeSpan.FromSeconds(100.5));
                client.ConnectedAsync += _mqttClient_ConnectedAsync;
                await client.ConnectAsync(build.Build());
                
                client.DisconnectedAsync += _mqttClient_DisconnectedAsync;
                client.ApplicationMessageReceivedAsync += _mqttClient_ApplicationMessageReceivedAsync;
 
                await client.SubscribeAsync(
                    new MqttClientSubscribeOptions
                    {
                        TopicFilters = new List<MqttTopicFilter> {new MqttTopicFilter() //订阅消息对象
                        {
                            Topic = "123",  //订阅消息主题
                            QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce  //消息类型
                        },new MqttTopicFilter() //订阅消息对象
                        {
                            Topic = "12345",  //订阅消息主题
                            QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce  //消息类型
                        }
                    }
                    });
            }
            catch (Exception e)
            {
                Console.WriteLine($"连接失败");
            }
        }

        private static Task _mqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            var msg = arg.ApplicationMessage.ConvertPayloadToString();
            foreach (var item in socketDic)
            {
                if (item.Value!=null && arg.ApplicationMessage.Topic.Contains(item.Value))
                {
                    item.Key.Send($"hello {item.Value},{msg}");
                }
            }
            Console.WriteLine(arg.ApplicationMessage.ConvertPayloadToString());
            return Task.FromResult("");
        }

        private static Task _mqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            Console.WriteLine($"客户端“{client.Options.ClientId}”已断开MQTT服务器!");
            return Task.FromResult("");
        }

        private static Task _mqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            Console.WriteLine($"客户端“{client.Options.ClientId}”已连接MQTT服务器!");
            return Task.FromResult("");
        }

3、网页端实现

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <title>websocket client</title>
    <script type="text/javascript">
        var start = function () {
            var inc = document.getElementById('incomming');
            var wsImpl = window.WebSocket || window.MozWebSocket;
            var form = document.getElementById('sendForm');
            var input = document.getElementById('sendText');
            
            inc.innerHTML += "connecting to server ..<br/>";

            // create a new websocket and connect
            window.ws = new wsImpl('ws://localhost:8181/');

            // when data is comming from the server, this metod is called
            ws.onmessage = function (evt) {
                inc.innerHTML += evt.data + '<br/>';
            };

            // when the connection is established, this method is called
            ws.onopen = function () {
                inc.innerHTML += '.. connection open<br/>';
                ws.send("SN:12345");
            };

            // when the connection is closed, this method is called
            ws.onclose = function () {
                inc.innerHTML += '.. connection closed<br/>';
            }

			//form.addEventListener('submit', function(e){
			//	e.preventDefault();
			//	var val = input.value;
			//	ws.send(val);
			//	input.value = "";
			//}); 
        }
        window.onload = start;
    </script>
</head>
<body>
	<form id="sendForm">
		<input id="sendText" placeholder="Text to send" />
	</form>
    <pre id="incomming"></pre>
</body>
</html>

4、测试

启动WebSocket服务器控制台应用程序;

运行MQTT.fx工具,新建连接

给12345主题发布消息,

观察网页端是否收到消息,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1318797.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在金属/绝缘体/p-GaN栅极高电子迁移率晶体管中同时实现大的栅压摆幅和增强的阈值电压稳定性

标题&#xff1a;Simultaneously Achieving Large Gate Swing and Enhanced Threshold Voltage Stability in Metal/Insulator/p-GaN Gate HEMT (IEDM2023) 摘要 摘要&#xff1a;对于增强型GaN功率晶体管的发展&#xff0c;栅压摆幅和阈值电压稳定性通常是互相排斥的。本文展…

Web前端-HTML(简介)

文章目录 1. HTML1.1概述1.2 HTML骨架标签1.3 HTML元素标签及分类1.4 HTML标签关系 2. 代码开发工具&#xff08;书写代码&#xff09;3. 文档类型<!DOCTYPE>4. 页面语言lang5. 字符集 1. HTML 1.1概述 HTML 指的是超文本标记语言 (Hyper Text Markup Language)&#x…

串口通信(6)-C#串口通信Modbus协议完整实例

本文讲解C#基于ModbusRTU协议串口通信完整实例。 前言 关于modbus的协议从上一篇中有介绍,本篇不在阐述。 串口通信(5)-C#串口通信数据接收不完整解决方案 创建实例 添加控件和事件等 参考界面文件 namespace ModbusRTUDemo {partial class MainForm{/// <summary>…

踩坑记录:java连接ssh的问题

目录 概述一、第一个问题解决 二、第二个问题分析解决 三、第三个问题分析解决 第四个问题解决 概述 手里有个CS架构的老系统&#xff0c;服务端要用SSH的方式传文件。没想到写了两天&#xff01;遇到一堆问题&#xff0c;于是记录下。&#xff08;老系统真恶心啊&#xff01;…

msvcp140.dll丢失怎样修复?全面分析msvcp140.dll的修复方法

在执行特定程序时&#xff0c;有可能遭遇msvcp140.dll文件遗失的困扰&#xff0c;此时该如何处理呢&#xff1f;此次将为您讲述面临此类问题的有效解决方案&#xff0c;涉及到多种修复方法&#xff0c;其中包括利用DLL修复工具进行操作。您可依据个人需求选择相应的修复方式&am…

学习Java第70天,过滤器Filter简介

过滤器概述 Filter,即过滤器,是JAVAEE技术规范之一,作用目标资源的请求进行过滤的一套技术规范,是Java Web项目中最为实用的技术之一 Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口 Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequest和…

用GitBook制作自己的网页版电子书

用GitBook制作自己的网页版电子书 前言 几年前阅读过其他人用GitBook创建的文档&#xff0c;可以直接在浏览器中打开&#xff0c;页面干净整洁&#xff0c;非常清爽&#xff0c;至今印象深刻。 GitBook非常适合用来为个人或团队制作文档&#xff0c;对于我这种偶尔写博客的人…

Vue 实现一个弹出框,允许用户输入信息,并在确认时将输入的信息进行输出到控制台

父组件用来点击按钮弹出弹出框 <!--ParentComponent.vue--> <template><div><button click"showPopupV">点我会有个弹出框&#xff01;&#xff01;&#xff01;</button><PopupComponent v-if"showPopup" :data"p…

java-sec-code中重定向

重定向 状态码3xx 存在问题的代码段 GetMapping("/redirect") public String redirect(RequestParam("url") String url) {return "redirect:" url; }用户访问/redirect路径时&#xff0c;redirect方法会获取web请求中的url参数内容&#xff0…

leetcode算法题:省份数量

leetcode算法题547 链接&#xff1a;https://leetcode.cn/problems/number-of-provinces 题目 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a 与城市 c 间…

EasyExcel 简单导入

前边写过使用easyexcel进行简单、多sheet页的导出。今天周日利用空闲写一下对应简单的导入。 重点&#xff1a;springboot、easyExcel、桥接模式&#xff1b; 说明&#xff1a;本次使用实体类student&#xff1a;属性看前边章节内容&#xff1b; 1、公共导入service public …

yarn历史日志_配置文件

yarn历史日志yarn配置文件yarn执行任务 1.3. YARN的历史日志 1.3.1. 历史日志概述 我们在YARN运行MapReduce的程序的时候&#xff0c;任务会被分发到不同的节点&#xff0c;在不同的Container内去执行。如果一个程序执行结束后&#xff0c;我们想去查看这个程序的运行状态呢…

GitHub入门介绍:从小白到大佬的旅程

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

动态规划学习——通符串匹配,正则表达式

目录 ​编辑 一&#xff0c;通符串匹配 1.题目 2.题目接口 3&#xff0c;解题思路及其代码 二&#xff0c;正则表达 1.题目 2.题目接口 3.解题思路及其代码 三&#xff0c;交错字符串 1.题目 2&#xff0c;题目接口 3.解题思路及其代码 一&#xff0c;通符串匹配 1…

docker使用详解

介绍 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。 Docker基于轻量级虚拟化技术&#xff0c;整个项目基于Go语言开…

2024最新FL Studio21.2MAC电脑版中文版下载安装步骤教程

FL Studio 简称FL&#xff0c;全称Fruity Loops Studio&#xff0c;因此国人习惯叫它"水果"。目前最新版本是FL Studio21.1.1.3750版本&#xff0c;它让你的计算机就像是全功能的录音室&#xff0c;大混音盘&#xff0c;非常先进的制作工具&#xff0c;让你的音乐突破…

MNIST内置手写数字数据集的实现

torchvision库 torchivision库是PyTorch中用来处理图像和视频的一个辅助库&#xff0c;接下来我们就会使用torchvision库加载内置的数据集进行分类模型的演示 为了统一数据加载和处理代码&#xff0c;PyTorch提供了两个类用于处理数据加载&#xff0c;他们分别是torch.utils.…

Typescript中Omit数据类型的理解

在 TypeScript 中&#xff0c;Omit 是一个内置的工具类型&#xff0c;它用于从对象类型中排除指定的属性&#xff0c;并返回剩余的属性。 Omit 的语法如下所示&#xff1a; type Omit<T, K> Pick<T, Exclude<keyof T, K>>;其中&#xff0c;T 表示原始类型…

Leetcode刷题笔记题解(C++):224. 基本计算器

思路&#xff1a; step 1&#xff1a;使用栈辅助处理优先级&#xff0c;默认符号为加号。 step 2&#xff1a;遍历字符串&#xff0c;遇到数字&#xff0c;则将连续的数字字符部分转化为int型数字。 step 3&#xff1a;遇到左括号&#xff0c;则将括号后的部分送入递归&#x…

面向对象三大特征——继承

目录 1. 概述 2. 继承的限制 2.1 单继承 2.2 访问修饰符 2.3 . final 3. 重写 4. super 4.1super的作用 4.2访问父类的成员和被重写方法 4.3调用父类的构造器 1. 概述 多个类中存在相同属性和行为时&#xff0c;将这些内容抽取到单独一个类中&#xff0c;那么就无需在…