服务器
using BarrageGrab;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Lyx {
class Server
{
private TcpListener listener;
private ConcurrentDictionary<TcpClient, DateTime> clients = new ConcurrentDictionary<TcpClient, DateTime>();
private CancellationTokenSource cts = new CancellationTokenSource();
public void Start(int port)
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
Console.WriteLine($"服务器已启动,监听端口 {port}...");
new Thread(AcceptClients) { IsBackground = true }.Start();
new Thread(CheckHeartbeats) { IsBackground = true }.Start();
new Thread(HandleConsoleInput) { IsBackground = true }.Start();
}
private void AcceptClients()
{
try
{
while (!cts.Token.IsCancellationRequested)
{
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("新客户端连接:" + client.Client.RemoteEndPoint);
clients.TryAdd(client, DateTime.Now);
new Thread(() => HandleClient(client)) { IsBackground = true }.Start();
}
}
catch (SocketException) { } // 监听器被停止时正常退出
}
private void HandleClient(TcpClient client)
{
NetworkStream stream = null;
try
{
stream = client.GetStream();
byte[] buffer = new byte[1024];
while (!cts.Token.IsCancellationRequested)
{
int bytesRead;
lock (client) // 同步网络流访问
{
if (!stream.DataAvailable)
{
Thread.Sleep(100);
continue;
}
bytesRead = stream.Read(buffer, 0, buffer.Length);
}
if (bytesRead <= 0) break;
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine($"收到消息: {message}");
if (message == "heartbeat")
{
clients.AddOrUpdate(client, DateTime.Now, (_, __) => DateTime.Now);
SendMessage(client, "heartbeat");
Logger.PrintColor($"服务器发送心跳: {message} ,给客户端成功:{client.Client.RemoteEndPoint}", ConsoleColor.Yellow);
continue;
}
//SendMessage(client, "服务器收到: " + message);
}
}
catch (Exception ex) { Console.WriteLine($"客户端错误: {ex.Message}"); }
finally
{
if (client.Connected )
{
Console.WriteLine("客户端断开:" + client.Client.RemoteEndPoint);
clients.TryRemove(client, out _);
client.Close();
stream?.Close();
}
}
}
public void BroadcastMessage(string message)
{
byte[] data = Encoding.UTF8.GetBytes("服务器广播: " + message);
foreach (var client in clients.Keys.ToArray())
{
try
{
lock (client)
{
client.GetStream().Write(data, 0, data.Length);
}
}
catch { }
}
Console.WriteLine("广播消息已发送");
}
public void SendMessage(TcpClient client, string message)
{
if (!clients.ContainsKey(client)) return;
byte[] data = Encoding.UTF8.GetBytes(message);
try
{
lock (client) // 同步网络流访问
{
client.GetStream().Write(data, 0, data.Length);
}
Console.WriteLine($"消息发送成功 -> {client.Client.RemoteEndPoint}: {message}");
}
catch
{
Console.WriteLine("消息发送失败");
}
}
private void HandleConsoleInput()
{
while (!cts.Token.IsCancellationRequested)
{
string input = Console.ReadLine();
if (input?.ToLower() == "exit")
{
Stop();
break;
}
else if (!string.IsNullOrWhiteSpace(input))
{
BroadcastMessage(input);
}
}
}
private void CheckHeartbeats()
{
while (!cts.Token.IsCancellationRequested)
{
Thread.Sleep(5000);
DateTime now = DateTime.Now;
foreach (var client in clients.Keys.ToArray())
{
if (clients.TryGetValue(client, out DateTime last) &&
(now - last).TotalSeconds > 10)
{
Console.WriteLine("客户端超时断开:" + client.Client.RemoteEndPoint);
clients.TryRemove(client, out _);
client.Close();
}
}
}
}
public void Stop()
{
cts.Cancel();
listener.Stop();
foreach (var client in clients.Keys.ToArray())
{
client.Close();
clients.TryRemove(client, out _);
}
Console.WriteLine("服务器已停止");
}
public void Main()
{
Server server = new Server();
server.Start(54621);
}
}
}
客户端
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class SocketClient : MonoBehaviour
{
private TcpClient client;
private NetworkStream stream;
private Thread receiveThread;
private bool isConnected = false;
private string serverIP = "127.0.0.1"; // 服务器IP地址
private int serverPort = 54621; // 服务器端口
private float heartbeatTimeout = 5f; // 心跳超时时间
private float heartbeatInterval = 0.5f; // 心跳发送间隔时间
private float lastHeartbeatTime;
private float lastSendHeartbeatTime;
private bool updateHeartbeat = false; // 标志位,用于通知主线程更新心跳时间
private int reconnectAttempts = 0; // 重连尝试次数
private const int maxReconnectAttempts = 3; // 最大重连次数
private const float reconnectInterval = 2f; // 重连间隔时间
void Start()
{
ConnectToServer();
}
void Update()
{
// 检查是否需要更新心跳时间
if (updateHeartbeat)
{
lastHeartbeatTime = Time.time;
updateHeartbeat = false;
}
// 检查心跳超时
if (isConnected && Time.time - lastHeartbeatTime > heartbeatTimeout)
{
Debug.Log("Heartbeat timeout, disconnecting...");
Disconnect();
}
// 定时发送心跳消息
if (isConnected && Time.time - lastSendHeartbeatTime > heartbeatInterval)
{
SendData("heartbeat");
lastSendHeartbeatTime = Time.time;
}
}
void ConnectToServer()
{
try
{
client = new TcpClient(serverIP, serverPort);
stream = client.GetStream();
isConnected = true;
lastHeartbeatTime = Time.time;
lastSendHeartbeatTime = Time.time;
reconnectAttempts = 0; // 重置重连尝试次数
receiveThread = new Thread(new ThreadStart(ReceiveData));
receiveThread.IsBackground = true;
receiveThread.Start();
Debug.Log("Connected to server.");
}
catch (Exception e)
{
Debug.LogError("Error connecting to server: " + e.Message);
TryReconnect();
}
}
void ReceiveData()
{
byte[] buffer = new byte[1024];
while (isConnected)
{
try
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
if (receivedMessage != null)
{
Debug.Log("Received from server: " + receivedMessage);
// 如果是心跳响应,通知主线程更新心跳时间
if (receivedMessage.Equals("heartbeat"))
{
updateHeartbeat = true;
}
}
}
}
catch (Exception e)
{
Debug.LogError("Error receiving data: " + e.Message);
Disconnect();
break;
}
}
}
public void SendData(string message)
{
if (isConnected)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
stream.Write(data, 0, data.Length);
Debug.Log("Sent to server: " + message);
}
catch (Exception e)
{
Debug.LogError("Error sending data: " + e.Message);
Disconnect();
}
}
}
void Disconnect()
{
if (isConnected)
{
isConnected = false;
if (receiveThread != null && receiveThread.IsAlive)
receiveThread.Abort();
if (stream != null)
stream.Close();
if (client != null)
client.Close();
Debug.Log("Disconnected from server.");
// 尝试重连
TryReconnect();
}
}
void TryReconnect()
{
Debug.Log("触发重连机制");
if (reconnectAttempts < maxReconnectAttempts)
{
reconnectAttempts++;
Debug.Log($"Attempting to reconnect ({reconnectAttempts}/{maxReconnectAttempts})...");
Invoke("ConnectToServer", reconnectInterval); // 2秒后重连
}
else
{
Debug.Log("Max reconnection attempts reached. Giving up.");
}
}
void OnDestroy()
{
Disconnect();
}
}