.net websocket 使用

news/2025/2/27 9:52:46

系列文章目录

目录

文章目录

前言

一、websocket是什么?

一、工作原理

二、特点与优势

三、应用场景

四、缺点与挑战

二、使用步骤

1.引入库

2.如何使用

总结


文章目录

  • websocket 在.net中使用
  • 前言
  • 一、websocket 是什么?
  • 二、使用步骤
    • 1.引入库
    • 2.如何使用
  • 总结


前言

WebSocket是一种网络通信协议,旨在解决传统HTTP协议在实时通信方面的不足。


一、websocket是什么?

WebSocket是一种在单个TCP连接上进行全双工通信的协议。它允许客户端与服务器之间进行持久的、双向的通信,而无需像传统HTTP那样需要客户端不断发起请求来检查服务器是否有新数据。WebSocket协议在2008年首次提出,2011年被IETF(互联网工程任务组)作为标准RFC 6455发布,并由W3C(万维网联盟)进行标准化。

一、工作原理

WebSocket的工作原理可以分为三个阶段:握手、数据传输和断开连接。

  1. 握手:客户端通过发送一个特殊的HTTP请求头来向服务器发起WebSocket连接请求。这个请求中包含了一些特定的字段,如UpgradeConnectionSec-WebSocket-Key等,用于表明客户端希望将协议从HTTP升级到WebSocket。服务器在接收到这个请求后,会进行验证,并返回一个包含Sec-WebSocket-Accept字段的HTTP响应头,表示握手成功,双方建立了WebSocket连接。
  2. 数据传输:一旦建立了WebSocket连接,客户端和服务器就可以通过该连接进行双向的实时数据传输。数据以帧的形式进行传输,每个帧都包含了一些特定的字段,如FIN(表示该帧是否是消息的最后一帧)、Opcode(指定该帧的类型,如文本帧或二进制帧)、Mask(表示是否对数据进行了掩码处理)、Payload Length(数据的长度)以及Payload Data(实际发送的数据)。
  3. 断开连接:当连接不再需要时,客户端或服务器可以发起关闭连接的请求。双方会交换特殊的关闭帧,以协商关闭连接,并确保双方都接收到了关闭请求。

二、特点与优势

  1. 全双工通信:与传统HTTP请求/响应模式不同,WebSocket可以同时进行发送和接收数据。这意味着服务器可以主动向客户端发送数据,而不需要客户端先发起请求。
  2. 低延迟:由于建立了持久连接,并且数据传输没有额外的HTTP头部信息负担,因此WebSocket能够更快地传输小量数据。
  3. 节省带宽:WebSocket只需要一个TCP握手就能创建一个到服务器的链接,并且这个链接可以被复用以节省带宽。
  4. 跨域问题简单:在正确配置后,WebSocket允许跨域通讯。
  5. 适用于实时应用:对于聊天、游戏、实时交易等实时性要求高的应用,WebSocket能够提供更好的服务。

三、应用场景

WebSocket在实际应用中具有广泛的应用场景,包括但不限于:

  1. 实时聊天应用:如在线聊天室、即时通讯软件等,用户可以实时地发送和接收消息,提高了沟通效率。
  2. 在线游戏:实现游戏数据的实时传输和同步,为玩家提供更好的游戏体验。
  3. 实时数据监控:如股票价格、天气信息、交通状况等,服务器可以实时地将最新的数据推送给客户端。
  4. 协同办公:如在线文档编辑、实时会议等,多个用户可以同时编辑同一个文档或代码文件,他们的编辑结果会实时地同步到其他用户的界面上。
  5. 物联网(IoT):用于设备的远程监控和控制,允许实时收集和传输设备数据。

四、缺点与挑战

尽管WebSocket具有诸多优势,但也存在一些缺点和挑战:

  1. 兼容性问题:虽然大多数现代浏览器都支持WebSocket,但是一些老版本浏览器可能不支持。此外,一些网络代理和防火墙可能会阻止WebSocket连接。
  2. 安全性问题:WebSocket虽然在协议上支持加密(如WSS,即加密的WebSocket),但它并没有像HTTP那样有完善成熟的安全策略。开发者需要自己去处理安全性问题,如校验消息内容等。
  3. 服务器压力较高:由于需要保持长连接,所以会占用较多的服务器资源。这对服务器的性能和管理提出了更高的要求。
  4. 不适合大数据量传输:WebSocket更适合频繁、小数据量传输。对于大文件或大数据量传输来说,可能并不是最理想的选择。

