Files
shgx_tz_mes_backend_sync/Infrastructure/Helper/SocketServerHelper.cs
2025-12-20 13:23:51 +08:00

256 lines
8.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Infrastructure
{
/// <summary>
/// Socket 服务端工具类(你的“接受端”)
/// 功能监听端口与网关客户端建立长连接支持收发字节数据byte[]
/// </summary>
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;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="listenIp">监听的IP如 "127.0.0.1" 或 "0.0.0.0"</param>
/// <param name="listenPort">监听的端口,如 8888</param>
public SocketGatewayServer(string listenIp = "127.0.0.1", int listenPort = 8888)
{
_listenIp = listenIp;
_listenPort = listenPort;
}
/// <summary>
/// 启动服务端,开始监听网关(客户端)连接
/// </summary>
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();
}
}
/// <summary>
/// 等待并接受一个客户端(网关)连接
/// </summary>
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}");
}
}
/// <summary>
/// 向网关客户端发送字节数据byte[]
/// </summary>
/// <param name="data">要发送的字节数据</param>
/// <returns>是否发送成功</returns>
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;
}
}
/// <summary>
/// (可选)接收来自网关的字节数据
/// </summary>
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("接收线程已退出");
}
}
/// <summary>
/// 将字节数组转换为十六进制字符串并打印
/// </summary>
/// <param name="bytes">要转换的字节数组</param>
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);
}
/// <summary>
/// 计算多个 byte[] 数组中所有字节之和,然后对 256 取余返回校验字节0~255
/// </summary>
/// <param name="byteArrays">多个 byte[] 数组,可以是任意数量</param>
/// <returns>校验和一个字节0~255所有字节之和 % 256</returns>
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);
}
}
}