From ce1292c9cf37195b6abd2699dfc5d6cb3e143c9b Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期日, 12 四月 2026 23:38:19 +0800
Subject: [PATCH] feat(MES): 添加MES接口相关实体和DTO JS扩展文件至JSX格式并更新配置
---
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs | 182 ++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 169 insertions(+), 13 deletions(-)
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
index 9f186e4..571cd45 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
@@ -1,16 +1,28 @@
-using HslCommunication.Core.IMessage;
-using System;
using System.Net.Sockets;
using System.Text;
using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
-using WIDESEAWCS_QuartzJob;
+using System.IO;
namespace WIDESEAWCS_Tasks.SocketServer
{
public partial class TcpSocketServer
{
+ /// <summary>
+ /// 澶勭悊瀹㈡埛绔繛鎺ョ殑娑堟伅寰幆
+ /// </summary>
+ /// <remarks>
+ /// 鎸佺画鎺ユ敹瀹㈡埛绔秷鎭紝鐩村埌杩炴帴鏂紑鎴栧彇娑堛��
+ /// 澶勭悊娴佺▼锛�
+ /// 1. 鎺ユ敹娑堟伅锛堝抚瑙f瀽锛�
+ /// 2. 鏇存柊瀹㈡埛绔姸鎬侊紙娲昏穬鏃堕棿銆佺紪鐮侊級
+ /// 3. 澶勭悊璁惧娉ㄥ唽
+ /// 4. 瑙﹀彂 MessageReceived 浜嬩欢
+ /// 杩炴帴鏂紑鏃舵竻鐞嗚祫婧愬苟瑙﹀彂 RobotReceived 浜嬩欢銆�
+ /// </remarks>
+ /// <param name="client">TCP 瀹㈡埛绔繛鎺�</param>
+ /// <param name="clientId">瀹㈡埛绔敮涓�鏍囪瘑</param>
+ /// <param name="cancellationToken">鍙栨秷浠ょ墝</param>
+ /// <param name="robotCrane">鏈哄櫒浜虹姸鎬�</param>
public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane)
{
using (client)
@@ -21,18 +33,21 @@
CancellationTokenSource? localCts = null;
if (_options.EnableHeartbeat || _options.IdleTimeoutSeconds > 0)
{
+ // 鍒涘缓閾炬帴鐨勫彇娑堜护鐗屾簮
localCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
}
try
{
+ // 娑堟伅鎺ユ敹寰幆
while (!cancellationToken.IsCancellationRequested && client.Connected)
{
string? message;
try
{
var ct = localCts?.Token ?? cancellationToken;
- message = await reader.ReadLineAsync().WaitAsync(ct);
+ // 鎺ユ敹瀹屾暣娑堟伅锛堝抚瑙f瀽锛�
+ message = await ReceiveFullMessageAsync(networkStream, _textEncoding, ct);
}
catch (OperationCanceledException)
{
@@ -44,23 +59,33 @@
break;
}
+ // 鏇存柊瀹㈡埛绔姸鎬�
UpdateClientStatus(clientId, message);
string messageLower = message.ToLowerInvariant();
+ // 澶勭悊娉ㄥ唽娑堟伅
if (TryHandleRegister(messageLower, message, clientId, networkStream, cancellationToken))
{
continue;
}
+ // 瑙﹀彂娑堟伅鎺ユ敹浜嬩欢
if (MessageReceived != null)
{
- try { _ = MessageReceived.Invoke(message, false, client, robotCrane); } catch { }
+ try
+ {
+ // 鍒ゆ柇鏄惁涓� JSON 鏍煎紡
+ bool isJsonFormat = TryParseJsonSilent(message);
+ _ = MessageReceived.Invoke(message, isJsonFormat, client, robotCrane);
+ }
+ catch { }
}
}
}
finally
{
+ // 娓呯悊璧勬簮
try { localCts?.Cancel(); localCts?.Dispose(); } catch { }
RemoveClient(clientId);
try { _ = RobotReceived.Invoke(clientId); } catch { }
@@ -68,6 +93,19 @@
}
}
+ /// <summary>
+ /// 澶勭悊璁惧娉ㄥ唽娑堟伅
+ /// </summary>
+ /// <remarks>
+ /// 娉ㄥ唽娑堟伅鏍煎紡锛歳egister,{deviceId}
+ /// 灏嗚澶� ID 缁戝畾鍒板綋鍓嶅鎴风 ID銆�
+ /// </remarks>
+ /// <param name="messageLower">娑堟伅灏忓啓鐗堟湰</param>
+ /// <param name="message">鍘熷娑堟伅</param>
+ /// <param name="clientId">瀹㈡埛绔� ID</param>
+ /// <param name="networkStream">缃戠粶娴�</param>
+ /// <param name="cancellationToken">鍙栨秷浠ょ墝</param>
+ /// <returns>鏄惁澶勭悊浜嗘敞鍐屾秷鎭�</returns>
private bool TryHandleRegister(string messageLower, string message, string clientId, NetworkStream networkStream, CancellationToken cancellationToken)
{
if (!messageLower.StartsWith("register,"))
@@ -75,30 +113,45 @@
return false;
}
+ // 鎻愬彇璁惧 ID
string deviceId = message.Substring("register,".Length).Trim();
if (!string.IsNullOrEmpty(deviceId))
{
lock (_syncRoot)
{
+ // 缁戝畾璁惧鍒板鎴风
_deviceBindings[deviceId] = clientId;
}
+ // 鍥炲娉ㄥ唽鎴愬姛
_ = WriteToClientAsync(clientId, networkStream, $"Registered,{deviceId}", cancellationToken);
}
return true;
}
+ /// <summary>
+ /// 鏇存柊瀹㈡埛绔姸鎬�
+ /// </summary>
+ /// <remarks>
+ /// 鏇存柊鏈�鍚庢椿璺冩椂闂村拰瀛楃缂栫爜銆�
+ /// 濡傛灉寮�鍚簡鑷姩缂栫爜妫�娴嬶紝鏍规嵁娑堟伅鍐呭鍒ゆ柇鏄� UTF-8 杩樻槸 GBK銆�
+ /// </remarks>
+ /// <param name="clientId">瀹㈡埛绔� ID</param>
+ /// <param name="message">鏈�鏂版帴鏀剁殑娑堟伅</param>
private void UpdateClientStatus(string clientId, string message)
{
lock (_syncRoot)
{
+ // 鏇存柊鏈�鍚庢椿璺冩椂闂�
_clientLastActive[clientId] = DateTime.Now;
+ // 濡傛灉杩樻病鏈夎褰曠紪鐮�
if (!_clientEncodings.ContainsKey(clientId))
{
if (_options.AutoDetectEncoding && _autoDetectedGb2312 != null)
{
+ // 鑷姩妫�娴嬬紪鐮侊細JSON 鎴� UTF-8 瀛楄妭鐗瑰緛鍒欑敤 UTF-8锛屽惁鍒欑敤 GBK
bool isUtf8 = TryParseJsonSilent(message) || IsLikelyUtf8(_textEncoding.GetBytes(message));
_clientEncodings[clientId] = isUtf8 ? _textEncoding : _autoDetectedGb2312;
}
@@ -110,6 +163,12 @@
}
}
+ /// <summary>
+ /// 寮傛鍙戦�佹秷鎭埌瀹㈡埛绔�
+ /// </summary>
+ /// <remarks>
+ /// 鍐呴儴鏂规硶锛屼笉浣跨敤甯ф牸寮忥紝鐩存帴鍙戦�佸師濮嬫秷鎭��
+ /// </remarks>
private async Task WriteToClientAsync(string clientId, NetworkStream networkStream, string message, CancellationToken cancellationToken)
{
SemaphoreSlim? sem = null;
@@ -125,7 +184,8 @@
if (sem != null) await sem.WaitAsync(cancellationToken);
try
{
- var data = enc.GetBytes(message + "\n");
+ var framedMessage = BuildFramedMessage(message);
+ var data = enc.GetBytes(framedMessage);
await networkStream.WriteAsync(data, 0, data.Length, cancellationToken);
}
finally
@@ -134,6 +194,30 @@
}
}
+ /// <summary>
+ /// 鏋勫缓甯ф秷鎭�
+ /// </summary>
+ /// <remarks>
+ /// 鍦ㄦ秷鎭墠鍚庢坊鍔犲ご灏炬爣璇嗐��
+ /// </remarks>
+ /// <param name="message">鍘熷娑堟伅</param>
+ /// <returns>甯﹀抚鏍囪瘑鐨勬秷鎭�</returns>
+ private string BuildFramedMessage(string message)
+ {
+ var header = _options.MessageHeader ?? string.Empty;
+ var footer = _options.MessageFooter ?? string.Empty;
+ return header + (message ?? string.Empty) + footer;
+ }
+
+ /// <summary>
+ /// 闈欓粯灏濊瘯瑙f瀽 JSON
+ /// </summary>
+ /// <remarks>
+ /// 鍒ゆ柇娑堟伅鏄惁浠� { 鎴� [ 寮�澶达紝濡傛灉鏄垯灏濊瘯瑙f瀽銆�
+ /// 瑙f瀽澶辫触涓嶆姏寮傚父銆�
+ /// </remarks>
+ /// <param name="message">娑堟伅鍐呭</param>
+ /// <returns>鏄惁鏄湁鏁堢殑 JSON 鏍煎紡</returns>
private static bool TryParseJsonSilent(string message)
{
if (string.IsNullOrWhiteSpace(message)) return false;
@@ -142,26 +226,36 @@
try { JsonDocument.Parse(message); return true; } catch { return false; }
}
+ /// <summary>
+ /// 鍒ゆ柇瀛楄妭鏁扮粍鏄惁涓� UTF-8 缂栫爜
+ /// </summary>
+ /// <remarks>
+ /// 閫氳繃妫�鏌ュ瓧鑺傚簭鍒楁槸鍚︾鍚� UTF-8 澶氬瓧鑺傚瓧绗︾殑缂栫爜瑙勫垯銆�
+ /// </remarks>
+ /// <param name="data">瀛楄妭鏁扮粍</param>
+ /// <returns>鏄惁鍙兘鏄� UTF-8 缂栫爜</returns>
private static bool IsLikelyUtf8(byte[] data)
{
int i = 0;
while (i < data.Length)
{
byte b = data[i];
- if (b <= 0x7F) { i++; continue; }
- if (b >= 0xC2 && b <= 0xDF)
+ if (b <= 0x7F) { i++; continue; } // ASCII 瀛楃
+
+ // 妫�鏌ュ瀛楄妭瀛楃
+ if (b >= 0xC2 && b <= 0xDF) // 2瀛楄妭瀛楃
{
if (i + 1 >= data.Length) return false;
if ((data[i + 1] & 0xC0) != 0x80) return false;
i += 2; continue;
}
- if (b >= 0xE0 && b <= 0xEF)
+ if (b >= 0xE0 && b <= 0xEF) // 3瀛楄妭瀛楃
{
if (i + 2 >= data.Length) return false;
if ((data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80) return false;
i += 3; continue;
}
- if (b >= 0xF0 && b <= 0xF4)
+ if (b >= 0xF0 && b <= 0xF4) // 4瀛楄妭瀛楃
{
if (i + 3 >= data.Length) return false;
if ((data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80 || (data[i + 3] & 0xC0) != 0x80) return false;
@@ -171,5 +265,67 @@
}
return true;
}
+
+ /// <summary>
+ /// 鎺ユ敹瀹屾暣娑堟伅锛堝抚瑙f瀽锛�
+ /// </summary>
+ /// <remarks>
+ /// 鏍规嵁閰嶇疆鐨勫ご灏炬爣璇嗚В鏋愭秷鎭��
+ /// 濡傛灉鏈厤缃ご灏撅紝鍒欎竴鐩磋鍒版暟鎹笉鍙敤銆�
+ /// </remarks>
+ /// <param name="networkStream">缃戠粶娴�</param>
+ /// <param name="encoding">瀛楃缂栫爜</param>
+ /// <param name="cancellationToken">鍙栨秷浠ょ墝</param>
+ /// <returns>鎺ユ敹鍒扮殑娑堟伅</returns>
+ private async Task<string?> ReceiveFullMessageAsync(NetworkStream networkStream, Encoding encoding, CancellationToken cancellationToken)
+ {
+ var header = _options.MessageHeader ?? string.Empty;
+ var footer = _options.MessageFooter ?? string.Empty;
+
+ var buffer = new byte[1024];
+ var builder = new StringBuilder();
+
+ while (true)
+ {
+ // 璇诲彇鏁版嵁
+ int bytesRead = await networkStream.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken);
+ if (bytesRead <= 0)
+ {
+ if (builder.Length == 0) return null;
+ // 鏃犲ご灏鹃厤缃椂锛岃繑鍥炲凡鏈夋暟鎹�
+ return string.IsNullOrEmpty(header) && string.IsNullOrEmpty(footer) ? builder.ToString() : null;
+ }
+
+ builder.Append(encoding.GetString(buffer, 0, bytesRead));
+
+ // 濡傛灉娌℃湁閰嶇疆澶村熬锛屼笖鏁版嵁涓嶅彲鐢紝杩斿洖宸叉湁鏁版嵁
+ if (string.IsNullOrEmpty(header) && string.IsNullOrEmpty(footer))
+ {
+ if (!networkStream.DataAvailable)
+ {
+ break;
+ }
+ continue;
+ }
+
+ // 鏌ユ壘甯уご
+ var data = builder.ToString();
+ var headerIndex = string.IsNullOrEmpty(header) ? 0 : data.IndexOf(header, StringComparison.Ordinal);
+ if (headerIndex < 0)
+ {
+ continue;
+ }
+
+ // 鎻愬彇甯у唴瀹�
+ var startIndex = headerIndex + header.Length;
+ var footerIndex = string.IsNullOrEmpty(footer) ? data.Length : data.IndexOf(footer, startIndex, StringComparison.Ordinal);
+ if (footerIndex >= 0)
+ {
+ return data.Substring(startIndex, footerIndex - startIndex);
+ }
+ }
+
+ return builder.ToString();
+ }
}
-}
\ No newline at end of file
+}
--
Gitblit v1.9.3