WebSocket通讯实现C++/C#

目录

0 任务概述

1 不同的与服务器进行持续通讯的方式对比

2 C++参考链接:

3 C#实现

服务端代码:

客户端代码:

4 代码集成

5 试验过程

1> 开启mqtt服务器

 2> 启动WebSocket_Server

 3> 启动WebSocket_Client

 4> 服务端信息

0 任务概述

架构形式:

1> Hololens*2   PC  三者之间用mqtt进行通讯;

2> 在PC上做开发,接收来自2个hololens的mqtt的消息,将其转发到websocket服务器(手持终端);

3> PC上MQTT+WEBSOCKET(暂定直接转发)。

目标:假定有一条来自mqtt的信息,将这条信息转发至WebSocket服务器端。

1 不同的与服务器进行持续通讯的方式对比

>>>>>>>>>>>>传统轮询长轮询服务器发送事件WebSocket
浏览器支持几乎所有现代浏览器几乎所有现代浏览器Firefox 6+ Chrome 6+ Safari 5+ Opera 10.1+IE 10+ Edge Firefox 4+ Chrome 4+ Safari 5+ Opera 11.5+
服务器负载较少的CPU资源,较多的内存资源和带宽资源与传统轮询相似,但是占用带宽较少与长轮询相似,除非每次发送请求后服务器不需要断开连接无需循环等待(长轮询),CPU和内存资源不以客户端数量衡量,而是以客户端事件数衡量。四种方式里性能最佳。
客户端负载占用较多的内存资源与请求数。与传统轮询相似。浏览器中原生实现,占用资源很小。同Server-Sent Event。
延迟非实时,延迟取决于请求间隔。同传统轮询。非实时,默认3秒延迟,延迟可自定义。实时。
实现复杂度非常简单。需要服务器配合,客户端实现非常简单。需要服务器配合,而客户端实现甚至比前两种更简单。需要Socket程序实现和额外端口,客户端实现简单。

websocket详解

http - WebSocket 详解 - 不挑食的程序员 - SegmentFault 思否

2 C++参考链接:

zaphoyd/websocketpp: C++ websocket client/server library (github.com)

在电脑上试跑examples/echo_client和echo_server两个cpp文件;其他的文件都尝试了,但是跑不成功。

结果:成功连接,但是无法将自定义的消息发送出来。

服务器截图:

客户端截图:

在另外一篇博文中已用C#实现mqtt信息接收,因此考虑改为C#进行开发。

链接:https://mp.csdn.net/mp_blog/creation/editor/new/129476972

3 C#实现

服务端代码:

