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

.NET Core中Socket连接半小时至两小时后无日志断开,求永久稳定方案

解决.NET Core Socket连接无日志自动断开问题,实现永久稳定连接

现有代码的核心问题

  1. 单连接仅处理一次数据:当前代码在接受连接后仅调用一次Receive,之后直接回到监听循环,既无法接收设备后续发送的数据,也无法感知连接是否存活。
  2. 同步阻塞+无异常捕获:同步Receive会阻塞线程,且未处理Socket操作可能抛出的SocketException等异常,一旦出现异常会直接终止整个监听流程,且无日志记录异常原因。
  3. 未启用TCP保活机制:长时间无数据传输时,中间网络设备(路由器、防火墙)会主动回收空闲连接,导致连接无预警断开。
  4. 无心跳交互逻辑:未与设备约定心跳机制,无法主动检测连接状态,也无法维持连接活跃。

修复方案与代码修改

1. 重构连接处理逻辑:异步独立处理每个连接

将每个连接的数据监听逻辑抽离为独立异步任务,避免阻塞主监听循环,同时持续处理该连接的后续数据:

public async Task StartListening()
{
    _logService.CreateLogCmd($"StartListening get ip&&port: {ServerIP} {Port}", "StartListening");

    var tcp = new TcpListener(IPAddress.Parse(ServerIP), Port);
    tcp.Start();
    _logService.CreateLogCmd($"tcpStart ip&&port: {ServerIP} {Port}", "StartListening");

    try
    {
        while (true)
        {
            var socket = await tcp.AcceptSocketAsync();
            _logService.CreateLogCmd($"AcceptSocket from {socket.RemoteEndPoint}", "StartListening");
            
            // 为每个连接启动独立异步任务处理数据,不阻塞监听循环
            _ = HandleClientConnectionAsync(socket);
        }
    }
    catch (Exception ex)
    {
        _logService.CreateLogCmd($"Listening failed: {ex.Message}", "StartListening");
        tcp.Stop();
    }
}

private async Task HandleClientConnectionAsync(Socket socket)
{
    var remoteEndpoint = socket.RemoteEndPoint.ToString();
    _logService.CreateLogCmd($"Start handling connection: {remoteEndpoint}", "HandleClientConnection");

    // 启用TCP KeepAlive,系统自动发送心跳维持连接
    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
    // 配置KeepAlive参数(根据实际网络调整)
    const int keepAliveTime = 60000; // 1分钟无数据则开始发送心跳
    const int keepAliveInterval = 10000; // 每10秒发送一次心跳
    byte[] keepAliveBytes = BitConverter.GetBytes(1);
    keepAliveBytes = keepAliveBytes.Concat(BitConverter.GetBytes(keepAliveTime)).ToArray();
    keepAliveBytes = keepAliveBytes.Concat(BitConverter.GetBytes(keepAliveInterval)).ToArray();
    socket.IOControl(IOControlCode.KeepAliveValues, keepAliveBytes, null);

    socket.ReceiveBufferSize = MAXBUFFERSIZE;
    socket.SendBufferSize = MAXBUFFERSIZE;

    byte[] buffer = new byte[MAXBUFFERSIZE];
    try
    {
        while (socket.Connected)
        {
            // 异步接收数据,避免阻塞
            int receivedBytes = await socket.ReceiveAsync(buffer, SocketFlags.None);
            if (receivedBytes == 0)
            {
                // 收到0字节表示连接已断开
                _logService.CreateLogCmd($"Connection closed by client: {remoteEndpoint}", "HandleClientConnection");
                break;
            }

            // 处理接收到的数据(截取实际收到的字节数,避免多余空数据)
            byte[] actualData = new byte[receivedBytes];
            Array.Copy(buffer, actualData, receivedBytes);
            Analysis(actualData, socket);
        }
    }
    catch (SocketException ex)
    {
        _logService.CreateLogCmd($"Socket error on {remoteEndpoint}: {ex.Message} (ErrorCode: {ex.ErrorCode})", "HandleClientConnection");
    }
    catch (Exception ex)
    {
        _logService.CreateLogCmd($"Unexpected error on {remoteEndpoint}: {ex.Message}", "HandleClientConnection");
    }
    finally
    {
        // 确保Socket资源被释放
        if (socket.Connected)
        {
            try
            {
                socket.Shutdown(SocketShutdown.Both);
            }
            catch { }
        }
        socket.Close();
        socket.Dispose();
        _logService.CreateLogCmd($"Connection disposed: {remoteEndpoint}", "HandleClientConnection");
    }
}

2. 实现心跳交互(可选,根据设备协议调整)

如果设备支持,约定心跳包格式,定期发送/接收心跳以主动检测连接状态:

private async Task SendHeartbeatAsync(Socket socket)
{
    byte[] heartbeatPacket = GetHeartbeatPacket(); // 根据设备协议生成心跳包
    await socket.SendAsync(heartbeatPacket, SocketFlags.None);
    _logService.CreateLogCmd("Heartbeat sent", "SendHeartbeat");
}

3. 关键配置说明

  • TCP KeepAlive:通过SetSocketOption和IOControl启用系统级TCP保活,让操作系统自动发送心跳包,避免中间网络设备断开空闲连接。
  • 异步操作:使用ReceiveAsync替代同步Receive,避免线程阻塞,提升程序并发能力。
  • 异常处理:捕获SocketException等异常,记录详细错误信息,确保单个连接的异常不会影响整个监听服务。
  • 资源释放:在finally块中关闭并释放Socket资源,避免资源泄漏。

额外排查方向

  • 检查设备端是否有连接超时逻辑:确认设备是否会主动断开空闲连接,如有则需要同步心跳机制。
  • 排查网络环境:检查服务器与设备之间的防火墙、路由器是否有空闲连接回收策略,必要时调整超时时间。
  • 日志增强:在Analysis方法和Socket操作的关键节点添加更详细的日志,便于定位问题。

内容的提问来源于stack exchange,提问作者Soroush Gorgin Pour

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:50:43