腾西天讯芭比球 發表於 2025-5-7 08:47:00

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

<p>在现代 Web 应用中,实时通信变得越来越重要。无论是聊天应用、在线游戏、股票行情推送还是协作编辑工具,都需要服务器能够主动向客户端推送数据。在 .NET 生态系统中,<strong>WebSocket</strong> 和 <strong>SignalR</strong> 是实现这一功能的两个主要方案。</p>
<p>本文将对这两种技术进行比较,分析它们的异同点和使用场景,并提供简单示例代码帮助你快速上手。</p>
<hr>
<h2 id="一什么是-websocket">一、什么是 WebSocket?</h2>
<p>WebSocket 是 HTML5 提供的一种<strong>全双工通信协议</strong>,允许客户端与服务器之间建立持久连接,实现双向实时通信。相比传统的 HTTP 请求-响应模式,WebSocket 更加高效,适合需要频繁交互的应用。</p>
<h3 id="websocket-特点">WebSocket 特点:</h3>
<ul>
<li>基于 TCP 协议</li>
<li>支持双向通信</li>
<li>连接是长连接(保持打开)</li>
<li>轻量级,性能高</li>
<li>需要手动管理连接和消息处理</li>
</ul>
<h3 id="使用场景">使用场景:</h3>
<ul>
<li>实时数据推送(如股票行情)</li>
<li>在线多人游戏</li>
<li>多人协作编辑</li>
<li>IoT 设备通信等</li>
</ul>
<hr>
<h2 id="二什么是-signalr">二、什么是 SignalR?</h2>
<p>SignalR 是微软开发的一个<strong>基于 .NET 的库</strong>,它简化了实时通信的实现。SignalR 内部封装了多种传输方式(包括 WebSocket、Server-Sent Events、长轮询等),并根据浏览器和网络环境自动选择最优的方式。</p>
<h3 id="signalr-特点">SignalR 特点:</h3>
<ul>
<li>抽象了底层通信细节</li>
<li>支持跨平台(.NET Core / .NET 6+)</li>
<li>自动降级兼容性差的浏览器</li>
<li>提供 Hub 模式,易于组织业务逻辑</li>
<li>可集成到 ASP.NET Core 中</li>
</ul>
<h3 id="使用场景-1">使用场景:</h3>
<ul>
<li>快速构建实时功能(无需关注底层通信细节)</li>
<li>Web 应用中的通知系统</li>
<li>即时通讯(IM)应用</li>
<li>实时仪表盘、状态监控</li>
</ul>
<hr>
<h2 id="三websocket-vs-signalr-对比">三、WebSocket vs SignalR 对比</h2>
<table>
<thead>
<tr>
<th>特性</th>
<th>WebSocket</th>
<th>SignalR</th>
</tr>
</thead>
<tbody>
<tr>
<td>通信方式</td>
<td>全双工</td>
<td>全双工(通过封装)</td>
</tr>
<tr>
<td>是否需要手动处理连接</td>
<td>✅ 需要</td>
<td>❌ 不需要</td>
</tr>
<tr>
<td>是否支持多路复用</td>
<td>❌ 不支持</td>
<td>✅ 支持(Hub)</td>
</tr>
<tr>
<td>是否支持自动降级</td>
<td>❌ 不支持</td>
<td>✅ 支持(长轮询等)</td>
</tr>
<tr>
<td>开发复杂度</td>
<td>较高</td>
<td>较低</td>
</tr>
<tr>
<td>性能</td>
<td>高</td>
<td>略低于 WebSocket</td>
</tr>
<tr>
<td>适合场景</td>
<td>高性能、定制化通信</td>
<td>快速开发、通用实时功能</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="四示例代码">四、示例代码</h2>
<h3 id="示例-1websocket-服务端--客户端net">示例 1:WebSocket 服务端 + 客户端(.NET)</h3>
<h4 id="服务端控制台程序">服务端(控制台程序)</h4>
<pre><code class="language-csharp">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;
      while (socket.State == WebSocketState.Open)
      {
            WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment&lt;byte&gt;(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&lt;byte&gt;(response), WebSocketMessageType.Text, true, CancellationToken.None);
      }
    }
}
</code></pre>
<h4 id="客户端javascript">客户端(JavaScript)</h4>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;WebSocket Client&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;input type="text" id="messageInput" placeholder="Enter message" /&gt;
    &lt;button onclick="sendMessage()"&gt;Send&lt;/button&gt;
    &lt;div id="output"&gt;&lt;/div&gt;

    &lt;script&gt;
      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 = '';
      }
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<hr>
<h3 id="示例-2signalr-服务端--客户端aspnet-core">示例 2:SignalR 服务端 + 客户端(ASP.NET Core)</h3>
<h4 id="服务端startupcs-或-programcs">服务端(Startup.cs 或 Program.cs)</h4>
<pre><code class="language-csharp">var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

app.MapHub&lt;ChatHub&gt;("/chatHub");

app.Run();

public class ChatHub : Hub
{
    public async Task Send(string user, string message)
    {
      await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}
</code></pre>
<h4 id="客户端javascript-1">客户端(JavaScript)</h4>
<pre><code class="language-html">&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/5.0.13/signalr.min.js"&gt;&lt;/script&gt;
&lt;input type="text" id="userInput" placeholder="User" /&gt;
&lt;input type="text" id="messageInput" placeholder="Message" /&gt;
&lt;button onclick="sendMessage()"&gt;Send&lt;/button&gt;
&lt;div id="chat"&gt;&lt;/div&gt;

&lt;script&gt;
    const connection = new signalR.HubConnectionBuilder()
      .withUrl("/chatHub")
      .build();

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

    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 = "";
    }
&lt;/script&gt;
</code></pre>
<hr>
<h2 id="五总结">五、总结</h2>
<table>
<thead>
<tr>
<th>场景</th>
<th>推荐技术</th>
</tr>
</thead>
<tbody>
<tr>
<td>高性能、低延迟、自定义协议</td>
<td>WebSocket</td>
</tr>
<tr>
<td>快速开发、通用实时功能</td>
<td>SignalR</td>
</tr>
<tr>
<td>浏览器兼容性要求高</td>
<td>SignalR</td>
</tr>
<tr>
<td>需要精细控制通信过程</td>
<td>WebSocket</td>
</tr>
</tbody>
</table>
<p>如果你正在开发一个简单的聊天室或通知系统,<strong>SignalR 是更好的选择</strong>;而如果你需要构建一个高性能、低延迟的物联网通信系统,<strong>WebSocket 更合适</strong>。</p>
<hr>
<h2 id="六延伸阅读">六、延伸阅读</h2>
<ul>
<li>Microsoft SignalR 文档</li>
<li>WebSocket W3C 标准文档</li>
<li>ASP.NET Core WebSocket 支持</li>
</ul>
<hr>
<p>希望这篇博客对你有所帮助!如果你有更多关于 C# 或实时通信的问题,欢迎留言交流 😊</p><br><br>
来源:https://www.cnblogs.com/wwwan/p/18863581
頁: [1]
查看完整版本: C# 中 WebSocket 与 SignalR:实时通信的两种选择