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

news2024/11/16 19:27:04

在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应用要能够自适应这些差异,提供合适的界面布局和功能操作。

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

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

相关文章

基于贝叶斯优化CNN-GRU网络的数据分类识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1卷积神经网络&#xff08;CNN&#xff09; 4.2 GRU网络 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 优化前&#xff1a; 优化后&#xff1a; 2.算法运行软件版…

Java网络编程、正则表达式、单例设计模式与Lombok

目录 Java网络编程、正则表达式、单例设计模式与Lombok Java网络编程 软件结构 网络基础知识 相关概念 IP地址 TCP协议和UDP协议介绍 TCP协议的三次握手和四次挥手 UDP协议编程 创建客户端 创建服务端 运行 TCP协议编程 创建客户端 创建服务端 运行 文件上传案例 创建客户端 创…

windows C++-同步数据结构与 Windows API

将并发运行时提供的同步数据结构的行为与 Windows API 提供的同步数据结构的行为进行比较。 并发运行时提供的同步数据结构遵循协作线程模型。 在协作线程模型中&#xff0c;同步基元显式将其处理资源传递给其他线程。 这与抢占式线程模型不同&#xff0c;其中处理资源由控制调…

Python | Leetcode Python题解之第434题字符串中的单词数

题目&#xff1a; 题解&#xff1a; class Solution:def countSegments(self, s):segment_count 0for i in range(len(s)):if (i 0 or s[i - 1] ) and s[i] ! :segment_count 1return segment_count

教授【优青】团队亲自指导-图解表观遗传学 | 组蛋白修饰!专业实验设计、数据分析、SCI论文辅助等全方位服务。精准高效,为农植物科研保驾护航!

教授【优青】团队亲自指导&#xff01;提供专业实验设计、数据分析、SCI论文辅助等全方位服务。精准高效&#xff0c;为医学科研保驾护航&#xff01; 专业实验外包服务&#xff0c;一站式解决您的所有需求&#xff1b; 还在犹豫&#xff1f;别让您的科研和论文停滞不前&#…

C# Socket 服务端

WPF 项目 引入 Socket using System.Net.Sockets; 声明 Socket 并创建对象等待客户端连接 开启线程等待客户端连接并接收消息 接收消息并解析 发送消息 完整代码

目标检测DOTA数据集

前言 ​ 之前对于xml格式的YOLO数据集&#xff0c;之前记录过如何用imgaug对其进行数据增强。不过DOTA数据集采用的是txt格式的旋转框标注&#xff0c;因此不能直接套用&#xff0c;只能另辟蹊径。 DOTA数据集简介 DOTA数据集全称&#xff1a;Dataset for Object deTection i…

Redis6 多线程模型

优质博文&#xff1a;IT-BLOG-CN 一、单线程的优缺点 对于一个请求操作Redis主要做3件事情&#xff1a;从客户端读取数据/解析、执行Redis命令、回写数据给客户端。所以主线程其实就是把所有操作的这3件事情串行一起执行&#xff0c;因为是基于内存&#xff0c;所以执行速度非…

区间合并算法

区间合并 区间合并就是有两个区间我们把两个区间合并成一个区间 我们来看一道题 Acwing 803 区间合并 1.题目 给定 n nn 个区间 [ l i , r i ] [li,ri][li,ri]&#xff0c;要求合并所有有交集的区间。 注意如果在端点处相交&#xff0c;也算有交集。 输出合并完成后的区间个…

C语言 | Leetcode C语言题解之第434题字符串中的单词数

题目&#xff1a; 题解&#xff1a; int countSegments(char * s){int count 0; //count用来记录单词个数for(int i0; i < strlen(s); i){ //遍历字符串 if((i 0 || s[i-1] ) && s[i] ! ) //一个…

C语言_指针(2)

1.指针与数组的关系 1.1 数组名 先看代码&#xff1a; #include <stdio.h> int main() {int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] %p\n", &arr[0]);printf("arr %p\n", arr);return 0;}运行结果是这样的&#xff1a; 我…

数据结构 ——— 数组 nums 包含了从 0 到 n 的所有整数,但是其中缺失了一个,请编写代码找出缺失的整数,并且在O(N)时间内完成

目录 题目要求 代码实现 方法1&#xff08;异或法&#xff09;&#xff1a; 异或算法的时间复杂度&#xff1a; 方法2&#xff08;等差数列公式&#xff09;&#xff1a; 等差数列公式的时间复杂度&#xff1a; 题目要求 整型数组 nums 包含了从 0 到 n 的所有整数&…

【有啥问啥】 Self-Play技术:强化学习中的自我进化之道

Self-Play技术&#xff1a;强化学习中的自我进化之道 在人工智能的快速发展中&#xff0c;强化学习&#xff08;Reinforcement Learning, RL&#xff09;已成为推动智能体自主学习与优化的关键力量。Self-Play技术&#xff0c;作为强化学习领域的一项前沿创新&#xff0c;通过…

Java语法-类和对象(上)

1. 面向对象的初步认识 1.1 什么是面向对象 概念: Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。 1.2 面向对象VS面向过程 如:洗衣服 面向过程: 注重的是洗衣服的过程,少了一个环节也不…

SPSS26统计分析笔记——3 假设检验

1 假设检验原理 假设检验的基本原理源于“小概率事件”原理&#xff0c;是一种基于概率性质的反证法。其核心思想是小概率事件在一次试验中几乎不会发生。检验的过程首先假设原假设 H 0 {H_0} H0​成立&#xff0c;然后通过统计方法分析样本数据。如果样本数据引发了“小概率事…

《数据压缩入门》笔记-Part 2

一篇文章显得略长&#xff0c;本文对应原书6-10章。序言、前言、第1-5章&#xff0c;请参考Part 1&#xff0c;第11-15章&#xff0c;请参考Part 3。 自适应统计编码 位置对熵的重要性 统计编码有一个问题&#xff1a;在编码开始之前都需要遍历一次数据&#xff0c;以计算出…

Linux:八种重定向详解(万字长文警告)

相关阅读Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 本文将讨论Linux中的重定向相关问题&#xff0c;在阅读本文前&#xff0c;强烈建议先学习文件描述符的相关内容Linux&#xff1a;文件描述符详解。 重定向分为两类&#x…

智能感知,主动防御:移动云态势感知为政企安全护航

数字化时代&#xff0c;网络安全已成为企业持续运营和发展的重要基石。随着业务扩展&#xff0c;企业资产的数量急剧增加&#xff0c;且分布日益分散&#xff0c;如何全面、准确地掌握和管理资产成为众多政企单位的难题。同时&#xff0c;传统安全手段又难以有效应对新型、隐蔽…

【unity进阶知识1】最详细的单例模式的设计和应用,继承和不继承MonoBehaviour的单例模式,及泛型单例基类的编写

文章目录 前言一、不使用单例二、普通单例模式1、单例模式介绍实现步骤&#xff1a;单例模式分为饿汉式和懒汉式两种。 2、不继承MonoBehaviour的单例模式2.1、基本实现2.2、防止外部实例化对象2.3、最终代码 3、继承MonoBehaviour的单例模式3.1、基本实现3.2、自动创建和挂载单…

苏轼为何要写石钟山记?时间节点是关键

《石钟山记》不仅是苏轼的旅行笔记&#xff0c;亦是其人生哲学与思想的深邃自省。文中不仅详述了他对石钟山的实地勘察&#xff0c;亦体现了其对历史、自然及人生之独到见解。黄州生涯及其对政治与文化的洞悉&#xff0c;为这篇作品注入了深厚底蕴。 苏轼的黄州岁月 黄州期间…