diff --git a/Infrastructure/Helper/SocketServerHelper.cs b/Infrastructure/Helper/SocketServerHelper.cs
new file mode 100644
index 00000000..353dd267
--- /dev/null
+++ b/Infrastructure/Helper/SocketServerHelper.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+
+namespace Infrastructure
+{
+
+
+ ///
+ /// Socket 服务端工具类(你的“接受端”)
+ /// 功能:监听端口,与网关(客户端)建立长连接,支持收发字节数据(byte[])
+ ///
+ public class SocketGatewayServer : IDisposable
+ {
+ private TcpListener _listener;
+ private bool _isRunning;
+ private Thread _acceptThread;
+
+ private TcpClient _connectedClient;
+ private NetworkStream _clientStream;
+ private bool _clientConnected;
+
+ private readonly string _listenIp;
+ private readonly int _listenPort;
+
+ ///
+ /// 构造函数
+ ///
+ /// 监听的IP,如 "127.0.0.1" 或 "0.0.0.0"
+ /// 监听的端口,如 8888
+ public SocketGatewayServer(string listenIp = "127.0.0.1", int listenPort = 8888)
+ {
+ _listenIp = listenIp;
+ _listenPort = listenPort;
+ }
+
+ ///
+ /// 启动服务端,开始监听网关(客户端)连接
+ ///
+ public void Start()
+ {
+ if (_isRunning) return;
+
+ try
+ {
+ IPAddress ipAddress = string.IsNullOrEmpty(_listenIp) || _listenIp == "0.0.0.0"
+ ? IPAddress.Any
+ : IPAddress.Parse(_listenIp);
+
+ _listener = new TcpListener(ipAddress, _listenPort);
+ _listener.Start();
+ _isRunning = true;
+
+ Console.WriteLine($"Socket 服务端已启动,正在监听 [{_listenIp}]:{_listenPort}");
+
+ _acceptThread = new Thread(AcceptClient);
+ _acceptThread.IsBackground = true;
+ _acceptThread.Start();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"❌ 启动服务端失败: {ex.Message}");
+ Stop();
+ }
+ }
+
+ ///
+ /// 等待并接受一个客户端(网关)连接
+ ///
+ private void AcceptClient()
+ {
+ try
+ {
+ while (_isRunning)
+ {
+ Console.WriteLine(" 等待网关(客户端)连接...");
+
+ TcpClient client = _listener.AcceptTcpClient(); // 阻塞直到客户端连接
+ Console.WriteLine($"网关(客户端)已连接: {client.Client.RemoteEndPoint}");
+ StartReceiving();
+
+ lock (this)
+ {
+ // 断开之前的连接(如果存在)
+ _connectedClient?.Close();
+ _connectedClient = client;
+ _clientStream = client.GetStream();
+ _clientConnected = true;
+
+ Console.WriteLine("已建立长连接,可以开始收发字节数据");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (_isRunning)
+ Console.WriteLine($"接受客户端时出错: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 向网关(客户端)发送字节数据(byte[])
+ ///
+ /// 要发送的字节数据
+ /// 是否发送成功
+ public bool SendToGateway(byte[] data)
+ {
+ if (!_clientConnected || _clientStream == null || _connectedClient == null)
+ {
+ Console.WriteLine(" 未连接到网关,无法发送数据");
+ return false;
+ }
+
+ try
+ {
+ _clientStream.Write(data, 0, data.Length);
+ Console.WriteLine($" 已发送 {data.Length} 字节数据给网关");
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"发送数据失败: {ex.Message}");
+ DisconnectClient();
+ return false;
+ }
+ }
+
+ ///
+ /// (可选)接收来自网关的字节数据
+ ///
+ public void StartReceiving()
+ {
+ Thread receiveThread = new Thread(ReceiveLoop);
+ receiveThread.IsBackground = true;
+ receiveThread.Start();
+ }
+
+ private void ReceiveLoop()
+ {
+ byte[] buffer = new byte[4096]; // 可根据需求调整缓冲区大小
+
+ try
+ {
+ while (_clientConnected && _connectedClient != null && _clientStream != null)
+ {
+ if (_clientStream.DataAvailable)
+ {
+ int bytesRead = _clientStream.Read(buffer, 0, buffer.Length);
+ if (bytesRead > 0)
+ {
+ byte[] receivedData = new byte[bytesRead];
+ Buffer.BlockCopy(buffer, 0, receivedData, 0, bytesRead);
+
+ Console.WriteLine($"收到来自网关的 {bytesRead} 字节数据");
+
+ // 🔧 新增:将收到的 byte[] 使用 GBK 编码转换为字符串
+ // string receivedText = Encoding.GetEncoding("GBK").GetString(receivedData);
+
+ // Console.WriteLine($"GBK 解码后的报文内容: {receivedText}");
+ PrintBytesAsHex(receivedData);
+ // TODO: 你可以在这里进一步处理 receivedText 或 receivedData
+ }
+ }
+ else
+ {
+ Thread.Sleep(100); // 避免空转消耗 CPU
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"接收数据时出错: {ex.Message}");
+ }
+ finally
+ {
+ Console.WriteLine("接收线程已退出");
+ }
+ }
+ ///
+ /// 将字节数组转换为十六进制字符串并打印
+ ///
+ /// 要转换的字节数组
+ static void PrintBytesAsHex(byte[] bytes)
+ {
+ if (bytes == null || bytes.Length == 0)
+ {
+ Console.WriteLine("字节数组为空或长度为0。");
+ return;
+ }
+
+ // 使用 StringBuilder 或直接拼接,这里使用 String.Join 和格式化
+ string hexString = BitConverter.ToString(bytes).Replace("-", " "); // 可选:用空格分隔每个字节
+ // 或者不替换,就是用 "-" 分隔:string hexString = BitConverter.ToString(bytes);
+
+ Console.WriteLine("字节数据的十六进制表示为:"+ hexString);
+
+ }
+
+ private void DisconnectClient()
+ {
+ lock (this)
+ {
+ _clientConnected = false;
+ _clientStream?.Close();
+ _connectedClient?.Close();
+ _clientStream = null;
+ _connectedClient = null;
+ Console.WriteLine("🔌 已断开与网关的连接");
+ }
+ }
+
+ public void Stop()
+ {
+ _isRunning = false;
+ DisconnectClient();
+ _listener?.Stop();
+ Console.WriteLine("🛑 Socket 服务端已停止");
+ }
+
+ public void Dispose()
+ {
+ Stop();
+ GC.SuppressFinalize(this);
+ }
+
+
+ ///
+ /// 计算多个 byte[] 数组中所有字节之和,然后对 256 取余,返回校验字节(0~255)
+ ///
+ /// 多个 byte[] 数组,可以是任意数量
+ /// 校验和,一个字节(0~255),即:所有字节之和 % 256
+ public static byte CalculateChecksum(params byte[][] byteArrays)
+ {
+ int sum = 0;
+
+ // 遍历每一个 byte[] 数组
+ foreach (byte[] bytes in byteArrays)
+ {
+ if (bytes == null)
+ continue; // 如果某个数组为空,跳过(你也可以选择抛异常)
+
+ // 累加该数组中的每一个字节
+ foreach (byte b in bytes)
+ {
+ sum += b; // byte 自动提升为 int,安全累加
+ }
+ }
+
+ // 计算校验和:总和 % 256,然后转为 byte(范围保证是 0~255)
+ return (byte)(sum % 256);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs
index 61138fae..58a590e7 100644
--- a/ZR.Admin.WebApi/Program.cs
+++ b/ZR.Admin.WebApi/Program.cs
@@ -112,6 +112,15 @@ builder.Services.Configure((o) =>
{
o.SuppressModelStateInvalidFilter = true;
});
+// 注册 SocketGatewayServer 为 Singleton(单例,整个应用生命周期一个实例)
+builder.Services.AddSingleton(provider =>
+{
+ var server = new SocketGatewayServer("192.168.50.163", 4021); // 你可以按需修改 IP 和端口
+ server.Start(); // 项目启动时立即启动监听
+ //server.StartReceiving();
+
+ return server;
+});
var app = builder.Build();
InternalApp.ServiceProvider = app.Services;
InternalApp.Configuration = builder.Configuration;
diff --git a/ZR.Admin.WebApi/background/SocketBackgroundService.cs b/ZR.Admin.WebApi/background/SocketBackgroundService.cs
new file mode 100644
index 00000000..910f5fe1
--- /dev/null
+++ b/ZR.Admin.WebApi/background/SocketBackgroundService.cs
@@ -0,0 +1,36 @@
+
+using DOAN.ServiceCore.MyMatchPush;
+using Infrastructure;
+using Microsoft.Extensions.Logging;
+
+namespace ZR.Admin.WebApi.background
+{
+ public class SocketBackgroundService : BackgroundService
+ {
+ private readonly SocketGatewayServer _socketGateway;
+ private readonly ILogger _logger;
+
+ public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger logger)
+ {
+ _socketGateway = socketGateway;
+ _logger = logger;
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ try
+ {
+ // 等待服务完全启动
+ await Task.Delay(1000, stoppingToken);
+
+ // 测试Socket推送功能
+ var result = Watchup.StartPush("测试Socket推送功能", _socketGateway);
+ _logger.LogInformation($"Socket推送测试结果: {result}");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Socket推送测试失败");
+ }
+ }
+ }
+}
diff --git a/ZR.Service/Utils/MyMatchPush/Watchup.cs b/ZR.Service/Utils/MyMatchPush/Watchup.cs
new file mode 100644
index 00000000..7d04fcd3
--- /dev/null
+++ b/ZR.Service/Utils/MyMatchPush/Watchup.cs
@@ -0,0 +1,54 @@
+
+using Infrastructure;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DOAN.ServiceCore.MyMatchPush
+{
+ public class Watchup
+ {
+ private static int PackageSort = 1;
+ public static bool StartPush(string message, SocketGatewayServer _socketGateway)
+ {
+
+ //发送报警信息
+ //包头
+ byte[] packageHeader = { 0x5A };
+
+ //包序号
+ byte[] packsort = { (byte)PackageSort };
+ PackageSort++;
+
+ if (PackageSort > 255)
+ {
+ PackageSort = 1;
+ }
+ // 地址
+ byte[] IPaddress = { 0xff, 0xff, 0xff, 0xff };
+ //命令码
+ byte[] CommandCode = { 0xE0 };
+ //数据长
+ //string message = $"产线:{record.LineCode},\n故障类型:{record.FaultDict},\n故障内容:{record.FaultContext},\n报警人:{record.AskPerson}";
+ // string message = $"产线:{record.LineCode}";
+ byte[] MessageData = Encoding.GetEncoding("GBK").GetBytes(message);
+ byte[] MessageLength = { (byte)MessageData.Length };
+ // === 先拼接除 CRC 之外的所有部分 ===
+ byte[] dataWithoutCRC =
+ packageHeader
+ .Concat(packsort)
+ .Concat(IPaddress)
+ .Concat(CommandCode)
+ .Concat(MessageLength)
+ .Concat(MessageData).ToArray();
+
+ //CRC : 校验和,CRC 前面所有数据之和除 256 的余数
+ byte[] CRC = { SocketGatewayServer.CalculateChecksum(dataWithoutCRC) };
+ byte[] Body = dataWithoutCRC.Concat(CRC).ToArray();
+
+ return _socketGateway.SendToGateway(Body);
+ }
+ }
+}