C# 中 WebSocket 与 SignalR实时通信的两种方案

 更新时间:2025年05月07日 09:14:18   作者:吴五万  
在现代 Web 应用中,实时通信变得越来越重要,无论是聊天应用、在线游戏、股票行情推送还是协作编辑工具,都需要服务器能够主动向客户端推送数据,本文将对这两种技术进行比较,分析它们的异同点和使用场景,并提供简单示例代码帮助你快速上手,感兴趣的朋友一起看看吧

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

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

一、什么是 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 对比

特性WebSocketSignalR
通信方式全双工全双工(通过封装)
是否需要手动处理连接✅ 需要❌ 不需要
是否支持多路复用❌ 不支持✅ 支持(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 更合适

六、延伸阅读

到此这篇关于C# 中 WebSocket 与 SignalR:实时通信的两种选择的文章就介绍到这了,更多相关C# WebSocket 与 SignalR实时通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#实现远程关闭和重启计算机的示例代码

    C#实现远程关闭和重启计算机的示例代码

    这篇文章主要为大家详细介绍了如何利用C#实现远程关闭和重启计算机的功能,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
    2022-12-12
  • 使用WPF实现一个虚拟键盘的代码示例

    使用WPF实现一个虚拟键盘的代码示例

    在某些特定场景下,我们可能需要使用虚拟键盘来替代实体键盘,本文将详细介绍如何使用 WPF 来实现一个虚拟键盘,并监控键盘输入,从而达到完全替代实体键盘的目的,需要的朋友可以参考下
    2025-04-04
  • DOTNETBAR制作圆角窗体和圆角控件代码实例

    DOTNETBAR制作圆角窗体和圆角控件代码实例

    这篇文章主要介绍了DOTNETBAR制作圆角窗体和圆角控件的方法,大家参考使用吧
    2013-11-11
  • C#中Linq延迟查询的例子

    C#中Linq延迟查询的例子

    这篇文章主要介绍了C#中Linq延迟查询的例子,本文用一个实例来讲解延迟查询的使用,需要的朋友可以参考下
    2015-06-06
  • c#互斥锁Mutex类用法介绍

    c#互斥锁Mutex类用法介绍

    本文详细讲解了c#互斥锁Mutex类的用法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-02-02
  • WPF中实现DataGrid行拖拽功能的完整方案

    WPF中实现DataGrid行拖拽功能的完整方案

    在WPF应用开发中,DataGrid是一个常用的数据展示控件,然而,原生的DataGrid并不支持行拖拽功能,这在需要调整行顺序的场景中显得尤为不便,所以本文将介绍如何实现一个优雅的DataGrid行拖拽功能,需要的朋友可以参考下
    2025-06-06
  • c#中返回文章发表的时间差的示例

    c#中返回文章发表的时间差的示例

    现在是2012-12-04 11:29:59,发表时间是:2012-12-02 21:29:59,传统的ts.Days因为值为1天14小时0分0秒,会返回“昨天”,而这个会返回“前天”
    2012-12-12
  • C#判断网站是否能访问或者断链的方法

    C#判断网站是否能访问或者断链的方法

    这篇文章主要介绍了C#判断网站是否能访问或者断链的方法,实例分析了C#判断网站是否能访问的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • C#与js实现去除textbox文本框里面重复记录的方法

    C#与js实现去除textbox文本框里面重复记录的方法

    这篇文章主要介绍了C#与js实现去除textbox文本框里面重复记录的方法,很实用的功能,需要的朋友可以参考下
    2014-08-08
  • Unity 修改FBX模型动画的操作

    Unity 修改FBX模型动画的操作

    这篇文章主要介绍了Unity 修改FBX模型动画的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04

最新评论