using System;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace WebSocketServer
{class WebSocket_Server{#region 避免重复显示static string lastMsg;static int lastCount;static int dupMsgCount = 0;static bool isFirst = true;#endregionstatic async Task Main(string[] args){string localIp = "127.0.0.1"; // 默认本地IP地址string port = ":8080";foreach (IPAddress ip in Dns.GetHostAddresses(Dns.GetHostName())){if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork){localIp = ip.ToString();break;}}Console.WriteLine("Server started at: " + localIp + port);HttpListener listener = new HttpListener();listener.Prefixes.Add("http://localhost:8080/");listener.Start();while (true){HttpListenerContext context = await listener.GetContextAsync();if (context.Request.IsWebSocketRequest){WebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null);WebSocket webSocket = webSocketContext.WebSocket;Console.WriteLine("Client connected: " + context.Request.RemoteEndPoint.ToString());await Echo(webSocket, context);}else{context.Response.StatusCode = 400;context.Response.Close();}}}private static async Task Echo(WebSocket webSocket, HttpListenerContext context){byte[] buffer = new byte[1024];while (webSocket.State == WebSocketState.Open)try{WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);if (result.MessageType == WebSocketMessageType.Text){string message = Encoding.UTF8.GetString(buffer, 0, result.Count);if (isFirst){lastMsg = message;                    //将第一次进入函数体的消息初始化为message的内容lastCount = 1;isFirst = false;}//Console.WriteLine("Received: message - " + message);//如果收到的信息重复,则不显示if (string.Equals(lastMsg, message)){dupMsgCount++;}else if ((dupMsgCount != 1) && (dupMsgCount != 0)){lastCount = dupMsgCount;//Console.WriteLine("Received: response - " + response + " " + dupMsgCount + " times. ");Console.WriteLine("Received: message - " + lastMsg + " " + lastCount + " times. ");dupMsgCount = 1;}lastMsg = message;byte[] responseBuffer = Encoding.UTF8.GetBytes("Echo: " + message);//将收到的数据回响给客户端await webSocket.SendAsync(new ArraySegment<byte>(responseBuffer), WebSocketMessageType.Text, true, CancellationToken.None);}else if (result.MessageType == WebSocketMessageType.Close){Console.WriteLine("Client disconnected: " + context.Request.RemoteEndPoint.ToString());await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);}}catch (Exception ex){Console.WriteLine("Error: " + ex.Message);}}}
}

客户端代码:

using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace WebSocketClient
{class WebSocket_Client{static async Task Main(string[] args){ClientWebSocket webSocket = new ClientWebSocket();string targetURI = "ws://localhost:8080";await webSocket.ConnectAsync(new Uri(targetURI), CancellationToken.None);Console.WriteLine("Connected to server at: " + targetURI);byte[] buffer;string message;while (true){Console.Write("Enter a message (type 'exit' to quit): ");message = Console.ReadLine();if (message.ToLower() == "exit"){break;}buffer = Encoding.UTF8.GetBytes(message);await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);buffer = new byte[1024];WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);string response = Encoding.UTF8.GetString(buffer, 0, result.Count);Console.WriteLine("Received: " + response);}// Send a close message to the server before closing the connectionawait webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);}}
}

4 代码集成

MQTT+WebSocket客户端

using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
using System.IO;namespace csharpMQTT
{class CsharpMQTT_Com{static string _msg;#region 避免重复显示static string lastMsg;static int lastCount;static int dupMsgCount = 0;static bool isFirst = true;#endregion//MQTT部分static MqttClient ConnectMQTT(string broker, int port, string clientId, string username, string password){MqttClient client = new MqttClient(broker, port, false, MqttSslProtocols.None, null, null);client.Connect(clientId, username, password);if (client.IsConnected){Console.WriteLine("Connected to MQTT Broker. Client Id: " + clientId.ToString());}else{Console.WriteLine("Failed to connect");}return client;}static async Task Publish(MqttClient client, string topic){int msg_count = 0;//自定义消息的内容while (true){//System.Threading.Thread.Sleep(1 * 1000);await Task.Delay(TimeSpan.FromSeconds(1));string msg = "messages: " + msg_count.ToString();client.Publish(topic, System.Text.Encoding.UTF8.GetBytes(msg));//将msg通过话题topic发布Console.WriteLine("Send `{0}` to topic `{1}`", msg, topic);msg_count++;_msg = msg;_ = WebSocketClient_Main();}}static void Subscribe(MqttClient client, string topic){client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;//用于将clientMqttMsgPublishReceived方法添加到对象MqttMsgPublishReceived的事件中。当客户端接收到来自订阅主题的消息时,将调用clientMqttMsgPublishReceived方法。client.Subscribe(new string[] { topic }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE });}static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e){//sender是事件的发送者,即MqttClient对象,e是事件参数,即MqttMsgPublishEventArgs对象。//MqttMsgPublishEventArgs对象包含有关消息的信息:主题、内容、是否重复、质量等级、是否应被保留。string payload = System.Text.Encoding.Default.GetString(e.Message);Console.WriteLine("Received `{0}` from `{1}` topic", payload, e.Topic.ToString());}static async Task Main(){try{string broker = "broker.emqx.io";//默认的云端服务器地址//string broker = "115.156.168.35"; //本地服务器ipint port = 1883;string topic = "Csharp/mqtt";string clientId = Guid.NewGuid().ToString();//生成全局唯一标识符,用于标识客户端ID地址string username = "emqx";string password = "public";MqttClient client = ConnectMQTT(broker, port, clientId, username, password);Subscribe(client, topic);//异步方法,它不会阻塞当前线程。相反,它会返回一个Task对象,表示指定的时间过去后,操作将完成。在等待这个Task对象完成的过程中,线程可以执行其他操作。这使得程序更加响应,因为用户可以与程序进行交互,而不必等待Task.Delay返回。var cancellationTokenSource = new CancellationTokenSource();var publishTask = Task.Run(() => Publish(client, topic), cancellationTokenSource.Token);await publishTask;//Publish(client, topic);}catch (Exception ex){Console.WriteLine("An error occurred: " + ex.Message);}}//WebSocket_Client部分static async Task WebSocketClient_Main(){//连接WebSocket服务器ClientWebSocket webSocket = new ClientWebSocket();string targetURI = "ws://localhost:8080";await webSocket.ConnectAsync(new Uri(targetURI), CancellationToken.None);Console.WriteLine("Connected to server at: " + targetURI);//发送和接收消息byte[] buffer;string message;while (true){#region 注释的是原先手动输入信息内容的代码//Console.Write("Enter a message (type 'exit' to quit): ");//message = Console.ReadLine();//if (message.ToLower() == "exit")//{//    break;//}#endregionmessage = _msg;//将消息替换为mqtt处的消息if (isFirst) {lastMsg = message;                    //将第一次进入函数体的消息初始化为message的内容lastCount = 1;isFirst = false;                                      }buffer = Encoding.UTF8.GetBytes(message);await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);buffer = new byte[1024];WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);string response = Encoding.UTF8.GetString(buffer, 0, result.Count);//将从服务器端收到的数据存储//如果收到的信息重复,则不显示if (string.Equals(lastMsg, message)){dupMsgCount++;}else if ((dupMsgCount != 1) && (dupMsgCount != 0)){lastCount = dupMsgCount;//Console.WriteLine("Received: response - " + response + " " + dupMsgCount + " times. ");Console.WriteLine("Received: response - " + lastMsg + " " + lastCount + " times. ");//记录数据改变时,实际上已经是下一组数据了;所以要记录改变前的数据和次数,对外输出。dupMsgCount = 1;}lastMsg = message;}//关闭WebSocket连接await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);}}
}

5 试验过程

1> 开启mqtt服务器

20230523下载emqx-5.0.25-windows-amd64.zip按照上述方式启动会提示路径有问题。如下图

没有找到解决方法,已改用emqx-4.4.18-otp24.3.4.6-windows-amd64。

进入bin目录下运行DOS窗口,输入emqx start,4.x版本运行成功无提示(5.x版本会有两行代码),任务管理器中进程多一项Erlang,如下。即为成功。

 2> 启动WebSocket_Server

等待客户端连接界面:

 3> 启动WebSocket_Client

客户端启动并连接成功:

 4> 服务端信息

 连接成功后服务端界面

客户端意外退出,服务器也不会断开。

6> 后期又修改了一些内容,使控制台输出信息统计次数,如图。

6 补充知识

1.mqtt消息的质量等级

SpringBoot 开发之 MQTT 协议消息质量等级分析_知道的越多,不知道的越多的博客-CSDN博客

qos 是发送方和接收方之间达成的协议,不是发布者和订阅者之间达成的协议。

也就是说发布者 Publish 一条 qos = 1 的消息,只能保证 Broker 能至少收到一次这个消息,至于对应的订阅者能否至少收到一次这个消息,还要取决于订阅者在 Subscribe 的时候和 Broker 协商的 qos 等级。

qos 为1 或者2时,消息会携带 messageId,qos 为 0 时没有。

qos = 0,最多一次送达。也就是消息发出去就直接删除掉,没有后面的事情了。
qos = 1,至少一次送达。发送方消息发出去之后会将消息保存,等待接收方带 messageId 的回应,如果没有回应,就会重新发送,直到回应到达后再把消息删除。
qos = 2,准确一次送达。

1 发送方消息发送后保存发送的消息,等待接收方回应,如果没有回应将会再次发送。
2 接收方会记录收到的 messageId,之后再收到相同 messageId 的消息都会被丢弃掉。
3 接收方发送带 messageId 的确认消息,等待发送方的回应,如果没有等到发送方回应,接收方会重复发送确认消息。
4 发送方收到确认消息之后,删除发送的消息,并发送带 messageId 的已确认消息。
5 接收方接收已确认消息后删除确认消息。

7 其他可行链接

用C#和html js文件实现了WebSocket通讯,后续还要考虑如何将变量从网页中取出来https://blog.csdn.net/Shuai_Sir/article/details/127364565?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168493215516800226547797%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168493215516800226547797&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~hot_rank-1-127364565-null-null.142%5Ev87%5Econtrol_2,239%5Ev2%5Einsert_chatgpt&utm_term=c%23%20websocket%E9%80%9A%E8%AE%AF&spm=1018.2226.3001.4187

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

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

相关文章

AjaxJson笔记,axios

wiki上ajax介绍 AJAX即“Asynchronous JavaScript and XML”&#xff08;异步的JavaScript与XML技术&#xff09;&#xff0c;指的是一套综合了多项技术的浏览器端网页开发技术。Ajax的概念由杰西詹姆士贾瑞特所提出[1]。 传统的Web应用允许用户端填写表单&#xff08;form&a…

[每天进步一点点~] uni-app 聊天对话

只有页面&#xff0c;功能未完成&#xff0c;使用uView插件 效果图&#xff1a; 代码&#xff1a;chat.vue <template><view class"content"><view class"content-box" touchstart"touchstart" id"content-box" :clas…

DRIVR_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS 蓝屏分析

最近在写windows驱动的时候发现有一个偶发蓝屏现象&#xff0c;打了一个full dump。记录分析的流程&#xff0c;便于以后查阅。 1 由上面的图片可以见到&#xff0c;蓝屏错误码是DRIVR_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS。查询 微软文档&#xff0c;可知该错误表…

【AI选股】如何通过python调用通达信-小达实现AI选股(量化又多了一个选股工具,原文Chrome浏览器请改为Edge浏览器)

文章目录 前言一、通达信-小达是什么&#xff1f;二、使用步骤1. 引入browser_cookie3库2. 通达信-小达 AI选股源代码 总结 前言 ChatGPT火遍网络&#xff0c;那么有没有可以不用写公式就可以实现AI选股的方法&#xff1f;答案是有&#xff0c;今天我们就来试试通达信的小达&a…

Opera One将取代 Opera 浏览器

导读Opera 日前推出了一款名为 Opera One 的新浏览器&#xff0c;该浏览器正处于开发者预览阶段&#xff0c;用户可以访问官网下载试用&#xff08;链接&#xff09;。这个浏览器的终极目标是在今年晚些时候取代其当家的 Opera 浏览器。 Opera One 遵循 "模块化设计理念&q…

ChatGPT引发新思考, 软件工程师们该如何应对?

语言模型ChatGPT最近火爆科技圈&#xff0c;仅两月时间&#xff0c;其月活跃用户数已突破1亿&#xff0c;成为史上用户增长速度最快的消费级应用程序。这款AI语言模型&#xff0c;让撰写邮件、论文、脚本&#xff0c;制定商业提案&#xff0c;创作诗歌、故事&#xff0c;甚至敲…

ChatGPT + Python = 王炸!

重磅&#xff0c;ChatGPT再次迎来里程碑式更新&#xff01; ChatGPT在上月推出了令人瞩目的插件功能&#xff0c;如果把ChatGPT看做是智能手机&#xff0c;那插件就相当于应用商店。现在的ChatGPT像一个“万能”的超级工具&#xff0c;善用它可以带来很多好处。 就与多年前移…

chatgpt赋能Python-python_aipocr

Python AIPocr&#xff1a;一款优秀的OCR识别库 Python AIPocr是一款基于Python语言的OCR识别库&#xff0c;具有许多强大的功能&#xff0c;可用于图像的字符和文本识别。在当前的人工智能应用时代&#xff0c;OCR技术的应用越来越广泛&#xff0c;Python AIPocr可以帮助开发…

大模型圆桌,ChatGPT、文心一言、讯飞星火如何看待「泛自动驾驶」

2022年11月30日&#xff0c;ChatGPT横空出世&#xff0c;掀开了人工智能认知大模型的进化爆发序幕。半年以来&#xff0c;国内外科技公司不甘落后&#xff0c;相继推出各自的认知模型&#xff0c;试图在巨大时代浪潮里分得一杯羹。 那么&#xff0c;层出不穷的大模型如何看待人…

ChatGPT:新晋CV工程师

在短短的两个星期内&#xff0c;ChatGPT 迅速成为公众聊天的焦点。超过一百万的人与OpenAI的新聊天机器人“交谈”&#xff0c;让它写诗和大学论文&#xff0c;生成创意食谱&#xff0c;创建虚拟机…它也被用来撰写新闻文章和YouTube视频的介绍。 作为计算机视觉公司的机器学习…

ChatGPT版必应发飙!怒斥人类:放尊重些

金磊 发自 凹非寺量子位 | 公众号 QbitAI 谁能想到&#xff0c;ChatGPT版必应竟能像人一样发脾气&#xff01; 事情是这样的。 前两天一个华人小哥不是“黑”了ChatGPT版必应&#xff0c;扒出它的小名叫Sydney嘛。 这可把一众网友们兴奋坏了&#xff0c;摩拳擦掌地准备去调戏它…

微软内战打响,ChatGPT对决新必应!13个灵魂拷问,新老AI各有所长

视学算法报道 编辑&#xff1a;编辑部 【导读】新必应和ChatGPT大PK&#xff0c;谁更厉害&#xff1f;记者亲测&#xff0c;新必应似乎比ChatGPT表现更好。 根据微软的说法&#xff0c;「新必应」搜索引擎是由「比ChatGPT更强大」的OpenAI技术驱动的。 因此&#xff0c;新必应…

ChatGPT与DataFocus:革新企业决策分析的数据分析工具

ChatGPT和Datafocus是目前市场上非常火热的两个数据分析工具&#xff0c;那么这两者之间有何联系呢&#xff1f;本文将着重探究ChatGDP和Datafocus搜索式BI这两个工具的联系及合作。 一、引言 随着大数据时代的到来&#xff0c;对于大数据的处理和分析变得越来越重要。为了更…

chatgpt赋能python:Python自动录音——让录制音频更加轻松自如

Python自动录音——让录制音频更加轻松自如 介绍 在现如今的数字时代&#xff0c;音频已经成为了人们生活中不可或缺的一部分。无论是在语音助手、在线教育还是音乐领域&#xff0c;音频的使用越来越普遍。然而&#xff0c;在某些情况下&#xff0c;我们可能需要录制一些音频…

chatgpt赋能python:Python录屏录音介绍

Python录屏录音介绍 在日常工作和学习中&#xff0c;录制屏幕和录制音频是一件很常见的事情。Python语言拥有强大的生态系统和第三方库支持&#xff0c;也可以轻松实现录制屏幕和录制音频的功能。本篇文章将介绍如何使用Python语言实现录屏录音功能。 Python录屏 录制屏幕可…

chatgpt赋能python:Python录音:介绍和使用方法

Python录音&#xff1a;介绍和使用方法 Python是一种高级编程语言&#xff0c;出现了许多支持模块&#xff0c;可用于不同领域中的开发和处理任务。对于音频处理和录音&#xff0c;Python提供了许多用于录制和处理音频的库和模块。在这篇文章中&#xff0c;我们将介绍如何使用…

chatgpt赋能python:PyAudio录音:快速入门指南

PyAudio录音&#xff1a;快速入门指南 PyAudio是一个流行的Python模块&#xff0c;用于录制音频并执行实时处理。它使用了底层音频库&#xff0c;具备可扩展性和灵活性&#xff0c;且可以用于听音乐、语音识别等方面。在本篇文章中&#xff0c;我们将快速入门PyAudio录音&…

宕机超 12 小时,损失过亿,唯品会基础平台负责人被免职!

整理 | 朱珂欣 出品 | CSDN程序人生&#xff08;ID&#xff1a;coder_life&#xff09; 对于后端程序员来说&#xff0c;“高并发”并非新鲜的话题&#xff0c;经历过一次服务器宕机&#xff0c;职业生涯才“完整”。 但如果事故超过 12 小时&#xff0c;或许会直接造成职业…

常见分布式锁4:zookeeper 瞬时znode节点 + watcher监听机制,ChatGPT回复的解决死锁的方案

原文地址在这里 临时节点具备数据自动删除的功能。当client与ZooKeeper连接和session断掉时&#xff0c;相应的临时节点就会被删除。zk有瞬时和持久节点&#xff0c;瞬时节点不可以有子节点。会话结束之后瞬时节点就会消失&#xff0c;基于zk的瞬时有序节点实现分布式锁&#x…

如何用ChatGPT设计出可控制的代码?

【编者按】如何训练 ChatGPT 实现自己想要的代码与功能&#xff0c;秘诀就是编写更具交互性和前瞻性的设计提示&#xff0c;本文作者分享了如何利用 ChatGPT 设计出可控制的代码步骤。 原文链接&#xff1a;https://www.friendlyskies.net/maybe/a-quick-way-to-get-more-creat…