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

通信协议—WebSocket

一、WebSocket编程概念

1.1 什么是WebSocket

WebSocket 是一种全双工通信协议,允许在客户端(通常是浏览器)和服务器之间建立持久连接,以实现实时的双向通信。它是 HTML5 标准的一部分,相比传统的 HTTP 请求,WebSocket 提供了更低的延迟和更高的性能,特别适合于需要实时更新数据的应用程序,如在线聊天、实时监控、游戏等

1.2 WebSocket的基本使用步骤

1.2.1 )服务器端
1.2.1.1)使用System.Net.WebSocket命名空间
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
1.2.1.2) 创建WebSocket服务器端点
public async Task HandleWebSocketConnection(HttpContext context)
{
    if (context.WebSockets.IsWebSocketRequest)
    {
        WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
        await EchoWebSocket(webSocket);
    }
    else
    {
        context.Response.StatusCode = 400;
    }
}
1.2.1.3)处理WebSocket消息
private async Task EchoWebSocket(WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    while (!result.CloseStatus.HasValue)
    {
        // 发送接收到的消息回客户端
        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
        // 继续接收下一条消息
        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }
    // 关闭 WebSocket 连接
    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
1.2.1.4)启动服务器
public static async Task Main(string[] args)
{
    var webSocketServer = new WebSocketServer();
    await webSocketServer.Start();
}
1.2.2 )客户端
1.2.2.1)使用System.Net.WebSocket.ClientWebSocket 命名空间
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
1.2.2.2)创建WebSocket客户端并连接到服务器
public async Task ConnectToWebSocketServer()
{
    using (var clientWebSocket = new ClientWebSocket())
    {
        Uri serverUri = new Uri("ws://localhost:8080/ws");
        await clientWebSocket.ConnectAsync(serverUri, CancellationToken.None);
        await SendAndReceiveData(clientWebSocket);
    }
}
1.2.2.3)发送和接收数据
private async Task SendAndReceiveData(ClientWebSocket clientWebSocket)
{
    var buffer = new byte[1024 * 4];
    string message = "Hello, WebSocket Server!";
    var sendBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message));
    await clientWebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);

    WebSocketReceiveResult result = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    string receivedMessage = Encoding.UTF8.GetString(buffer, 0, result.Count);
    Console.WriteLine($"Received: {receivedMessage}");
}
1.2.2.4)启动客户端
public static async Task Main(string[] args)
{
    var webSocketClient = new WebSocketClient();
    await webSocketClient.ConnectToWebSocketServer();
}
1.2.3) 运行步骤

1.2.3.1)先启动服务器程序,服务器将开始监听请求。
1.2.3.2)再启动客户端程序,客户端会连接到服务器并发送一条消息。
1.2.3.3)服务器接收到消息后,打印消息并回复。
1.2.3.4)客户端接收到服务器的回复并打印。

1.3 完整代码示例

1.3.1)服务器端
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace WebSocketServerExample
{
    public class WebSocketServer
    {
        private readonly IWebHost _webHost;

        public WebSocketServer()
        {
            _webHost = new WebHostBuilder()
              .UseKestrel()
              .ConfigureServices(services => services.AddRouting())
              .Configure(app =>
               {
                   app.UseWebSockets();
                   app.Use(async (context, next) =>
                   {
                       if (context.WebSockets.IsWebSocketRequest)
                       {
                           WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                           await EchoWebSocket(webSocket);
                       }
                       else
                       {
                           context.Response.StatusCode = 400;
                       }
                   });
               })
              .Build();
        }

        public async Task Start()
        {
            await _webHost.StartAsync();
        }

        private async Task EchoWebSocket(WebSocket webSocket)
        {
            var buffer = new byte[1024 * 4];
            WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            while (!result.CloseStatus.HasValue)
            {
                // 发送接收到的消息回客户端
                await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
                // 继续接收下一条消息
                result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }
            // 关闭 WebSocket 连接
            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
        }
    }

    class Program
    {
        static async Task Main(string[] args)
        {
            var webSocketServer = new WebSocketServer();
            await webSocketServer.Start();
        }
    }
}