综上所述,WebSocket作为一种现代Web实时通信的核心技术,具有显著的优势和广泛的应用场景。然而,在使用WebSocket时也需要考虑其兼容性问题、安全性问题以及服务器资源管理等挑战。

二、使用步骤

1.引入库

代码如下(示例):

using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.WebSockets;

2.如何使用

1.新建帮助类

代码如下(示例):


using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.WebSockets;

namespace Xhxx.WebSockets;

public class WebSocketHandler
{
    private WebSocket _webSocket;

    private int frameBytesCount = 10240;

    public event EventHandler Opened;

    public event EventHandler<string> TextMessageReceived;

    public event EventHandler Closed;

    public virtual async Task ProcessRequest(AspNetWebSocketContext context)
    {
        _webSocket = context.WebSocket;
        RaiseOpenEvent();
        while (_webSocket.State == WebSocketState.Open)
        {
            List<byte> receivedBytes = new List<byte>();
            ArraySegment<byte> buffer2 = WebSocket.CreateServerBuffer(frameBytesCount);
            WebSocketReceiveResult receiveResult = await _webSocket.ReceiveAsync(buffer2, CancellationToken.None);
            if (receiveResult.MessageType == WebSocketMessageType.Close)
            {
                await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                RaiseOnClosed();
                break;
            }

            WebSocketMessageType messageType = receiveResult.MessageType;
            MergeFrameContent(receivedBytes, buffer2.Array, receiveResult.Count);
            while (!receiveResult.EndOfMessage)
            {
                buffer2 = WebSocket.CreateServerBuffer(frameBytesCount);
                receiveResult = await _webSocket.ReceiveAsync(buffer2, CancellationToken.None);
                MergeFrameContent(receivedBytes, buffer2.Array, receiveResult.Count);
            }

            RaiseMessageArrive(receivedBytes.ToArray(), messageType, receivedBytes.Count);
        }
    }

    public virtual async Task SendMessage(string message)
    {
        if (_webSocket == null || _webSocket.State != WebSocketState.Open)
        {
            throw new InvalidOperationException("the web socket is not open.");
        }

        byte[] bytes = Encoding.UTF8.GetBytes(message);
        for (int sentBytes = 0; sentBytes < bytes.Length; sentBytes += frameBytesCount)
        {
            int remainingBytes = bytes.Length - sentBytes;
            await _webSocket.SendAsync(new ArraySegment<byte>(bytes, sentBytes, (remainingBytes > frameBytesCount) ? frameBytesCount : remainingBytes), WebSocketMessageType.Text, endOfMessage: true, CancellationToken.None);
        }
    }

    protected void MergeFrameContent(List<byte> destBuffer, byte[] buffer, long count)
    {
        count = ((count < buffer.Length) ? count : buffer.Length);
        if (count == buffer.Length)
        {
            destBuffer.AddRange(buffer);
            return;
        }

        byte[] array = new byte[count];
        Array.Copy(buffer, array, count);
        destBuffer.AddRange(array);
    }

    protected void RaiseOpenEvent()
    {
        this.Opened?.Invoke(this, EventArgs.Empty);
    }

    protected void RaiseMessageArrive(byte[] buffer, WebSocketMessageType type, long count)
    {
        if (type == WebSocketMessageType.Text && this.TextMessageReceived != null)
        {
            this.TextMessageReceived(this, Encoding.UTF8.GetString(buffer));
        }
    }

    protected void RaiseOnClosed()
    {
        this.Closed?.Invoke(this, EventArgs.Empty);
    }
}

2使用帮助类

      private static Dictionary<string, WebSocketHandler> _handlers = new Dictionary<string, WebSocketHandler>();
