导读:本期聚焦于小伙伴创作的《C#怎么实现TCP心跳检测 C#如何在Socket长连接中实现心跳包检测和断线自动重连》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#怎么实现TCP心跳检测 C#如何在Socket长连接中实现心跳包检测和断线自动重连》有用,将其分享出去将是对创作者最好的鼓励。

在C#的Socket长连接开发中,网络波动、客户端异常退出等情况都可能导致连接无声断开,此时如果没有心跳检测机制,服务端和客户端都无法及时感知连接失效,会造成资源浪费和业务异常。心跳检测通过定时发送小数据包并等待响应,来确认连接是否存活,结合断线自动重连机制,能大幅提升长连接应用的可靠性。

C#怎么实现TCP心跳检测 C#如何在Socket长连接中实现心跳包检测和断线自动重连

TCP心跳检测的核心逻辑

TCP心跳检测的本质是通信双方约定一个固定的时间间隔,由一方或双方定时发送特定格式的数据包(即心跳包),接收方收到后返回对应的响应包。如果发送方在设定的超时时间内没有收到响应,就判定当前连接已经断开。

心跳包的设计不需要携带复杂的业务数据,通常只需要一个固定的标识即可,比如约定心跳包的内容为Heartbeat,响应包内容为Heartbeat_ACK,这样可以减少网络传输开销。

客户端实现心跳检测的步骤

  • 建立Socket连接后,启动一个独立的线程或定时器,按照设定的间隔发送心跳包
  • 发送心跳包后记录发送时间,同时启动超时计时
  • 收到服务端的响应包后,重置超时计时器,更新最后收到响应的时间
  • 如果超时时间内没有收到响应,触发断线处理逻辑

服务端实现心跳检测的步骤

  • 接收客户端连接后,记录客户端的最后活跃时间
  • 每次收到客户端的任意数据包(包括心跳包和业务包),都更新该客户端的最后活跃时间
  • 启动一个定时扫描线程,遍历所有连接的客户端,判断当前时间与最后活跃时间的差值是否超过设定的超时阈值
  • 如果超过阈值,判定客户端连接失效,主动关闭对应的Socket并释放资源

断线自动重连的实现思路

断线自动重连需要在检测到连接断开后,按照设定的策略重新尝试建立连接,避免频繁重试对系统造成压力。常见的重试策略是指数退避,即每次重试的间隔时间逐步增加,比如第一次重试间隔1秒,第二次2秒,第三次4秒,直到达到最大重试间隔后保持固定间隔重试。

重连成功后,需要重新启动心跳检测线程,恢复正常的通信逻辑,同时可以根据业务需求同步之前未完成的操作。

完整示例代码

客户端实现代码