// 代码解释
// 创建 WebSocket 服务器端点:
// app.UseWebSockets();:启用 WebSocket 中间件。
// context.WebSockets.IsWebSocketRequest:检查请求是否为 WebSocket 请求。
// context.WebSockets.AcceptWebSocketAsync():接受 WebSocket 请求并创建 WebSocket 对象。

// 处理 WebSocket 消息:
// await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);:接收客户端发送的消息。
// await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);:将接收到的消息发送回客户端。
// await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);:当收到关闭请求时,关闭连接。





 

1.3.2)客户端
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;

namespace WebSocketClientExample
{
    public class WebSocketClient
    {
        public async Task ConnectToWebSocketServer()
        {
            using (var clientWebSocket = new ClientWebSocket())
            {
                Uri serverUri = new Uri("ws://localhost:8080/ws");
                await clientWebSocket.ConnectAsync(serverUri, CancellationToken.None);
                await SendAndReceiveData(clientWebSocket);
            }
        }

        private async Task SendAndReceiveData(ClientWebSocket clientWebSocket)
        {
            var buffer = new byte[1024 * 4];
            string message = "Hello, WebSocket Server!";
            var sendBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message));
            await clientWebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);

            WebSocketReceiveResult result = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            string receivedMessage = Encoding.UTF8.GetString(buffer, 0, result.Count);
            Console.WriteLine($"Received: {receivedMessage}");
        }
    }

    class Program
    {
        static async Task Main(string[] args)
        {
            var webSocketClient = new WebSocketClient();
            await webSocketClient.ConnectToWebSocketServer();
        }
    }
}

// 代码解释
// 创建 WebSocket 客户端并连接到服务器:
// new ClientWebSocket():创建 WebSocket 客户端对象。
// clientWebSocket.ConnectAsync(serverUri, CancellationToken.None);:连接到服务器。

发送和接收数据:
// await clientWebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);:向服务器发送消息。
// await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);:接收服务器的消息。


1.4 注意事项

1.4.1)端口号和URI : 确保服务器和客户端使用相同的端口号和URI路径

1.4.2)异常处理 :在实际应用中,需要添加适当的异常处理代码,例如处理连接失败、接收或发送消息时的异常等

1.4.3)多客户端处理 :上述服务器端代码仅处理一个客户端,对于多客户端场景,需要使用更复杂的逻辑,例如使用  ConcurrentDictionary  来管理多个客户端连接


http://www.kler.cn/a/512308.html

相关文章:

  • 【Linux】gawk编辑器二
  • 生产环境中常用的设计模式
  • 【日志篇】(7.6) ❀ 01. 在macOS下刷新FortiAnalyzer固件 ❀ FortiAnalyzer 日志分析
  • C#,入门教程(02)—— Visual Studio 2022开发环境搭建图文教程
  • xiao esp32 S3播放SD卡wav音频
  • 大语言模型的语境中“越狱”和思维链
  • 电子应用设计方案97:智能AI投影仪系统设计
  • uniapp时间组件
  • 回归算法、聚类算法、决策树、随机森林、神经网络
  • Kafka面试题----Kafka都有哪些特点
  • Lightning初探
  • Go channel关闭方法
  • JAVA-IO模型的理解(BIO、NIO)
  • 在VSCode中使用Jupyter Notebook
  • Centos 8 交换空间管理
  • LeetCodeHOT100:60. n个骰子的点数、4. 寻找两个正序数组的中位数
  • 以“智慧建造”为理念,综合应用云、大、物、移、智等数字化技术的智慧工地云平台源码
  • 愿景是什么?
  • JSON-stringify和parse
  • 48V电气架构全面科普和解析:下一代智能电动汽车核心驱动
  • Android 空包签名(详细版)
  • AI刷题-病毒在封闭空间中的传播时间
  • 企业级流程架构设计思路-基于价值链的流程架构
  • 数据结构(二)栈/队列和二叉树/堆
  • centos虚拟机异常关闭,导致数据出现问题
  • 【2024年度个人生活与博客事业的融合与平衡总结】