public HttpResponseMessage Connect(string nickName)
{
    var webSocketHandler = new WebSocketHandler();
    if (_handlers.ContainsKey(nickName))
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
    _handlers[nickName] = webSocketHandler;
    webSocketHandler.TextMessageReceived += (sendor, Parameter) =>
    {
        try
        {
            WebSocketDto _para = Newtonsoft.Json.JsonConvert.DeserializeObject<WebSocketDto>(Parameter);
            if (_para == null)
            {
                _handlers.Remove(nickName);
                result.code = (int)Const.c_code.参数错误;
                result.message = Const.c_code.参数错误.ToString();
                SendMessage(nickName, result.ToJson());
            }
            else
            {
                _para.nickName = nickName;
                if (_para.queryType == (int)QuestType.Login)
                {
                    DealMainLogin(_para);
                }
                if (_para.queryType == (int)QuestType.Agent)
                {
                    DealMainAgent(_para);
                }
                if (_para.queryType == (int)QuestType.xintiao)
                {
                    result.code = (int)QuestType.xintiao;
                    result.message = "恭喜,您目前处于活蹦乱跳状态 ^_^ ";
                    SendMessage(nickName, result.ToJson());
                }
            }
        }
        catch (Exception ex)
        {
            _handlers.Remove(nickName);
            result.code = (int)Const.c_code.抛出异常;
            result.message = ex.Message;
            SendMessage(nickName, result.ToJson());
        }
    };
    webSocketHandler.Closed += (sendor, arg) =>
    {
        if (nickName.Contains("login_"))
        {
            ClosedLogin(nickName);
        }
        _handlers.Remove(nickName);
    };
    webSocketHandler.Opened += (sendor, arg) =>
    {
        result.message = "连接成功...";
        SendMessage(nickName, result.ToJson());
    };

    HttpContext.Current.AcceptWebSocketRequest(webSocketHandler);

    return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);
}

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sendorNickName"></param>
        /// <param name="message"></param>
        private void SendMessage(string sendorNickName, string message, bool Broadcast = false)
        {
            foreach (var handlerKvp in _handlers)
            {
                if (Broadcast)
                {
                    //广播发送
                    handlerKvp.Value.SendMessage(message).Wait();
                }
                else
                {
                    //点对点发送
                    if (handlerKvp.Key == sendorNickName)
                    {
                        handlerKvp.Value.SendMessage(message).Wait();
                    }
                }

            }
        }

总结

这就是相关的websocket 使用方法


http://www.niftyadmin.cn/n/5869910.html

相关文章

Java Junit框架

JUnit 是一个广泛使用的 Java 单元测试框架&#xff0c;用于编写和运行可重复的测试。它是 xUnit 家族的一部分&#xff0c;专门为 Java 语言设计。JUnit 的主要目标是帮助开发者编写可维护的测试代码&#xff0c;确保代码的正确性和稳定性。 JUnit 的主要特点 注解驱动&…

如何做微课视频教程,小白零基础起步方法

想做微课视频教程&#xff0c;却不知从何下手&#xff1f;别慌&#xff0c;作为曾经的小白&#xff0c;我摸索出了一套超实用的方法&#xff0c;现在就分享给同样想入门的你&#xff0c;让你轻松掌握如何做微课视频教程。 制作微课视频&#xff0c;得先确定主题。这个主题要足…

python-leetcode-完全平方数

279. 完全平方数 - 力扣&#xff08;LeetCode&#xff09; class Solution:def numSquares(self, n: int) -> int:# 初始化 dp 数组&#xff0c;dp[i] 存储和为 i 的最少完全平方数数量dp [float(inf)] * (n 1)dp[0] 0 # 和为 0 的最少完全平方数数量是 0for i in range…

【构建工具】Gradle 8中Android BuildConfig的变化与开启方法

随着Gradle 8的发布&#xff0c;Android开发者需要注意一个重要变化&#xff1a;BuildConfig类的生成现在默认被关闭了&#xff01;&#xff01;&#xff01;。这个变化可能会影响许多依赖于BuildConfig的项目&#xff08;别问&#xff0c;问就是我也被影响了&#xff0c;多好用…

登录逻辑结合redis

1. 用户登录 用户访问登录页面&#xff0c;输入用户名和密码&#xff0c;提交表单。 服务端验证用户名和密码&#xff1a; 如果验证成功&#xff0c;生成 ticket&#xff0c;并将 ticket 和用户 ID 存储在缓存中&#xff08;如 Redis&#xff09;。 将 ticket 放入 Cookie 中…

org.springframework.boot不存在的其中一个解决办法

最近做项目的时候发现问题&#xff0c;改了几次pom.xml文件之后突然发现项目中的注解全部爆红。 可以尝试点击左上角的循环小图标&#xff0c;同步所有maven项目。 建议顺便检查一下Project Structure中的SDK和Language Level是否对应&#xff0c;否则可能报类似&#xff1a;“…

Jenkinsfile流水线构建教程

前言 Jenkins 是目前使用非常广泛的自动化流程的执行工具, 我们目前的一些自动化编译, 自动化测试都允许在 Jenkins 上面. 在 Jenkins 的术语里面, 一些自动化工作联合起来称之为流水线, 比如拉取代码, 编译, 运行自动化测试等. 本文的主要目的是引导你快速熟悉 Jenkinsfile …

C++ Primer 初识泛型算法

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…