心跳策略(Heartbeat) 和 Ping/Echo 策略
一、心跳策略(Heartbeat)
原理:客户端定期向服务端发送心跳包,服务端监控客户端存活状态,超时未收到心跳则判定客户端离线
- 服务端代码
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Threading;
public class HeartbeatServer
{
private TcpListener _listener;
private Dictionary<string, DateTime> _clients = new Dictionary<string, DateTime>();
public void Start(int port)
{_listener = new TcpListener(IPAddress.Any, port);_listener.Start();Console.WriteLine("Heartbeat Server started...");// 启动心跳监控线程new Thread(MonitorClients).Start();while (true){var client = _listener.AcceptTcpClient();new Thread(() => HandleClient(client)).Start();}
}private void HandleClient(TcpClient client)
{string clientId = client.Client.RemoteEndPoint.ToString();Console.WriteLine($"Client connected: {clientId}");using (var stream = client.GetStream())using (var reader = new StreamReader(stream)){try{while (true){var message = reader.ReadLine();if (message == "HEARTBEAT"){lock (_clients){_clients[clientId] = DateTime.Now; // 更新最后心跳时间}}}}catch{Console.WriteLine($"Client disconnected: {clientId}");lock (_clients) { _clients.Remove(clientId); }client.Close();}}
}private void MonitorClients()
{while (true){Thread.Sleep(5000); // 每5秒检查一次lock (_clients){foreach (var client in _clients.Keys.ToList()){if ((DateTime.Now - _clients[client]).TotalSeconds > 10) // 超时10秒{Console.WriteLine($"Client timeout: {client}");_clients.Remove(client);}}}}
}
}
- 客户端代码
using System;
using System.Net.Sockets;
using System.Threading;
public class HeartbeatClient
{
private TcpClient _client;
private Thread _heartbeatThread;
public void Connect(string serverIp, int port)
{_client = new TcpClient();_client.Connect(serverIp, port);Console.WriteLine("Connected to server.");// 启动心跳线程_heartbeatThread = new Thread(SendHeartbeat);_heartbeatThread.Start();
}private void SendHeartbeat()
{var writer = new StreamWriter(_client.GetStream()) { AutoFlush = true };while (true){try{writer.WriteLine("HEARTBEAT");Thread.Sleep(2000); // 每2秒发送一次}catch{Console.WriteLine("Connection lost.");break;}}
}
}
二、Ping/Echo 策略
原理:客户端主动发送 Ping 请求,服务端必须回复 Echo 响应,超时未响应则判定服务端离线。
- 客户端代码
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class PingEchoClient
{
private TcpClient _client;
private Timer _pingTimer;
public void Connect(string ip, int port)
{_client = new TcpClient();_client.Connect(ip, port);Console.WriteLine("Connected to server.");// 每2秒发送一次Ping_pingTimer = new Timer(SendPing, null, 0, 2000);
}private void SendPing(object state)
{NetworkStream stream = _client.GetStream();byte[] pingMsg = Encoding.UTF8.GetBytes("PING");byte[] buffer = new byte[1024];try{// 发送Ping并等待Echo(超时1秒)stream.Write(pingMsg, 0, pingMsg.Length);Console.WriteLine("Sent PING.");var cts = new CancellationTokenSource(1000); // 超时1秒int bytesRead = stream.ReadAsync(buffer, 0, buffer.Length, cts.Token).Result;string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);if (response == "ECHO"){Console.WriteLine("Received ECHO.");}}catch (Exception ex){Console.WriteLine($"Server timeout: {ex.Message}");Environment.Exit(1);}
}public static void Main()
{var client = new PingEchoClient();client.Connect("127.0.0.1", 8081);Thread.Sleep(Timeout.Infinite); // 保持连接
}
}
2.服务端代码
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class PingEchoServer
{
private TcpListener _listener;
private bool _isRunning = true;
public void Start(int port)
{_listener = new TcpListener(IPAddress.Any, port);_listener.Start();Console.WriteLine("Ping/Echo Server started...");while (_isRunning){TcpClient client = _listener.AcceptTcpClient();ThreadPool.QueueUserWorkItem(HandleClient, client);}
}private void HandleClient(object obj)
{TcpClient client = (TcpClient)obj;NetworkStream stream = client.GetStream();byte[] buffer = new byte[1024];try{while (true){int bytesRead = stream.Read(buffer, 0, buffer.Length);string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);if (message == "PING"){byte[] response = Encoding.UTF8.GetBytes("ECHO");stream.Write(response, 0, response.Length);Console.WriteLine("Responded to PING.");}}}catch (Exception ex){Console.WriteLine($"Client disconnected: {ex.Message}");client.Close();}
}public static void Main()
{var server = new PingEchoServer();server.Start(8081);
}
}
三、两种策略对比
四、运行说明
心跳策略
启动 HeartbeatServer 和 HeartbeatClient。
停止服务端后,客户端将在5秒内检测到超时。
Ping/Echo策略
启动 PingEchoServer 和 PingEchoClient。
停止服务端后,客户端下一次Ping会触发超时。
五、扩展建议
心跳策略优化:可结合 UDP 广播减少连接数,或使用 WebSocket 协议。
Ping/Echo增强:添加序列号或时间戳,防止重放攻击。
集群化:将客户端扩展为多节点,服务端通过负载均衡(如Nginx)分发请求。