| | |
| | | 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 |
| | | { |
| | | public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane) |
| | | /// <summary> |
| | | /// 弿¥å¤çä¸å·²è¿æ¥çTCP客æ·ç«¯çéä¿¡ï¼å¤çæºå¨äººèµ·éæºä¼è¯ä¸çä¼ å
¥æ¶æ¯å客æ·ç«¯ç¶ææ´æ°ã |
| | | /// </summary> |
| | | /// <remarks>æ¤æ¹æ³ç®¡ç客æ·ç«¯è¿æ¥ççå½å¨æï¼å
æ¬è¯»åæ¶æ¯ãæ´æ°å®¢æ·ç«¯ç¶æåè°ç¨ç¸å
³äºä»¶ã |
| | | /// å½å¤çç»ææ¶ï¼å®¢æ·ç«¯åç¸å
³çç½ç»èµæºå°è¢«éæ¾ã妿å¯ç¨å¿è·³æç©ºé²è¶
æ¶éé¡¹ï¼ |
| | | /// å°åºç¨é¢å¤çåæ¶é»è¾ãäºä»¶è°ç¨æé´çå¼å¸¸å°è¢«æè·å¹¶æå¶ï¼ä»¥ç¡®ä¿ä¼è¯å¤çç鲿£æ§ã</remarks> |
| | | /// <param name="client">表示è¦å¤ççè¿ç¨è¿æ¥çTCP客æ·ç«¯ãæ¹æ³å®æåå°éæ¾æ¤å¯¹è±¡ã</param> |
| | | /// <param name="clientId">å·²è¿æ¥å®¢æ·ç«¯çå¯ä¸æ è¯ç¬¦ãç¨äºå¨æ´ä¸ªä¼è¯ä¸è·è¸ªåæ´æ°å®¢æ·ç«¯ç¶æã</param> |
| | | /// <param name="cancellationToken">å¯ç¨äºåæ¶å®¢æ·ç«¯å¤çæä½ç忶令çãå¦æè¯·æ±åæ¶ï¼æ¹æ³å°ç«å³ç»æ¢å¤çã</param> |
| | | /// <param name="stackerState">表示ä¸å®¢æ·ç«¯å
³èçæºå¨äººèµ·éæºçå½åç¶æå¯¹è±¡ãç¨äºä¸ºæ¶æ¯å¤çåäºä»¶è°ç¨æä¾ä¸ä¸æã</param> |
| | | /// <returns>表示å¤ç客æ·ç«¯è¿æ¥ç弿¥æä½çä»»å¡ãå½å®¢æ·ç«¯æå¼è¿æ¥æè¯·æ±åæ¶æ¶ä»»å¡å®æã</returns> |
| | | public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, StackerSocketState stackerState) |
| | | { |
| | | using (client) |
| | | using (NetworkStream networkStream = client.GetStream()) |
| | |
| | | try |
| | | { |
| | | var ct = localCts?.Token ?? cancellationToken; |
| | | message = await reader.ReadLineAsync().WaitAsync(ct); |
| | | message = await ReceiveFullMessageAsync(networkStream, _textEncoding, ct); |
| | | //message = await reader.ReadLineAsync().WaitAsync(ct); |
| | | } |
| | | catch (OperationCanceledException) |
| | | { |
| | |
| | | { |
| | | try |
| | | { |
| | | |
| | | _ = MessageReceived.Invoke(message, false, client, robotCrane); |
| | | |
| | | // 夿æ¯å¦ä¸º JSON æ ¼å¼ |
| | | bool isJsonFormat = TryParseJsonSilent(message); |
| | | _ = MessageReceived.Invoke(message, isJsonFormat, client, stackerState); |
| | | } |
| | | catch { } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å°è¯å¤çæ¥èªå®¢æ·ç«¯çè®¾å¤æ³¨å请æ±ãè¿åä¸ä¸ªå¼æç¤ºè¯¥æ¶æ¯æ¯å¦è¢«ä½ä¸ºæ³¨å请æ±å¤çã |
| | | /// </summary> |
| | | /// <remarks>å¦ææ¶æ¯æ¯ææç注å请æ±ä¸å
å«é空çè®¾å¤æ è¯ç¬¦ï¼ |
| | | /// åå°è®¾å¤ç»å®å°å®¢æ·ç«¯å¹¶åé确认信æ¯ãæ¤æ¹æ³ä¸ä¼å æ ææ¶æ¯èæåºå¼å¸¸ï¼ |
| | | /// å®ä»
è¿å falseã</remarks> |
| | | /// <param name="messageLower">客æ·ç«¯æ¶æ¯çå°åçæ¬ï¼ç¨äºå¤ææ¶æ¯æ¯å¦ä¸ºæ³¨å请æ±ã</param> |
| | | /// <param name="message">å
嫿³¨åå½ä»¤åè®¾å¤æ è¯ç¬¦çåå§å®¢æ·ç«¯æ¶æ¯ã</param> |
| | | /// <param name="clientId">åéæ³¨å请æ±ç客æ·ç«¯çå¯ä¸æ è¯ç¬¦ã</param> |
| | | /// <param name="client">ä¸å®¢æ·ç«¯éä¿¡çTCP客æ·ç«¯è¿æ¥ã</param> |
| | | /// <param name="cancellationToken">å¯ç¨äºåæ¶æ³¨åæä½ç忶令çã</param> |
| | | /// <returns>å¦ææ¶æ¯è¢«è¯å«å¹¶ä½ä¸ºæ³¨å请æ±å¤çï¼åè¿å trueï¼å¦åè¿å falseã</returns> |
| | | private bool TryHandleRegister(string messageLower, string message, string clientId, NetworkStream networkStream, CancellationToken cancellationToken) |
| | | { |
| | | if (!messageLower.StartsWith("register,")) |
| | |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ´æ°å®¢æ·ç«¯ç¶æ |
| | | /// </summary> |
| | | /// <param name="clientId"></param> |
| | | /// <param name="message"></param> |
| | | private void UpdateClientStatus(string clientId, string message) |
| | | { |
| | | lock (_syncRoot) |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå
¥æ¶æ¯å°å®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <param name="clientId"></param> |
| | | /// <param name="networkStream"></param> |
| | | /// <param name="message"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | private async Task WriteToClientAsync(string clientId, NetworkStream networkStream, string message, CancellationToken cancellationToken) |
| | | { |
| | | SemaphoreSlim? sem = null; |
| | |
| | | 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 |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ·»å æ¶æ¯å¸§å¤´å°¾ |
| | | /// </summary> |
| | | /// <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> |
| | | /// JSONæ ¼å¼å°è¯è§£æï¼éé»å¤±è´¥ï¼ |
| | | /// </summary> |
| | | /// <param name="message"></param> |
| | | /// <returns></returns> |
| | | private static bool TryParseJsonSilent(string message) |
| | | { |
| | | if (string.IsNullOrWhiteSpace(message)) return false; |
| | |
| | | try { JsonDocument.Parse(message); return true; } catch { return false; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// utf-8 å¯è½æ§æ£æµ |
| | | /// </summary> |
| | | /// <param name="data"></param> |
| | | /// <returns></returns> |
| | | private static bool IsLikelyUtf8(byte[] data) |
| | | { |
| | | int i = 0; |
| | |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 读å宿´æ¶æ¯ |
| | | /// </summary> |
| | | /// <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(); |
| | | } |
| | | } |
| | | } |