Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

282 řádky
10 KiB

  1. using System;
  2. using System.Threading.Tasks;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Threading;
  6. using System.IO.Pipelines;
  7. using System.Buffers;
  8. using JT808.Protocol;
  9. using Microsoft.Extensions.Logging;
  10. using JT808.Protocol.Exceptions;
  11. using JT808.Protocol.Extensions;
  12. using JT808.Gateway.Client.Services;
  13. using JT808.Gateway.Client.Metadata;
  14. using Microsoft.Extensions.DependencyInjection;
  15. namespace JT808.Gateway.Client
  16. {
  17. public class JT808TcpClient:IDisposable
  18. {
  19. private bool disposed = false;
  20. private Socket clientSocket;
  21. private readonly ILogger Logger;
  22. private readonly JT808Serializer JT808Serializer;
  23. private readonly JT808SendAtomicCounterService SendAtomicCounterService;
  24. private readonly JT808ReceiveAtomicCounterService ReceiveAtomicCounterService;
  25. private bool socketState = true;
  26. public JT808DeviceConfig DeviceConfig { get; }
  27. public JT808TcpClient(
  28. JT808DeviceConfig deviceConfig,
  29. IServiceProvider serviceProvider)
  30. {
  31. DeviceConfig = deviceConfig;
  32. SendAtomicCounterService = serviceProvider.GetRequiredService<JT808SendAtomicCounterService>();
  33. ReceiveAtomicCounterService = serviceProvider.GetRequiredService<JT808ReceiveAtomicCounterService>();
  34. JT808Serializer = serviceProvider.GetRequiredService<IJT808Config>().GetSerializer();
  35. Logger = serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("JT808TcpClient");
  36. }
  37. public async ValueTask<bool> ConnectAsync(EndPoint remoteEndPoint)
  38. {
  39. clientSocket = new Socket(remoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  40. try
  41. {
  42. await clientSocket.ConnectAsync(remoteEndPoint);
  43. return true;
  44. }
  45. catch (Exception e)
  46. {
  47. return false;
  48. }
  49. }
  50. public async void StartAsync(CancellationToken cancellationToken)
  51. {
  52. await Task.Factory.StartNew(async (state) =>
  53. {
  54. var session = (Socket)state;
  55. if (Logger.IsEnabled(LogLevel.Information))
  56. {
  57. Logger.LogInformation($"[Connected]:{session.LocalEndPoint} to {session.RemoteEndPoint}");
  58. }
  59. var pipe = new Pipe();
  60. Task writing = FillPipeAsync(session, pipe.Writer, cancellationToken);
  61. Task reading = ReadPipeAsync(session, pipe.Reader);
  62. await Task.WhenAll(reading, writing);
  63. }, clientSocket);
  64. }
  65. private async Task FillPipeAsync(Socket session, PipeWriter writer, CancellationToken cancellationToken)
  66. {
  67. while (true)
  68. {
  69. try
  70. {
  71. Memory<byte> memory = writer.GetMemory(80960);
  72. int bytesRead = await session.ReceiveAsync(memory, SocketFlags.None, cancellationToken);
  73. if (bytesRead == 0)
  74. {
  75. break;
  76. }
  77. writer.Advance(bytesRead);
  78. }
  79. catch (System.Net.Sockets.SocketException ex)
  80. {
  81. Logger.LogError($"[{ex.SocketErrorCode.ToString()},{ex.Message}]:{session.RemoteEndPoint}");
  82. break;
  83. }
  84. catch (Exception ex)
  85. {
  86. Logger.LogError(ex, $"[Receive Error]:{session.RemoteEndPoint}");
  87. break;
  88. }
  89. FlushResult result = await writer.FlushAsync();
  90. if (result.IsCompleted)
  91. {
  92. break;
  93. }
  94. }
  95. writer.Complete();
  96. }
  97. private async Task ReadPipeAsync(Socket session, PipeReader reader)
  98. {
  99. while (true)
  100. {
  101. ReadResult result = await reader.ReadAsync();
  102. if (result.IsCompleted)
  103. {
  104. break;
  105. }
  106. ReadOnlySequence<byte> buffer = result.Buffer;
  107. SequencePosition consumed = buffer.Start;
  108. SequencePosition examined = buffer.End;
  109. try
  110. {
  111. if (result.IsCanceled) break;
  112. if (buffer.Length > 0)
  113. {
  114. ReaderBuffer(ref buffer, session, out consumed, out examined);
  115. }
  116. }
  117. catch (Exception ex)
  118. {
  119. Close();
  120. break;
  121. }
  122. finally
  123. {
  124. reader.AdvanceTo(consumed, examined);
  125. }
  126. }
  127. reader.Complete();
  128. }
  129. private void ReaderBuffer(ref ReadOnlySequence<byte> buffer, Socket session, out SequencePosition consumed, out SequencePosition examined)
  130. {
  131. consumed = buffer.Start;
  132. examined = buffer.End;
  133. SequenceReader<byte> seqReader = new SequenceReader<byte>(buffer);
  134. if (seqReader.TryPeek(out byte beginMark))
  135. {
  136. if (beginMark != JT808Package.BeginFlag) throw new ArgumentException("Not JT808 Packages.");
  137. }
  138. byte mark = 0;
  139. long totalConsumed = 0;
  140. while (!seqReader.End)
  141. {
  142. if (seqReader.IsNext(JT808Package.BeginFlag, advancePast: true))
  143. {
  144. if (mark == 1)
  145. {
  146. try
  147. {
  148. var package = JT808Serializer.HeaderDeserialize(seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).FirstSpan,minBufferSize:10240);
  149. ReceiveAtomicCounterService.MsgSuccessIncrement();
  150. if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Success Counter]:{ReceiveAtomicCounterService.MsgSuccessCount}");
  151. if (Logger.IsEnabled(LogLevel.Trace)) Logger.LogTrace($"[Accept Hex {session.RemoteEndPoint}]:{package.OriginalData.ToArray().ToHexString()}");
  152. }
  153. catch (JT808Exception ex)
  154. {
  155. Logger.LogError(ex, $"[HeaderDeserialize ErrorCode]:{ ex.ErrorCode}");
  156. }
  157. totalConsumed += (seqReader.Consumed - totalConsumed);
  158. if (seqReader.End) break;
  159. seqReader.Advance(1);
  160. mark = 0;
  161. }
  162. mark++;
  163. }
  164. else
  165. {
  166. seqReader.Advance(1);
  167. }
  168. }
  169. if (seqReader.Length == totalConsumed)
  170. {
  171. examined = consumed = buffer.End;
  172. }
  173. else
  174. {
  175. consumed = buffer.GetPosition(totalConsumed);
  176. }
  177. }
  178. public async ValueTask SendAsync(JT808ClientRequest message)
  179. {
  180. if (disposed) return;
  181. if (IsOpen && socketState)
  182. {
  183. if (message.Package != null)
  184. {
  185. try
  186. {
  187. var sendData = JT808Serializer.Serialize(message.Package, minBufferSize: message.MinBufferSize);
  188. //clientSocket.Send(sendData);
  189. await clientSocket.SendAsync(sendData, SocketFlags.None);
  190. SendAtomicCounterService.MsgSuccessIncrement();
  191. }
  192. catch (System.Net.Sockets.SocketException ex)
  193. {
  194. socketState = false;
  195. Logger.LogError($"[{ex.SocketErrorCode.ToString()},{ex.Message},{DeviceConfig.TerminalPhoneNo}]");
  196. }
  197. catch (System.Exception ex)
  198. {
  199. Logger.LogError(ex.Message);
  200. }
  201. }
  202. else if (message.HexData != null)
  203. {
  204. try
  205. {
  206. clientSocket.Send(message.HexData);
  207. SendAtomicCounterService.MsgSuccessIncrement();
  208. }
  209. catch (System.Net.Sockets.SocketException ex)
  210. {
  211. socketState = false;
  212. Logger.LogError($"[{ex.SocketErrorCode.ToString()},{ex.Message},{DeviceConfig.TerminalPhoneNo}]");
  213. }
  214. catch (System.Exception ex)
  215. {
  216. Logger.LogError(ex.Message);
  217. }
  218. }
  219. }
  220. }
  221. public void Close()
  222. {
  223. if (disposed) return;
  224. var socket = clientSocket;
  225. if (socket == null)
  226. return;
  227. if (Interlocked.CompareExchange(ref clientSocket, null, socket) == socket)
  228. {
  229. try
  230. {
  231. clientSocket.Shutdown(SocketShutdown.Both);
  232. }
  233. finally
  234. {
  235. clientSocket.Close();
  236. }
  237. }
  238. }
  239. private void Dispose(bool disposing)
  240. {
  241. if (disposed) return;
  242. if (disposing)
  243. {
  244. // 清理托管资源
  245. clientSocket.Dispose();
  246. }
  247. disposed = true;
  248. }
  249. ~JT808TcpClient()
  250. {
  251. //必须为false
  252. //这表明,隐式清理时,只要处理非托管资源就可以了。
  253. Dispose(false);
  254. }
  255. public void Dispose()
  256. {
  257. //必须为true
  258. Dispose(true);
  259. //通知垃圾回收机制不再调用终结器(析构器)
  260. GC.SuppressFinalize(this);
  261. }
  262. public bool IsOpen
  263. {
  264. get
  265. {
  266. if (disposed) return false;
  267. if (clientSocket != null)
  268. {
  269. return clientSocket.Connected && socketState;
  270. }
  271. return false;
  272. }
  273. }
  274. }
  275. }