using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Serilog;
namespace Protocol376Simulator.Services
{
///
/// 网络服务类,负责TCP连接和网络通信
///
public class NetworkService : IDisposable
{
private readonly string _serverAddress;
private readonly int _serverPort;
private TcpClient _client;
private NetworkStream _stream;
private CancellationTokenSource _cancellationTokenSource;
private readonly string _deviceIdentifier;
///
/// 当接收到消息时触发
///
public event EventHandler MessageReceived;
///
/// 当连接状态改变时触发
///
public event EventHandler ConnectionStatusChanged;
///
/// 当发生错误时触发
///
public event EventHandler ErrorOccurred;
///
/// 连接状态枚举
///
public enum ConnectionStatus
{
Disconnected,
Connecting,
Connected,
Failed,
Reconnecting
}
///
/// 是否连接到服务器
///
public bool IsConnected => _client != null && _client.Connected;
///
/// 构造函数
///
/// 服务器地址
/// 服务器端口
/// 设备标识(用于日志)
public NetworkService(string serverAddress, int serverPort, string deviceIdentifier)
{
_serverAddress = serverAddress;
_serverPort = serverPort;
_deviceIdentifier = deviceIdentifier;
_cancellationTokenSource = new CancellationTokenSource();
}
///
/// 连接到服务器
///
public async Task ConnectAsync()
{
try
{
// 如果已有连接,先断开
await DisconnectAsync();
// 重置取消标记
_cancellationTokenSource = new CancellationTokenSource();
// 触发状态改变事件
ConnectionStatusChanged?.Invoke(this, ConnectionStatus.Connecting);
// 连接服务器
_client = new TcpClient();
Log.Information("{DeviceId} 正在连接到服务器 {ServerAddress}:{ServerPort}...",
_deviceIdentifier, _serverAddress, _serverPort);
await _client.ConnectAsync(_serverAddress, _serverPort);
_stream = _client.GetStream();
Log.Information("{DeviceId} 已成功连接到服务器", _deviceIdentifier);
// 触发状态改变事件
ConnectionStatusChanged?.Invoke(this, ConnectionStatus.Connected);
// 启动接收消息任务
_ = StartReceiveMessagesAsync(_cancellationTokenSource.Token);
}
catch (Exception ex)
{
Log.Error(ex, "{DeviceId} 连接失败: {ErrorMessage}", _deviceIdentifier, ex.Message);
// 触发错误事件
ErrorOccurred?.Invoke(this, ex);
// 触发状态改变事件
ConnectionStatusChanged?.Invoke(this, ConnectionStatus.Failed);
// 确保清理资源
_client?.Dispose();
_client = null;
_stream = null;
// 重新抛出异常,让调用者处理
throw;
}
}
///
/// 断开连接
///
public async Task DisconnectAsync()
{
try
{
// 取消所有后台任务
_cancellationTokenSource?.Cancel();
// 关闭网络流和客户端
_stream?.Close();
_client?.Close();
// 等待一段时间确保资源释放
await Task.Delay(100);
// 触发状态改变事件
ConnectionStatusChanged?.Invoke(this, ConnectionStatus.Disconnected);
Log.Information("{DeviceId} 已断开连接", _deviceIdentifier);
}
catch (Exception ex)
{
Log.Error(ex, "{DeviceId} 断开连接时发生错误: {ErrorMessage}", _deviceIdentifier, ex.Message);
ErrorOccurred?.Invoke(this, ex);
}
finally
{
_stream = null;
_client = null;
}
}
///
/// 发送消息
///
/// 要发送的消息字节数组
public async Task SendMessageAsync(byte[] message)
{
if (!IsConnected)
{
throw new InvalidOperationException("未连接到服务器,无法发送消息");
}
try
{
await _stream.WriteAsync(message, 0, message.Length);
await _stream.FlushAsync();
Log.Debug("{DeviceId} 发送消息: {HexMessage}",
_deviceIdentifier, BitConverter.ToString(message).Replace("-", " "));
}
catch (Exception ex)
{
Log.Error(ex, "{DeviceId} 发送消息失败: {ErrorMessage}", _deviceIdentifier, ex.Message);
ErrorOccurred?.Invoke(this, ex);
throw;
}
}
///
/// 开始接收消息的后台任务
///
/// 取消标记
private async Task StartReceiveMessagesAsync(CancellationToken cancellationToken)
{
byte[] buffer = new byte[1024];
try
{
while (!cancellationToken.IsCancellationRequested && IsConnected)
{
// 读取消息长度
int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
if (bytesRead > 0)
{
// 创建一个新数组,只包含实际读取的字节
byte[] receivedMessage = new byte[bytesRead];
Array.Copy(buffer, receivedMessage, bytesRead);
Log.Debug("{DeviceId} 收到消息: {HexMessage}",
_deviceIdentifier, BitConverter.ToString(receivedMessage).Replace("-", " "));
// 触发消息接收事件
MessageReceived?.Invoke(this, receivedMessage);
}
else
{
// 读取0字节表示连接已关闭
Log.Warning("{DeviceId} 连接已关闭(服务器端断开)", _deviceIdentifier);
break;
}
}
}
catch (OperationCanceledException)
{
// 任务被取消,正常退出
Log.Information("{DeviceId} 接收消息任务已取消", _deviceIdentifier);
}
catch (Exception ex)
{
if (!cancellationToken.IsCancellationRequested)
{
Log.Error(ex, "{DeviceId} 接收消息时发生错误: {ErrorMessage}", _deviceIdentifier, ex.Message);
ErrorOccurred?.Invoke(this, ex);
// 触发连接状态变更
ConnectionStatusChanged?.Invoke(this, ConnectionStatus.Failed);
}
}
// 如果不是因为取消而退出循环,表示连接已断开
if (!cancellationToken.IsCancellationRequested && _client != null)
{
// 额外检查并确认连接状态
try
{
if (_client.Client != null && !_client.Client.Poll(0, SelectMode.SelectRead) || _client.Available != 0)
{
// 客户端仍然连接
return;
}
}
catch
{
// 忽略额外的检查异常
}
// 连接已断开
ConnectionStatusChanged?.Invoke(this, ConnectionStatus.Disconnected);
}
}
///
/// 释放资源
///
public void Dispose()
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_stream?.Dispose();
_client?.Dispose();
_cancellationTokenSource = null;
_stream = null;
_client = null;
}
}
}