以下是C#客户端实现心跳检测和断线自动重连的完整代码:

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class TcpClientWithHeartbeat
{
    // 服务端IP和端口
    private string serverIp = "127.0.0.1";
    private int serverPort = 9000;
    // 心跳发送间隔,单位毫秒
    private int heartbeatInterval = 3000;
    // 心跳超时时间,单位毫秒
    private int heartbeatTimeout = 5000;
    // 最大重连间隔,单位毫秒
    private int maxReconnectInterval = 30000;
    // 当前重连间隔
    private int currentReconnectInterval = 1000;

    private Socket clientSocket;
    private Thread heartbeatThread;
    private Thread receiveThread;
    private bool isConnected = false;
    private DateTime lastHeartbeatResponseTime;
    private ManualResetEvent reconnectEvent = new ManualResetEvent(false);

    // 启动客户端
    public void Start()
    {
        ConnectToServer();
        // 启动重连监控线程
        Thread reconnectThread = new Thread(ReconnectLoop);
        reconnectThread.IsBackground = true;
        reconnectThread.Start();
    }

    // 连接服务端
    private void ConnectToServer()
    {
        try
        {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clientSocket.Connect(serverIp, serverPort);
            isConnected = true;
            lastHeartbeatResponseTime = DateTime.Now;
            Console.WriteLine("连接服务端成功");

            // 启动心跳发送线程
            heartbeatThread = new Thread(SendHeartbeat);
            heartbeatThread.IsBackground = true;
            heartbeatThread.Start();

            // 启动接收线程
            receiveThread = new Thread(ReceiveData);
            receiveThread.IsBackground = true;
            receiveThread.Start();

            // 重置重连间隔
            currentReconnectInterval = 1000;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"连接服务端失败:{ex.Message}");
            isConnected = false;
        }
    }

    // 发送心跳包
    private void SendHeartbeat()
    {
        while (isConnected)
        {
            try
            {
                // 发送心跳包
                byte[] heartbeatData = Encoding.UTF8.GetBytes("Heartbeat");
                clientSocket.Send(heartbeatData);
                Console.WriteLine("发送心跳包");

                // 检查是否超时
                TimeSpan timeSinceLastResponse = DateTime.Now - lastHeartbeatResponseTime;
                if (timeSinceLastResponse.TotalMilliseconds > heartbeatTimeout)
                {
                    Console.WriteLine("心跳超时,判定连接断开");
                    HandleDisconnect();
                }

                Thread.Sleep(heartbeatInterval);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发送心跳包异常:{ex.Message}");
                HandleDisconnect();
            }
        }
    }

    // 接收数据
    private void ReceiveData()
    {
        byte[] buffer = new byte[1024];
        while (isConnected)
        {
            try
            {
                int length = clientSocket.Receive(buffer);
                if (length == 0)
                {
                    Console.WriteLine("接收到空数据,判定连接断开");
                    HandleDisconnect();
                    break;
                }

                string receiveStr = Encoding.UTF8.GetString(buffer, 0, length);
                // 判断是否为心跳响应
                if (receiveStr == "Heartbeat_ACK")
                {
                    lastHeartbeatResponseTime = DateTime.Now;
                    Console.WriteLine("收到心跳响应");
                }
                else
                {
                    // 处理业务数据
                    Console.WriteLine($"收到业务数据:{receiveStr}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"接收数据异常:{ex.Message}");
                HandleDisconnect();
                break;
            }
        }
    }

    // 处理断线
    private void HandleDisconnect()
    {
        if (!isConnected) return;
        isConnected = false;
        try
        {
            clientSocket.Close();
        }
        catch { }
        // 通知重连线程进行重连
        reconnectEvent.Set();
    }

    // 重连循环
    private void ReconnectLoop()
    {
        while (true)
        {
            reconnectEvent.WaitOne();
            reconnectEvent.Reset();
            Console.WriteLine($"开始重连,当前重连间隔:{currentReconnectInterval}毫秒");
            Thread.Sleep(currentReconnectInterval);
            ConnectToServer();
            if (isConnected)
            {
                // 重连成功,重置重连间隔
                currentReconnectInterval = 1000;
            }
            else
            {
                // 重连失败,增加重连间隔,不超过最大值
                currentReconnectInterval = Math.Min(currentReconnectInterval * 2, maxReconnectInterval);
            }
        }
    }

    // 发送业务数据
    public void SendBusinessData(string data)
    {
        if (!isConnected) return;
        try
        {
            byte[] sendData = Encoding.UTF8.GetBytes(data);
            clientSocket.Send(sendData);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发送业务数据异常:{ex.Message}");
            HandleDisconnect();
        }
    }
}

服务端实现代码

以下是C#服务端实现心跳检测的代码:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class TcpServerWithHeartbeat
{
    // 监听端口
    private int listenPort = 9000;
    // 心跳超时时间,单位毫秒
    private int heartbeatTimeout = 10000;
    // 客户端最后活跃时间字典
    private Dictionary<Socket, DateTime> clientLastActiveTime = new Dictionary<Socket, DateTime>();
    private Socket serverSocket;
    private bool isRunning = false;

    // 启动服务端
    public void Start()
    {
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, listenPort));
        serverSocket.Listen(100);
        isRunning = true;
        Console.WriteLine($"服务端启动,监听端口:{listenPort}");

        // 启动客户端连接接收线程
        Thread acceptThread = new Thread(AcceptClient);
        acceptThread.IsBackground = true;
        acceptThread.Start();

        // 启动心跳检测线程
        Thread heartbeatCheckThread = new Thread(CheckClientHeartbeat);
        heartbeatCheckThread.IsBackground = true;
        heartbeatCheckThread.Start();
    }

    // 接收客户端连接
    private void AcceptClient()
    {
        while (isRunning)
        {
            try
            {
                Socket clientSocket = serverSocket.Accept();
                Console.WriteLine($"客户端连接成功:{clientSocket.RemoteEndPoint}");
                // 记录客户端最后活跃时间
                clientLastActiveTime[clientSocket] = DateTime.Now;

                // 启动客户端数据接收线程
                Thread receiveThread = new Thread(ReceiveClientData);
                receiveThread.IsBackground = true;
                receiveThread.Start(clientSocket);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"接收客户端连接异常:{ex.Message}");
            }
        }
    }

    // 接收客户端数据
    private void ReceiveClientData(object obj)
    {
        Socket clientSocket = obj as Socket;
        byte[] buffer = new byte[1024];
        while (true)
        {
            try
            {
                int length = clientSocket.Receive(buffer);
                if (length == 0)
                {
                    Console.WriteLine($"客户端断开连接:{clientSocket.RemoteEndPoint}");
                    RemoveClient(clientSocket);
                    break;
                }

                // 更新客户端最后活跃时间
                clientLastActiveTime[clientSocket] = DateTime.Now;
                string receiveStr = Encoding.UTF8.GetString(buffer, 0, length);

                // 判断是否为心跳包
                if (receiveStr == "Heartbeat")
                {
                    // 返回心跳响应
                    byte[] responseData = Encoding.UTF8.GetBytes("Heartbeat_ACK");
                    clientSocket.Send(responseData);
                    Console.WriteLine($"收到客户端心跳包,已返回响应:{clientSocket.RemoteEndPoint}");
                }
                else
                {
                    // 处理业务数据
                    Console.WriteLine($"收到客户端业务数据:{receiveStr},来自:{clientSocket.RemoteEndPoint}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"接收客户端数据异常:{ex.Message},客户端:{clientSocket.RemoteEndPoint}");
                RemoveClient(clientSocket);
                break;
            }
        }
    }

    // 检测客户端心跳
    private void CheckClientHeartbeat()
    {
        while (isRunning)
        {
            Thread.Sleep(5000);
            List<Socket> needRemoveClients = new List<Socket>();
            DateTime now = DateTime.Now;
            foreach (var item in clientLastActiveTime)
            {
                TimeSpan timeSinceLastActive = now - item.Value;
                if (timeSinceLastActive.TotalMilliseconds > heartbeatTimeout)
                {
                    Console.WriteLine($"客户端心跳超时,断开连接:{item.Key.RemoteEndPoint}");
                    needRemoveClients.Add(item.Key);
                }
            }

            foreach (var client in needRemoveClients)
            {
                RemoveClient(client);
            }
        }
    }

    // 移除客户端
    private void RemoveClient(Socket clientSocket)
    {
        if (clientLastActiveTime.ContainsKey(clientSocket))
        {
            clientLastActiveTime.Remove(clientSocket);
        }
        try
        {
            clientSocket.Close();
        }
        catch { }
    }
}

注意事项

  • 心跳间隔和超时时间需要根据实际业务场景调整,间隔过短会增加网络开销,过长会导致断线感知不及时
  • 重连策略要避免无限快速重试,否则会在网络异常时占用大量系统资源
  • 多线程操作共享资源时需要注意线程安全,比如客户端字典的读写需要加锁
  • Socket操作需要做好异常处理,避免异常导致程序崩溃
实际开发中可以根据需求扩展心跳包的内容,比如加入客户端标识、时间戳等信息,方便排查问题。如果使用的是异步Socket,可以将心跳逻辑和接收逻辑整合到异步回调中,减少线程开销。

C#TCP心跳检测Socket长连接断线自动重连修改时间:2026-07-03 18:12:47

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。