C# 中 WebSocket 与 SignalR:实时通信的两种选择

在现代 Web 应用中,实时通信变得越来越重要。无论是聊天应用、在线游戏、股票行情推送还是协作编辑工具,都需要服务器能够主动向客户端推送数据。在 .NET 生态系统中,WebSocketSignalR 是实现这一功能的两个主要方案。

本文将对这两种技术进行比较,分析它们的异同点和使用场景,并提供简单示例代码帮助你快速上手。


一、什么是 WebSocket?

WebSocket 是 HTML5 提供的一种全双工通信协议,允许客户端与服务器之间建立持久连接,实现双向实时通信。相比传统的 HTTP 请求-响应模式,WebSocket 更加高效,适合需要频繁交互的应用。

WebSocket 特点:

  • 基于 TCP 协议
  • 支持双向通信
  • 连接是长连接(保持打开)
  • 轻量级,性能高
  • 需要手动管理连接和消息处理

使用场景:

  • 实时数据推送(如股票行情)
  • 在线多人游戏
  • 多人协作编辑
  • IoT 设备通信等

二、什么是 SignalR?

SignalR 是微软开发的一个基于 .NET 的库,它简化了实时通信的实现。SignalR 内部封装了多种传输方式(包括 WebSocket、Server-Sent Events、长轮询等),并根据浏览器和网络环境自动选择最优的方式。

SignalR 特点:

  • 抽象了底层通信细节
  • 支持跨平台(.NET Core / .NET 6+)
  • 自动降级兼容性差的浏览器
  • 提供 Hub 模式,易于组织业务逻辑
  • 可集成到 ASP.NET Core 中

使用场景:

  • 快速构建实时功能(无需关注底层通信细节)
  • Web 应用中的通知系统
  • 即时通讯(IM)应用
  • 实时仪表盘、状态监控

三、WebSocket vs SignalR 对比

特性 WebSocket SignalR
通信方式 全双工 全双工(通过封装)
是否需要手动处理连接 需要 不需要
是否支持多路复用 不支持 支持(Hub)
是否支持自动降级 不支持 支持(长轮询等)
开发复杂度 较高 较低
性能 略低于 WebSocket
适合场景 高性能、定制化通信 快速开发、通用实时功能

四、示例代码

示例 1:WebSocket 服务端 + 客户端(.NET)

服务端(控制台程序)

using System;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        HttpListener listener = new HttpListener();
        listener.Prefixes.Add("http://localhost:5000/");
        listener.Start();
        Console.WriteLine("WebSocket Server started on http://localhost:5000");

        while (true)
        {
            HttpListenerContext context = await listener.GetContextAsync();
            if (context.Request.IsWebSocketRequest)
            {
                WebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null);
                _ = HandleWebSocketConnection(webSocketContext.WebSocket);
            }
            else
            {
                context.Response.StatusCode = 400;
                context.Response.Close();
            }
        }
    }

    private static async Task HandleWebSocketConnection(WebSocket socket)
    {
        byte[] buffer = new byte[1024 * 4];
        while (socket.State == WebSocketState.Open)
        {
            WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
            Console.WriteLine($"Received: {message}");

            // Echo back the message
            byte[] response = Encoding.UTF8.GetBytes($"Echo: {message}");
            await socket.SendAsync(new ArraySegment<byte>(response), WebSocketMessageType.Text, true, CancellationToken.None);
        }
    }
}

客户端(JavaScript)

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Client</title>
</head>
<body>
    <input type="text" id="messageInput" placeholder="Enter message" />
    <button onclick="sendMessage()">Send</button>
    <div id="output"></div>

    <script>
        const ws = new WebSocket('ws://localhost:5000');
        ws.onmessage = function (event) {
            document.getElementById('output').innerText += event.data + '\n';
        };

        function sendMessage() {
            const input = document.getElementById('messageInput');
            const message = input.value;
            ws.send(message);
            input.value = '';
        }
    </script>
</body>
</html>

示例 2:SignalR 服务端 + 客户端(ASP.NET Core)

服务端(Startup.cs 或 Program.cs)

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddSignalR();

var app = builder.Build();

app.MapHub<ChatHub>("/chatHub");

app.Run();

public class ChatHub : Hub
{
    public async Task Send(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

客户端(JavaScript)

<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/5.0.13/signalr.min.js"></script>
<input type="text" id="userInput" placeholder="User" />
<input type="text" id="messageInput" placeholder="Message" />
<button onclick="sendMessage()">Send</button>
<div id="chat"></div>

<script>
    const connection = new signalR.HubConnectionBuilder()
        .withUrl("/chatHub")
        .build();

    connection.on("ReceiveMessage", function (user, message) {
        const msg = `${user}: ${message}`;
        document.getElementById("chat").innerHTML += `<p>${msg}</p>`;
    });

    connection.start().catch(function (err) {
        return console.error(err.toString());
    });

    function sendMessage() {
        const user = document.getElementById("userInput").value;
        const message = document.getElementById("messageInput").value;
        connection.invoke("Send", user, message).catch(function (err) {
            return console.error(err.toString());
        });
        document.getElementById("messageInput").value = "";
    }
</script>

五、总结

场景 推荐技术
高性能、低延迟、自定义协议 WebSocket
快速开发、通用实时功能 SignalR
浏览器兼容性要求高 SignalR
需要精细控制通信过程 WebSocket

如果你正在开发一个简单的聊天室或通知系统,SignalR 是更好的选择;而如果你需要构建一个高性能、低延迟的物联网通信系统,WebSocket 更合适


六、延伸阅读

  • Microsoft SignalR 文档
  • WebSocket W3C 标准文档
  • ASP.NET Core WebSocket 支持

希望这篇博客对你有所帮助!如果你有更多关于 C# 或实时通信的问题,欢迎留言交流

来源链接:https://www.cnblogs.com/wwwan/p/18863581

© 版权声明
THE END
支持一下吧
点赞9 分享
评论 抢沙发
头像
请文明发言!
提交
头像

昵称

取消
昵称表情代码快捷回复

    暂无评论内容