当前位置: 首页 > news >正文

在C#中实现WebSocket的单聊和分频道聊天

在C#中实现WebSocket的单聊和分频道聊天,可以利用System.Net.WebSockets库。以下是如何实现这个功能的具体方案和代码。

在这里插入图片描述

方案概述:

在这里插入图片描述

WebSocket Server:

  • 通过HttpListener或ASP.NET Core来承载WebSocket服务。
  • 维护每个客户端的连接,使用唯一标识来区分用户。
  • 处理不同的频道,通过简单的房间机制(频道名作为键)来区分不同聊天组。

WebSocket Client:

  • 每个客户端通过WebSocket与服务器通信。
  • 支持在一个特定的频道中发送和接收消息。

具体实现步骤:

1. WebSocket Server 代码

首先实现一个简单的WebSocket服务端,可以通过频道区分不同的房间。

在这里插入图片描述

使用HttpListener实现WebSocket服务端:

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;class WebSocketServer
{private HttpListener _httpListener;private ConcurrentDictionary<string, ConcurrentBag<WebSocket>> _channels = new ConcurrentDictionary<string, ConcurrentBag<WebSocket>>();public WebSocketServer(string uriPrefix){_httpListener = new HttpListener();_httpListener.Prefixes.Add(uriPrefix);}public async Task Start(){_httpListener.Start();Console.WriteLine("WebSocket server started.");while (true){var context = await _httpListener.GetContextAsync();if (context.Request.IsWebSocketRequest){HandleClient(context);}}}private async void HandleClient(HttpListenerContext context){WebSocket webSocket = (await context.AcceptWebSocketAsync(null)).WebSocket;Console.WriteLine("New client connected.");// 获取频道名称,从查询字符串中提取string channelName = context.Request.QueryString["channel"];if (!_channels.ContainsKey(channelName)){_channels[channelName] = new ConcurrentBag<WebSocket>();}_channels[channelName].Add(webSocket);await ReceiveMessages(webSocket, channelName);}private async Task ReceiveMessages(WebSocket webSocket, string channelName){var buffer = new byte[1024 * 4];while (webSocket.State == WebSocketState.Open){WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);string message = Encoding.UTF8.GetString(buffer, 0, result.Count);Console.WriteLine($"Message received in channel {channelName}: {message}");// 向频道内的所有用户广播消息await BroadcastMessage(channelName, message);}Console.WriteLine("Client disconnected.");_channels[channelName].TryTake(out _); // 从频道中移除该客户端}private async Task BroadcastMessage(string channelName, string message){var webSockets = _channels[channelName];var buffer = Encoding.UTF8.GetBytes(message);foreach (var webSocket in webSockets){if (webSocket.State == WebSocketState.Open){await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);}}}
}class Program
{static async Task Main(string[] args){var server = new WebSocketServer("http://localhost:5000/");await server.Start();}
}

解释:

  • 服务器通过HttpListener监听WebSocket连接。
  • 每个客户端可以加入不同的频道,服务器通过查询字符串中channel参数区分频道。
  • 当消息从一个客户端发出时,服务器将该消息广播到同一频道的所有客户端。

WebSocket Client 代码

客户端连接到服务器并指定频道,发送和接收消息。
在这里插入图片描述

using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;class WebSocketClient
{private ClientWebSocket _webSocket = new ClientWebSocket();public async Task ConnectAsync(string uri, string channel){string fullUri = $"{uri}?channel={channel}";await _webSocket.ConnectAsync(new Uri(fullUri), CancellationToken.None);Console.WriteLine($"Connected to server at {fullUri}");// 开始接收消息ReceiveMessages();}private async void ReceiveMessages(){var buffer = new byte[1024 * 4];while (_webSocket.State == WebSocketState.Open){WebSocketReceiveResult result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);string message = Encoding.UTF8.GetString(buffer, 0, result.Count);Console.WriteLine($"Received: {message}");}}public async Task SendMessageAsync(string message){var buffer = Encoding.UTF8.GetBytes(message);await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);}public async Task CloseAsync(){await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client closing", CancellationToken.None);}
}class Program
{static async Task Main(string[] args){var client = new```csharp
WebSocketClient();string serverUri = "ws://localhost:5000/";string channel = "general";  // 可以是任意频道名称,比如 "sports", "tech", 等等。// 连接到服务器并加入频道await client.ConnectAsync(serverUri, channel);// 发送消息到频道Console.WriteLine("Type a message to send:");while (true){string message = Console.ReadLine();if (message == "exit"){break;}await client.SendMessageAsync(message);}// 关闭连接await client.CloseAsync();Console.WriteLine("Connection closed.");}
}
解释:
  • 客户端使用ClientWebSocket连接到服务器,连接时通过查询字符串指定频道。
  • 客户端可以发送消息到服务器,服务器会将消息广播到同一频道内的其他客户端。
  • 客户端在后台一直监听来自服务器的消息,并将其显示出来。

3. 总结与扩展

  • 单聊:可以通过创建一个唯一的频道(例如:根据用户ID生成)实现单聊。
  • 分频道聊天:不同的聊天频道通过字符串(如"general"、"sports"等)进行区分,客户端连接时通过指定频道加入相应的聊天组。
  • 扩展:可以将WebSocket服务托管在ASP.NET Core中,使用更加高级的管理机制(例如SignalR,提升复杂度和功能)。

这个方案简洁易实现,适合初学者和小型应用的WebSocket单聊和分频道聊天系统。如果需要扩展到大规模用户或更复杂的应用,建议使用更加成熟的WebSocket库或框架。

//python 因为爱,所以学
print("Hello, Python!")

在这里插入图片描述

关注我,不迷路,共学习,同进步

关注我,不迷路,共学习,同进步


一、IM(即时通讯)项目概念介绍

(一)定义

即时通讯(Instant Messaging,简称IM)是一种基于互联网的实时通信方式,允许用户之间快速地交换文本消息、语音消息、视频通话、文件等内容。典型的IM应用包括微信、QQ、WhatsApp等。

(二)功能特点

  1. 实时性
    • 用户发送的消息几乎能够即时被对方接收,这种实时交互的特性使得IM在社交、商务沟通等场景中非常高效。例如,在工作场景中,团队成员可以通过IM工具迅速交流项目进展、解决突发问题。
  2. 多种消息类型支持
    • 除了基本的文本消息,还支持语音消息。语音消息方便用户在不方便打字的情况下快速传达信息,比如在驾车或者手上忙于其他事情的时候。
    • 视频通话功能则进一步拉近了用户之间的距离,适用于远程会议、家庭视频聊天等场景。
    • 能够发送文件,如文档、图片、音频和视频文件等,满足了用户在工作和生活中的多种需求。
  3. 用户状态展示
    • 可以显示用户的在线、离线、忙碌等状态。这样其他用户就可以根据对方的状态来决定是否联系或者以何种方式联系。例如,看到对方显示忙碌状态时,可能会选择发送离线消息而不是即时打扰。
  4. 群组功能
    • 支持创建和加入群组。群组可以是基于兴趣爱好(如摄影爱好者群)、工作项目(如项目团队沟通群)或者社交关系(如同学群、家族群)等。在群组中,多个用户可以同时进行交流互动。

二、IM项目的开发难点

(一)网络适配与稳定性

  1. 网络环境多样性
    • 不同用户可能处于不同的网络环境,如Wi - Fi、4G/5G、甚至是信号较差的2G网络。IM应用需要在各种网络条件下都能正常工作。例如,在弱网络环境下,要确保消息能够尽量不丢失、延迟在可接受范围内。如果没有良好的网络适配机制,可能会出现消息发送失败、语音或视频通话卡顿等问题。
  2. 网络切换处理
    • 当用户从Wi - Fi切换到移动数据或者反之,IM应用需要平滑过渡,不能导致连接中断或者消息丢失。这需要在应用层和底层网络协议处理上有相应的机制来保证数据的连贯性和完整性。

(二)消息的可靠传递

  1. 消息顺序保证
    • 在多消息并发发送的情况下,要确保消息按照发送的顺序到达接收方。例如,在一个聊天场景中,用户先发送了一条“你好”,接着发送“今天过得怎么样”,接收方应该按照这个顺序收到消息,否则可能会造成语义理解混乱。
  2. 消息不丢失
    • 由于网络波动或者设备故障等原因,消息可能会有丢失的风险。开发人员需要设计消息重传机制、确认机制等,以保证重要消息能够准确无误地传递到目的地。

(三)安全性

  1. 数据加密
    • 用户的聊天内容可能包含敏感信息,如商业机密、个人隐私等。因此,需要对消息进行加密处理,防止信息在传输过程中被窃取或篡改。例如,采用端到端加密技术,只有消息的发送方和接收方能够解密消息内容,即使消息在传输过程中被截获,第三方也无法获取其中的信息。
  2. 用户身份验证
    • 要确保用户身份的真实性,防止恶意用户冒用他人身份进行通信。这可能涉及到多种身份验证方式的结合,如账号密码登录、短信验证码验证、生物识别技术(指纹识别、面部识别等)。

(四)性能优化

  1. 海量消息处理
    • 对于大型IM应用,每天可能会有海量的消息交互。服务器需要具备高效的消息处理能力,能够快速地接收、存储和转发消息。例如,像微信这样拥有数亿用户的应用,在节假日等消息高峰期,要保证消息处理的及时性。
  2. 资源占用优化
    • 在客户端方面,IM应用要尽量减少对设备资源(如内存、CPU等)的占用,以确保设备的流畅运行。如果IM应用占用过多资源,可能会导致设备卡顿,影响用户体验。

(五)跨平台兼容性

  1. 不同操作系统
    • 需要在多种操作系统(如Windows、iOS、Android等)上都能正常运行,并且保持一致的用户体验。不同操作系统有不同的开发规范、界面设计准则和底层架构,开发人员需要针对每个平台进行适配和优化。
  2. 不同设备类型
    • 除了操作系统,还需要考虑不同设备类型,如手机、平板电脑、电脑等。不同设备的屏幕尺寸、分辨率、硬件性能等都有所不同,IM应用要能够自适应这些差异,提供合适的界面布局和功能操作。

相关文章:

  • 域 缺省参数 函数重载 引用
  • 【Golang】Go语言中如何面向对象?
  • 【研赛A题成品论文】24华为杯数学建模研赛A题成品论文+可运行代码丨免费分享
  • GO Serial 学习与使用
  • 大模型微调4:Alpaca模型微调、Adalora、Qlora
  • mysql学习教程,从入门到精通,SQL LIKE 运算符(28)
  • C++教程(三):c++常用的配置文件类型
  • 基于nodejs+vue的宠物医院管理系统
  • jupyter报错IProgress not found. Please update jupyter and ipywidgets
  • 基于Spring框架的分层解耦详解
  • 状态模式原理剖析
  • HTML基础用法介绍二
  • 计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-23
  • 单体到微服务架构服务演化过程
  • 《深度学习》【项目】OpenCV 发票识别 透视变换、轮廓检测解析及案例解析
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • [数据结构]链表的实现在PHP中
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • golang 发送GET和POST示例
  • Golang-长连接-状态推送
  • JavaScript 奇技淫巧
  • JWT究竟是什么呢?
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • Python学习之路16-使用API
  • Redis 中的布隆过滤器
  • Redis字符串类型内部编码剖析
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 简单数学运算程序(不定期更新)
  • 解析 Webpack中import、require、按需加载的执行过程
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 来,膜拜下android roadmap,强大的执行力
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 面试遇到的一些题
  • 前端面试题总结
  • 前端性能优化——回流与重绘
  • 前端自动化解决方案
  • 算法-图和图算法
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 整理一些计算机基础知识!
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • # AI产品经理的自我修养:既懂用户,更懂技术!
  • # include “ “ 和 # include < >两者的区别
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • (1)(1.13) SiK无线电高级配置(六)
  • (2024,LoRA,全量微调,低秩,强正则化,缓解遗忘,多样性)LoRA 学习更少,遗忘更少
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (不用互三)AI绘画:科技赋能艺术的崭新时代
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (回溯) LeetCode 46. 全排列