using SmartScanner.ViewModel;
|
using System;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using System.Net;
|
using System.Net.Sockets;
|
using System.Text;
|
using System.Threading;
|
using System.Threading.Tasks;
|
|
namespace SmartScanner
|
{
|
public class TcpServerManager : IDisposable
|
{
|
private TcpListener _listener;
|
public static bool _isRunning;
|
private CancellationTokenSource _cts;
|
private Func<Task<int[]>> _imageProcessingHandler; // 图像处理委托
|
private int _outputIOCount; // 输出IO数量
|
// 心跳配置
|
public bool EnableHeartbeat { get; private set; }
|
public string HeartbeatCommand { get; private set; }
|
public int HeartbeatInterval { get; private set; }
|
|
// 客户端列表管理(如果需要跟踪多个客户端)
|
// private ConcurrentDictionary<string, TcpClient> _connectedClients = new ConcurrentDictionary<string, TcpClient>();
|
|
public event Action<string> LogMessage;
|
public event Action<string, string> CommandReceived;
|
public event Action<string> ClientConnected;
|
public event Action<string> ClientDisconnected;
|
|
public TcpServerManager(bool enableHeartbeat, string heartbeatCommand, int heartbeatInterval,
|
Func<Task<int[]>> imageProcessingHandler, int outputIOCount)
|
{
|
EnableHeartbeat = enableHeartbeat;
|
HeartbeatCommand = heartbeatCommand ?? "heartBeat";
|
HeartbeatInterval = heartbeatInterval > 0 ? heartbeatInterval : 1000;
|
_imageProcessingHandler = imageProcessingHandler ?? throw new ArgumentNullException(nameof(imageProcessingHandler));
|
_outputIOCount = outputIOCount > 0 ? outputIOCount : 1;
|
}
|
/// <summary>
|
/// TCP服务器开始侦听
|
/// </summary>
|
/// <param name="ip">服务器IP地址</param>
|
/// <param name="port">服务器端口</param>
|
public async Task StartAsync(string ip, int port)
|
{
|
if (port == -1) return;
|
_cts = new CancellationTokenSource();
|
_isRunning = true;
|
_listener = new TcpListener(IPAddress.Parse(ip), port);
|
_listener.Start();
|
|
LogMessage?.Invoke($"TCP服务器已启动,开始侦听 {ip}:{port}");
|
LogMessage?.Invoke($"心跳检测: {(EnableHeartbeat ? "已启用" : "已禁用")}");
|
if (EnableHeartbeat)
|
{
|
LogMessage?.Invoke($"心跳指令: {HeartbeatCommand}, 间隔: {HeartbeatInterval}ms");
|
}
|
|
try
|
{
|
while (_isRunning)
|
{
|
var acceptTask = _listener.AcceptTcpClientAsync();
|
var cancelTask = Task.Delay(-1, _cts.Token);
|
|
var completedTask = await Task.WhenAny(acceptTask, cancelTask);
|
|
if (completedTask == cancelTask || _cts.Token.IsCancellationRequested)
|
{
|
break;
|
}
|
var client = await acceptTask;
|
_ = HandleClientAsync(client);
|
}
|
}
|
catch (Exception ex)
|
{
|
LogMessage?.Invoke($"服务器错误: {ex.Message}");
|
}
|
}
|
|
private async Task HandleClientAsync(TcpClient client)
|
{
|
var clientId = client.Client.RemoteEndPoint?.ToString() ?? "未知客户端";
|
ClientConnected?.Invoke(clientId);
|
LogMessage?.Invoke($"客户端已连接: {clientId}");
|
|
try
|
{
|
using (client)
|
using (var stream = client.GetStream())
|
{
|
// 使用NetworkStream读取
|
byte[] buffer = new byte[4096];
|
MemoryStream ms = new MemoryStream();
|
|
while (!_cts.IsCancellationRequested && client.Connected)
|
{
|
// 检查数据是否可用
|
if (!stream.DataAvailable)
|
{
|
await Task.Delay(10, _cts.Token); // 短暂等待
|
continue;
|
}
|
|
// 同步读取方式
|
int bytesRead = stream.Read(buffer, 0, buffer.Length);
|
if (bytesRead == 0) // 连接已关闭
|
{
|
LogMessage?.Invoke($"客户端 {clientId} 正常断开");
|
break;
|
}
|
|
ms.Write(buffer, 0, bytesRead);
|
|
// 处理完整消息(消息以换行符结尾)
|
string receivedData = Encoding.ASCII.GetString(ms.ToArray());
|
//if (receivedData.Contains('\n'))
|
//{
|
string[] messages = receivedData.Split('\n');
|
for (int i = 0; i < messages.Length - 1; i++) // 最后一段可能不完整
|
{
|
string message = messages[i].Trim();
|
if (!string.IsNullOrEmpty(message))
|
{
|
await ProcessMessageAsync(message, stream, clientId);
|
}
|
}
|
|
// 保留不完整的部分
|
ms.SetLength(0);
|
if (!string.IsNullOrEmpty(messages.Last()))
|
{
|
ms.Write(Encoding.ASCII.GetBytes(messages.Last()), 0, messages.Last().Length);
|
}
|
//}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogMessage?.Invoke($"处理客户端 {clientId} 时出错: {ex.Message}");
|
}
|
finally
|
{
|
ClientDisconnected?.Invoke(clientId);
|
LogMessage?.Invoke($"客户端断开: {clientId}");
|
}
|
}
|
|
private async Task ProcessMessageAsync(string message, NetworkStream stream, string clientId)
|
{
|
LogMessage?.Invoke($"来自 {clientId}: {message}");
|
|
Console.WriteLine($"{DateTime.Now:HH:mm:ss:fff}:检测到触发信号{message}");
|
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:检测到触发信号{message}");
|
// 处理心跳
|
if (EnableHeartbeat && message == HeartbeatCommand)
|
{
|
byte[] ack = Encoding.ASCII.GetBytes($"{HeartbeatCommand}_ACK\n");
|
await stream.WriteAsync(ack, 0, ack.Length);
|
return;
|
}
|
|
// 处理业务消息
|
var parts = message.Split(',');
|
if (parts.Length >= 2 && int.TryParse(parts[0], out var functionCode))
|
{
|
// 处理触发信号 (暂定功能码为3,待后续与客户沟通)
|
if (functionCode == 3)
|
{
|
await HandleTriggerCommand(stream, clientId);
|
}
|
else
|
{
|
// 其他功能码处理
|
var response = $"{functionCode},0,Invalid function code\n";
|
byte[] responseBytes = Encoding.ASCII.GetBytes(response);
|
await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
|
}
|
}
|
}
|
private async Task HandleTriggerCommand(NetworkStream stream, string clientId)
|
{
|
try
|
{
|
LogMessage?.Invoke($"开始处理触发命令,进行图像采集和推理...");
|
// 调用图像处理委托
|
int[] processingResults = await _imageProcessingHandler()
|
.ConfigureAwait(false); // 避免死锁
|
if (processingResults == null || processingResults.Length != _outputIOCount)
|
{
|
throw new InvalidOperationException($"图像处理结果无效,预期{_outputIOCount}个输出,实际得到{processingResults?.Length ?? 0}");
|
}
|
|
// 构建响应消息
|
var responseBuilder = new StringBuilder();
|
responseBuilder.Append("3,"); // 功能号
|
responseBuilder.Append(_outputIOCount); // 输出IO数
|
|
// 添加每个点位的处理结果
|
foreach (var result in processingResults)
|
{
|
responseBuilder.Append($",{result}");
|
}
|
|
responseBuilder.Append("\n"); // 结束符
|
|
string response = responseBuilder.ToString();
|
LogMessage?.Invoke($"返回结果: {response.Trim()}");
|
EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:检测完成,返回结果{response.Trim()}");
|
// 发送响应
|
byte[] responseBytes = Encoding.ASCII.GetBytes(response);
|
await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
|
}
|
catch (Exception ex)
|
{
|
LogMessage?.Invoke($"处理触发命令时出错: {ex.Message}");
|
|
// 发送错误响应
|
var errorResponse = $"3,0,Error: {ex.Message}\n";
|
byte[] errorBytes = Encoding.ASCII.GetBytes(errorResponse);
|
await stream.WriteAsync(errorBytes, 0, errorBytes.Length);
|
}
|
}
|
|
private async Task StartHeartbeatAsync(StreamWriter writer, CancellationToken token)
|
{
|
try
|
{
|
while (!token.IsCancellationRequested)
|
{
|
await writer.WriteLineAsync(HeartbeatCommand);
|
await Task.Delay(HeartbeatInterval, token);
|
}
|
}
|
catch (OperationCanceledException)
|
{
|
// 正常取消
|
}
|
catch (Exception ex)
|
{
|
LogMessage?.Invoke($"心跳任务错误: {ex.Message}");
|
}
|
}
|
|
public void Stop()
|
{
|
_isRunning = false;
|
_cts?.Cancel();
|
try
|
{
|
_listener?.Stop();
|
LogMessage?.Invoke("TCP服务器已停止");
|
}
|
catch (Exception ex)
|
{
|
LogMessage?.Invoke($"停止服务器时出错: {ex.Message}");
|
}
|
}
|
|
public void Dispose()
|
{
|
Stop();
|
_cts?.Dispose();
|
}
|
}
|
}
|