You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET如何建立与指定HTTP服务的持久长连接?

实现.NET长连接读取流式HTTP响应的正确方式

这个场景是典型的HTTP流式响应+持久连接:Chrome能正常处理是因为它在收到响应头后就会持续监听响应流,不会等待整个响应完成。在.NET里要复刻这个行为,核心就是要避开那些会等待响应完全结束的API,直接操作响应流。下面给你两种主流实现方案:


现代.NET(Core/.NET 5+)推荐方案:HttpClient流式读取

这是当前.NET官方推荐的方式,代码简洁且性能更优:

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

class Program
{
    static async Task Main(string[] args)
    {
        var targetUrl = "https://srs-ds.i.daimler.com/STARCDS/services/Server?action=connect&id=GS0034837&version=1.4";
        
        // 创建取消令牌,支持手动终止连接(比如Ctrl+C)
        using var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (sender, e) =>
        {
            e.Cancel = true;
            cts.Cancel();
            Console.WriteLine("\n正在终止连接...");
        };

        // 建议全局单例复用HttpClient,避免Socket资源耗尽
        using var httpClient = new HttpClient
        {
            // 设置无限超时,匹配服务5分钟保活的间隔
            Timeout = Timeout.InfiniteTimeSpan
        };

        try
        {
            // 关键:使用ResponseHeadersRead选项,收到响应头就返回,不等待全量内容
            using var response = await httpClient.GetAsync(
                targetUrl, 
                HttpCompletionOption.ResponseHeadersRead, 
                cts.Token
            );
            response.EnsureSuccessStatusCode(); // 验证请求成功

            // 获取响应流并持续读取
            using var stream = await response.Content.ReadAsStreamAsync(cts.Token);
            using var reader = new StreamReader(stream);

            Console.WriteLine("已建立连接,开始监听响应...(按Ctrl+C终止)");

            // 循环读取直到连接关闭或手动取消
            while (!reader.EndOfStream && !cts.Token.IsCancellationRequested)
            {
                var message = await reader.ReadLineAsync(cts.Token);
                if (!string.IsNullOrEmpty(message))
                {
                    Console.WriteLine($"收到消息: {message}");
                }
            }
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("连接已被手动终止");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发生错误: {ex.Message}");
        }
    }
}

核心注意点:

  • HttpCompletionOption.ResponseHeadersRead:这是实现流式读取的关键,它告诉HttpClient不要等待整个响应下载完成,拿到响应头就返回控制权。
  • 超时设置:默认HttpClient超时是100秒,远短于服务5分钟的保活间隔,必须设置为Timeout.InfiniteTimeSpan或者足够长的时间。
  • HttpClient复用:不要每次请求都新建HttpClient,建议全局单例使用,避免频繁创建导致的Socket资源耗尽问题。

.NET Framework 兼容方案:HttpWebRequest实现

如果是老版本.NET Framework项目,可以用HttpWebRequest来实现:

using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var targetUrl = "https://srs-ds.i.daimler.com/STARCDS/services/Server?action=connect&id=GS0034837&version=1.4";
        
        using var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (sender, e) =>
        {
            e.Cancel = true;
            cts.Cancel();
            Console.WriteLine("\n正在终止连接...");
        };

        try
        {
            var request = (HttpWebRequest)WebRequest.Create(targetUrl);
            request.KeepAlive = true; // 启用持久连接(默认已开启)
            request.Timeout = Timeout.Infinite;
            request.ReadWriteTimeout = Timeout.Infinite;

            using var response = (HttpWebResponse)await request.GetResponseAsync();
            using var stream = response.GetResponseStream();
            using var reader = new StreamReader(stream);

            Console.WriteLine("已建立连接,开始监听响应...(按Ctrl+C终止)");

            while (!reader.EndOfStream && !cts.Token.IsCancellationRequested)
            {
                var message = await reader.ReadLineAsync(cts.Token);
                if (!string.IsNullOrEmpty(message))
                {
                    Console.WriteLine($"收到消息: {message}");
                }
            }
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("连接已被手动终止");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发生错误: {ex.Message}");
        }
    }
}

为什么你之前的尝试可能失败?

大概率是用了GetStringAsync、ReadAsStringAsync这类API——它们会强制等待整个响应完成才返回结果,但你的服务连接不会主动终止,所以会一直卡住。只要切换到直接读取响应流的方式,就能和Chrome保持一样的行为。

内容的提问来源于stack exchange,提问作者Leonardo Perez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:21:11