轮询、WebSocket 和 SSE:实时通信技术全面指南(含C#实现)

轮询、WebSocket 和 SSE:实时通信技术全面指南(含C#实现)

技术概览与对比

1. 轮询 (Polling)

简介
轮询是一种客户端定期向服务器发送请求以检查更新的伪推送技术。

C# 服务端示例

// ASP.NET Core 轮询接口示例
[ApiController]
[Route("api/poll")]
public class PollingController : ControllerBase
{
    private static DateTime _lastUpdate = DateTime.MinValue;
    
    [HttpGet]
    public IActionResult GetUpdates([FromQuery] DateTime lastClientUpdate)
    {
        // 检查是否有新数据
        if (_lastUpdate > lastClientUpdate)
        {
            return Ok(new {
                timestamp = _lastUpdate,
                data = "新的轮询数据"
            });
        }
        
        return NoContent(); // 304也可以
    }
    
    // 更新数据的方法(通常由其他服务调用)
    public static void UpdateData()
    {
        _lastUpdate = DateTime.Now;
    }
}

客户端使用

// 前端轮询示例
function startPolling() {
    setInterval(async () => {
        const response = await fetch('/api/poll?lastClientUpdate=' + lastUpdateTime);
        if (response.ok) {
            const data = await response.json();
            // 处理数据...
            lastUpdateTime = data.timestamp;
        }
    }, 5000); // 每5秒轮询一次
}

2. WebSocket

简介
WebSocket 提供了全双工、持久的连接,支持真正的实时双向通信。

C# 服务端实现

// ASP.NET Core WebSocket 示例
public class WebSocketHandler
{
    private readonly RequestDelegate _next;

    public WebSocketHandler(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await HandleWebSocketConnection(webSocket);
        }
        else
        {
            await _next(context);
        }
    }

    private async Task HandleWebSocketConnection(WebSocket webSocket)
    {
        var buffer = new byte[1024 * 4];
        WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        
        while (!result.CloseStatus.HasValue)
        {
            // 处理接收到的消息
            string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
            Console.WriteLine($"Received: {message}");
            
            // 发送响应
            string response = $"Echo: {message} at {DateTime.Now}";
            byte[] responseBytes = Encoding.UTF8.GetBytes(response);
            await webSocket.SendAsync(new ArraySegment<byte>(responseBytes), 
                WebSocketMessageType.Text, true, CancellationToken.None);
            
            result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        }
        
        await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
    }
}

客户端使用

// 前端WebSocket示例
const socket = new WebSocket('ws://yourserver.com/ws');

socket.onopen = function(e) {
    console.log("WebSocket连接已建立");
    socket.send("Hello Server!");
};

socket.onmessage = function(event) {
    console.log(`收到消息: ${event.data}`);
};

socket.onclose = function(event) {
    if (event.wasClean) {
        console.log(`连接正常关闭,code=${event.code} reason=${event.reason}`);
    } else {
        console.log('连接中断');
    }
};

socket.onerror = function(error) {
    console.log(`错误: ${error.message}`);
};

3. 服务器发送事件 (SSE)

简介
SSE 是一种允许服务器向客户端推送数据的单向通信技术。

C# 服务端实现

// ASP.NET Core SSE 示例
[ApiController]
[Route("api/sse")]
public class SSEController : ControllerBase
{
    [HttpGet]
    public async Task Get()
    {
        Response.Headers.Add("Content-Type", "text/event-stream");
        Response.Headers.Add("Cache-Control", "no-cache");
        Response.Headers.Add("Connection", "keep-alive");

        for (int i = 0; i < 10; i++)
        {
            var data = new {
                message = $"Message {i}",
                time = DateTime.Now.ToString("HH:mm:ss")
            };
            
            string eventData = $"data: {JsonSerializer.Serialize(data)}\n\n";
            await Response.WriteAsync(eventData);
            await Response.Body.FlushAsync();
            
            await Task.Delay(1000);
        }
        
        Response.Body.Close();
    }
}

客户端使用

// 前端SSE示例
const eventSource = new EventSource('/api/sse');

eventSource.onmessage = function(event) {
    const data = JSON.parse(event.data);
    console.log('收到消息:', data);
};

eventSource.onopen = function() {
    console.log('SSE连接已建立');
};

eventSource.onerror = function() {
    console.log('SSE连接错误');
    // 自动重连
};

技术对比总结

特性轮询WebSocketSSE
通信方向客户端→服务器双向服务器→客户端
协议HTTPWS/WSSHTTP
实现复杂度简单中等简单
实时性低(取决于轮询间隔)
资源消耗高(频繁请求)低(持久连接)中等
兼容性所有浏览器IE10+, 现代浏览器除IE外的现代浏览器
C#支持简单HTTP接口需要中间件处理流式响应
适用场景简单更新,兼容性要求高聊天、游戏、实时协作实时通知、数据推送

生产环境建议

  1. WebSocket最佳实践
    • 使用SignalR库(.NET官方实时通信库)
    • 处理连接中断和重连
    • 考虑消息压缩(特别是高频小消息)
// SignalR 服务端示例
public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}
  1. SSE优化建议
    • 设置适当的重试时间(retry字段)
    • 使用事件类型区分不同消息
    • 考虑心跳机制保持连接
// 带心跳的SSE
await Response.WriteAsync("retry: 5000\n\n"); // 5秒重试
while (true)
{
    if (hasData)
    {
        await Response.WriteAsync($"data: {data}\n\n");
    }
    else
    {
        // 心跳
        await Response.WriteAsync(": heartbeat\n\n");
    }
    await Task.Delay(1000);
}
  1. 降级策略
// 检测支持情况并提供降级方案
if (HttpContext.WebSockets.IsWebSocketRequest)
{
    // WebSocket处理
}
else if (Request.Headers["Accept"] == "text/event-stream")
{
    // SSE处理
}
else
{
    // 降级到轮询
    return PollingEndpoint();
}

总结

  • 选择WebSocket:当需要双向实时通信时(如聊天应用、实时游戏)
  • 选择SSE:当只需服务器推送且希望简单实现时(如通知、行情更新)
  • 选择轮询:仅作为兼容性后备方案或在极简单场景中使用

.NET开发者特别推荐使用SignalR库,它自动选择最佳传输方式(WebSocket、SSE、长轮询等)并处理连接管理、重连等复杂问题。

这只是开胃菜,SignalR 是下一篇要讲的,敬请期待…

【SignalR 完全指南:.NET 实时通信的终极解决方案】飞机票 直达

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上有潜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值