You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#实现HTTP持久化连接对接国产热成像安防摄像头的技术求助

解决HTTP持久化连接获取热成像摄像头持续数据的问题

看起来你踩了一个常见的坑:用HttpClient.GetAsync()来处理持续数据流型的持久连接。这个方法会一直等待服务器发送完整个响应才会返回,但厂商描述的场景是服务器会在建立连接后持续推送告警数据(通常用Transfer-Encoding: chunked编码),所以你的代码会一直卡在GetAsync()那里,永远拿不到返回值。

下面是针对你的场景的修改方案,完全适配HTTP 1.1持久连接的需求:

核心修改点

  • 放弃GetAsync(),改用流读取方式直接处理持续推送的数据,因为持久连接下服务器不会发送完整响应
  • 复用HttpClient实例:原代码每次请求都创建新的HttpClient,会导致连接被频繁关闭,直接破坏持久化机制。HttpClient是设计为复用的单例/静态实例
  • 持续监听响应流,直到连接断开或你主动停止接收

修改后的完整代码

// 注意:HttpClient应该复用,不要每次请求都创建,这里声明为静态实例
private static readonly HttpClient _httpClient;

// 静态构造函数初始化HttpClient,确保只创建一次
static YourClassName()
{
    var camUri = new Uri("http://<cam's IPv4>/ISAPI/Thermal/channels/2/thermometry/realTimethermometry/rules?format=json");
    var credentialCache = new CredentialCache();
    credentialCache.Add(camUri, "Digest", new NetworkCredential("test", "test"));

    var handler = new HttpClientHandler() 
    { 
        AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, 
        Credentials = credentialCache,
        // HTTP 1.1默认启用Keep-Alive,这里明确保持配置
        UseProxy = false,
        AllowAutoRedirect = false
    };

    _httpClient = new HttpClient(handler);
    _httpClient.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
    // 设置合理超时,避免无数据时无限等待,可根据厂商建议调整
    _httpClient.Timeout = TimeSpan.FromMinutes(30);
}

public async Task StartReceivingThermalAlerts(CancellationToken cancellationToken)
{
    var camUri = new Uri("http://<cam's IPv4>/ISAPI/Thermal/channels/2/thermometry/realTimethermometry/rules?format=json");

    try
    {
        // 使用ResponseHeadersRead选项:收到响应头就返回,不等待完整响应
        using (var response = await _httpClient.GetAsync(camUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
        {
            response.EnsureSuccessStatusCode(); // 确保连接成功建立

            // 获取响应流,开始持续读取数据
            using (var stream = await response.Content.ReadAsStreamAsync(cancellationToken))
            using (var reader = new StreamReader(stream))
            {
                // 循环读取直到主动取消或连接断开
                while (!cancellationToken.IsCancellationRequested && !reader.EndOfStream)
                {
                    // 假设服务器每行返回一条JSON格式的告警数据,可根据实际格式调整读取逻辑
                    var rawData = await reader.ReadLineAsync(cancellationToken);
                    if (!string.IsNullOrEmpty(rawData))
                    {
                        // 这里处理你的热成像数据/告警逻辑
                        Console.WriteLine($"Received thermal alert: {rawData}");
                    }
                }
            }
        }
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("Thermal alert receiving stopped by cancellation");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Connection error occurred: {ex.Message}");
        // 可选:添加重连逻辑,只有当连接断开时才重新调用本方法建立新连接,不要重复发起GET请求
    }
}

关键说明

  1. HttpClient复用:HttpClient是线程安全的,必须作为单例或静态实例使用,避免频繁创建销毁导致连接池耗尽或持久连接被强制关闭。
  2. HttpCompletionOption.ResponseHeadersRead:这是处理持续数据流的核心配置,告诉HttpClient在收到响应头后立即返回,而不是等待服务器发送完所有数据。
  3. 流读取逻辑:示例中用ReadLineAsync处理每行一条数据的场景,如果厂商推送的是连续JSON块或其他格式,你需要调整为按字节块读取后再解析。
  4. 遵循厂商要求:一旦调用StartReceivingThermalAlerts建立连接,就持续从流中读取数据;只有当连接异常断开时,才重新调用该方法建立新连接,绝对不要重复发起GET请求。
  5. CancellationToken:用于主动停止接收流程,比如程序退出时可以通过取消令牌终止任务。

额外检查项

  • 确认摄像头服务使用HTTP 1.1协议(可通过抓包查看响应头的HTTP/1.1标识)
  • 检查响应头是否包含Transfer-Encoding: chunked,这是服务器支持持续数据推送的标志
  • 如果Digest认证出现问题,可通过抓包工具验证认证流程是否正确

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

火山引擎 最新活动