using System;
|
using System.Net.Sockets;
|
using System.Text;
|
using System.Threading;
|
using System.Threading.Tasks;
|
|
namespace ConnectionUtil
|
{
|
/// <summary>
|
/// TCP客户端包装类
|
/// </summary>
|
/// <summary>
|
/// TCP客户端包装类
|
/// </summary>
|
public class TcpClientWrapper : IDisposable
|
{
|
private System.Net.Sockets.TcpClient _client;
|
private NetworkStream _stream;
|
private readonly string _host;
|
private readonly int _port;
|
private bool _isConnected;
|
private readonly CancellationTokenSource _cts;
|
private Task _heartbeatTask;
|
private readonly SemaphoreSlim _sendReceiveLock;
|
|
/// <summary>
|
/// 初始化TCP客户端
|
/// </summary>
|
/// <param name="host">服务器地址</param>
|
/// <param name="port">服务器端口</param>
|
public TcpClientWrapper(string host = "127.0.0.1", int port = 6543)
|
{
|
_host = host;
|
_port = port;
|
_cts = new CancellationTokenSource();
|
_sendReceiveLock = new SemaphoreSlim(1, 1);
|
}
|
|
/// <summary>
|
/// 异步连接到服务器
|
/// </summary>
|
/// <returns>连接是否成功</returns>
|
public async Task<bool> ConnectAsync()
|
{
|
try
|
{
|
_client = new System.Net.Sockets.TcpClient();
|
await _client.ConnectAsync(_host, _port);
|
_stream = _client.GetStream();
|
_isConnected = true;
|
|
// 启动心跳任务
|
_heartbeatTask = StartHeartbeatAsync(_cts.Token);
|
|
Console.WriteLine($"成功连接到服务器 {_host}:{_port}");
|
return true;
|
}
|
catch (Exception ex)
|
{
|
Console.WriteLine($"连接服务器失败:{ex.Message}");
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// 同步连接到服务器
|
/// </summary>
|
/// <returns>连接是否成功</returns>
|
public bool Connect()
|
{
|
try
|
{
|
_client = new System.Net.Sockets.TcpClient();
|
_client.Connect(_host, _port);
|
_stream = _client.GetStream();
|
_isConnected = true;
|
|
// 启动心跳任务
|
_heartbeatTask = StartHeartbeatAsync(_cts.Token);
|
return true;
|
}
|
catch (Exception ex)
|
{
|
Console.WriteLine($"连接服务器失败:{ex.Message}");
|
return false;
|
}
|
}
|
|
/// <summary>
|
/// 启动心跳检测
|
/// </summary>
|
private async Task StartHeartbeatAsync(CancellationToken token)
|
{
|
while (!token.IsCancellationRequested && _isConnected)
|
{
|
try
|
{
|
await Task.Delay(20000, token); // 20秒发送一次心跳
|
if (_isConnected)
|
{
|
await SendMessageAsync("ping");
|
}
|
}
|
catch (OperationCanceledException)
|
{
|
break;
|
}
|
catch (Exception)
|
{
|
_isConnected = false;
|
break;
|
}
|
}
|
}
|
|
/// <summary>
|
/// 发送消息并接收响应
|
/// </summary>
|
/// <typeparam name="T">响应数据类型</typeparam>
|
/// <param name="data">要发送的数据对象</param>
|
/// <param name="timeout">超时时间</param>
|
/// <returns>服务器响应数据</returns>
|
public async Task<string> SendMessageAsync(string message, TimeSpan? timeout = null)
|
{
|
if (!_isConnected)
|
{
|
throw new InvalidOperationException("未连接到服务器");
|
}
|
|
TimeSpan actualTimeout = timeout ?? TimeSpan.FromSeconds(30);
|
|
if (!await _sendReceiveLock.WaitAsync(actualTimeout))
|
{
|
throw new TimeoutException("等待发送超时");
|
}
|
|
try
|
{
|
byte[] messageBytes = Encoding.UTF8.GetBytes(message + "\r\n");
|
|
// 发送消息
|
await _stream.WriteAsync(messageBytes, 0, messageBytes.Length);
|
|
// 接收响应
|
byte[] buffer = new byte[1024];
|
StringBuilder response = new StringBuilder();
|
int bytesRead;
|
|
CancellationTokenSource cts = new CancellationTokenSource(actualTimeout);
|
|
try
|
{
|
// 读取直到遇到换行符
|
while ((bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
|
{
|
string received = Encoding.UTF8.GetString(buffer, 0, bytesRead);
|
response.Append(received);
|
|
if (received.EndsWith("\r\n"))
|
{
|
break;
|
}
|
|
if (cts.Token.IsCancellationRequested)
|
{
|
throw new TimeoutException("接收响应超时");
|
}
|
}
|
}
|
finally
|
{
|
cts.Dispose();
|
}
|
|
string jsonResponse = response.ToString().TrimEnd('\r', '\n');
|
Console.WriteLine($"收到服务器响应:{jsonResponse}");
|
|
// 反序列化响应
|
return jsonResponse;
|
}
|
catch (Exception ex)
|
{
|
Console.WriteLine($"发送消息失败:{ex.Message}");
|
_isConnected = false;
|
throw;
|
}
|
finally
|
{
|
_sendReceiveLock.Release();
|
}
|
}
|
|
/// <summary>
|
/// 同步发送消息并接收响应
|
/// </summary>
|
/// <typeparam name="T">响应数据类型</typeparam>
|
/// <param name="data">要发送的数据对象</param>
|
/// <param name="timeout">超时时间</param>
|
/// <returns>服务器响应数据</returns>
|
public string SendMessage(string message, TimeSpan? timeout = null)
|
{
|
timeout = timeout ?? TimeSpan.FromSeconds(30);
|
|
try
|
{
|
// 使用 Task.Run 来执行异步操作,并等待结果
|
return Task.Run(() => SendMessageAsync(message, timeout)).Result;
|
}
|
catch (AggregateException ae)
|
{
|
// 解包异常
|
throw ae.InnerException;
|
}
|
}
|
|
/// <summary>
|
/// 检查是否已连接
|
/// </summary>
|
public bool IsConnected
|
{
|
get { return _isConnected; }
|
}
|
|
/// <summary>
|
/// 释放资源
|
/// </summary>
|
public void Dispose()
|
{
|
_cts.Cancel();
|
_isConnected = false;
|
if (_stream != null)
|
{
|
_stream.Dispose();
|
}
|
if (_client != null)
|
{
|
_client.Dispose();
|
}
|
_cts.Dispose();
|
if (_sendReceiveLock != null)
|
{
|
_sendReceiveLock.Dispose();
|
}
|
}
|
|
/// <summary>
|
/// 关闭连接
|
/// </summary>
|
public void Close()
|
{
|
Dispose();
|
}
|
}
|
}
|