C#实现MQTT over WebSocket

如何在网页端实现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 connectwindow.ws = new wsImpl('ws://localhost:8181/');// when data is comming from the server, this metod is calledws.onmessage = function (evt) {inc.innerHTML += evt.data + '<br/>';};// when the connection is established, this method is calledws.onopen = function () {inc.innerHTML += '.. connection open<br/>';ws.send("SN:12345");};// when the connection is closed, this method is calledws.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.hqwc.cn/news/283555.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UML系统建模专题---1、UML概述和理论

概述 什么是uml Unified Modeling Language 统一建模语言&#xff0c;又称标准建模语言。是用来对软件密集系统进行可视化建模的一种语言&#xff0c; 语言&#xff0c;也就是一个表达思想的符号约定。 uml的发展与版本 建模语言出现在二十世纪70年代&#xff0c;80年代末开…

【unity小技巧】使用三种方式实现瞄准瞄具放大变焦效果

最终效果对比 文章目录 最终效果对比前言第一种办法方法二1. 创建URP环境2. 配置 Universal Render Pipeline Asset3. 这里向我们新建一个无光的ShaderGraph4. 主图配置4. 新建材质&#xff0c;挂载5. 下面是shaderGraph 的连线图6. 新增脚本控制ObjectScreenPosition随着瞄准镜…

C语言之文件操作(下)

C语言之文件操作&#xff08;下&#xff09; 文章目录 C语言之文件操作&#xff08;下&#xff09;1. 文件的顺序读写1.1 文件的顺序读写函数1.1.1 字符输入/输出函数&#xff08;fgetc/fputc&#xff09;1.1.2 ⽂本⾏输⼊/输出函数&#xff08;fgets/fputs&#xff09;1.1.3 格…

MySQL 报错 You can‘t specify target table for update in FROM clause解决办法

You can’t specify target table for update in FROM clause 其含义是&#xff1a;不能在同一表中查询的数据作为同一表的更新数 单独执行复合查询是正常的&#xff0c;如下&#xff1a; 但是当执行子查询删除命令时&#xff0c;报如下错误 DELETE FROM abpusers WHERE Id I…

【Gradle】运行时一直要下载 gradle-8.5-bin.zip

如何解决 Downloading https://services.gradle.org/distributions/gradle-8.5-bin.zip 的问题 文章目录 1. 问题描述2. 解决方法1&#xff09;找到 gradle-wrapper.properties2&#xff09;修改 distributionUrl 对应的值 3. 验证 1. 问题描述 在执行 gradlew 命令的时候&…

频谱论文:面向频谱地图构建的频谱态势生成技术研究

#频谱# [1]李竟铭.面向频谱地图构建的频谱态势生成技术研究.2019.南京航空航天大学,MA thesis.doi:10.27239/d.cnki.gnhhu.2019.000556. &#xff08;南京航空航天大学&#xff09; 频谱地图是对无线电环境的抽象表达&#xff0c;它可以直观、多维度地展现频谱态势信息&…

基于Python实现的一个书法字体风格识别器源码,通过输入图片,识别出图片中的书法字体风格,采用Tkinter实现GUI界面

项目描述 本项目是一个书法字体风格识别器&#xff0c;通过输入图片&#xff0c;识别出图片中的书法字体风格。项目包含以下文件&#xff1a; 0_setting.yaml&#xff1a;配置文件&#xff0c;包含书法字体风格列表、图片调整大小的目标尺寸等设置。1_Xy.py&#xff1a;预处理…

【最新版】在WSL上运行 Linux GUI (图形用户界面)应用(Gnome 文本编辑器、GIMP、Nautilus、VLC、X11 应用)

文章目录 一、 安装WSL0. 先决条件1. 全新安装2. 现有 WSL 安装3. 注意事项 二、运行 Linux GUI 应用1. 更新发行版中的包2. 安装 Gnome 文本编辑器启动 3. 安装 GIMP启动 4. 安装 Nautilus启动 5. 安装 VLC启动 6. 安装 X11 应用 适用于 Linux 的 Windows 子系统 (WSL) 现在支…

深入理解强化学习——马尔可夫决策过程:价值迭代-[价值迭代算法]

分类目录&#xff1a;《深入理解强化学习》总目录 文章《深入理解强化学习——马尔可夫决策过程&#xff1a;价值迭代-[最优性原理]》和文章《深入理解强化学习——马尔可夫决策过程&#xff1a;价值迭代-[确认性价值迭代]》介绍了价值迭代的基础知识&#xff0c;本文将介绍价值…

在公司内网开发的时候如何和互联网第三方平台环境联调之内网穿透

一、背景 一般情况下&#xff0c;不会出现所处不在同一网段进行后端服务联调&#xff0c;但是当遇到和第三方平台对接之时&#xff0c;这个时候如果你自身处在公司内部局域网的范畴下&#xff0c;那么一般都是会被保护的&#xff0c;也就是说外网无法访问你的ip。这个时候就需…

【赠书第11期】Unity 3D游戏开发

文章目录 前言 1 Unity 3D简介 2 Unity 3D基本概念 2.1 场景&#xff08;Scene&#xff09; 2.2 游戏对象&#xff08;Game Object&#xff09; 2.3 组件&#xff08;Component&#xff09; 2.4 资源&#xff08;Asset&#xff09; 3 Unity 3D重要组件 3.1 物理引擎 …

百分比组件 - elementui改动

<el-slider v-model"value2" style"width: 87%;position: absolute;bottom: 9px;" disabled :show-tooltip"false"></el-slider>value2: 0,// 百分比条 ::v-deep .el-slider__runway.disabled .el-slider__bar {background-color: #…