Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

224 linhas
9.4 KiB

  1. using System;
  2. using System.Buffers;
  3. using System.Collections.Generic;
  4. using System.IO.Pipelines;
  5. using System.Net;
  6. using System.Net.Sockets;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using JT808.Gateway.Abstractions;
  11. using JT808.Gateway.Abstractions.Enums;
  12. using JT808.Gateway.Configurations;
  13. using JT808.Gateway.Services;
  14. using JT808.Gateway.Session;
  15. using JT808.Protocol;
  16. using JT808.Protocol.Exceptions;
  17. using JT808.Protocol.Extensions;
  18. using Microsoft.Extensions.Hosting;
  19. using Microsoft.Extensions.Logging;
  20. using Microsoft.Extensions.Options;
  21. namespace JT808.Gateway
  22. {
  23. public class JT808TcpServer:IHostedService
  24. {
  25. private Socket server;
  26. private readonly ILogger Logger;
  27. private readonly JT808SessionManager SessionManager;
  28. private readonly IJT808MsgProducer MsgProducer;
  29. private readonly JT808Serializer Serializer;
  30. private readonly JT808AtomicCounterService AtomicCounterService;
  31. private readonly JT808Configuration Configuration;
  32. public JT808TcpServer(
  33. IOptions<JT808Configuration> jT808ConfigurationAccessor,
  34. IJT808Config jT808Config,
  35. ILoggerFactory loggerFactory,
  36. JT808SessionManager jT808SessionManager,
  37. IJT808MsgProducer jT808MsgProducer,
  38. JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory)
  39. {
  40. SessionManager = jT808SessionManager;
  41. Logger = loggerFactory.CreateLogger("JT808TcpServer");
  42. Serializer = jT808Config.GetSerializer();
  43. MsgProducer = jT808MsgProducer;
  44. AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp);
  45. Configuration = jT808ConfigurationAccessor.Value;
  46. var IPEndPoint = new System.Net.IPEndPoint(IPAddress.Any, Configuration.TcpPort);
  47. server = new Socket(IPEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  48. server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
  49. server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
  50. server.LingerState = new LingerOption(false, 0);
  51. server.Bind(IPEndPoint);
  52. server.Listen(Configuration.SoBacklog);
  53. }
  54. public Task StartAsync(CancellationToken cancellationToken)
  55. {
  56. Logger.LogInformation($"JT808 TCP Server start at {IPAddress.Any}:{Configuration.TcpPort}.");
  57. Task.Run(async() => {
  58. while (!cancellationToken.IsCancellationRequested)
  59. {
  60. var socket = await server.AcceptAsync();
  61. JT808TcpSession jT808TcpSession = new JT808TcpSession(socket);
  62. await Task.Factory.StartNew(async (state) =>
  63. {
  64. var session = (JT808TcpSession)state;
  65. SessionManager.TryAdd(session);
  66. if (Logger.IsEnabled(LogLevel.Information))
  67. {
  68. Logger.LogInformation($"[Connected]:{session.Client.RemoteEndPoint}");
  69. }
  70. var pipe = new Pipe();
  71. Task writing = FillPipeAsync(session, pipe.Writer);
  72. Task reading = ReadPipeAsync(session, pipe.Reader);
  73. await Task.WhenAll(reading, writing);
  74. SessionManager.RemoveBySessionId(session.SessionID);
  75. }, jT808TcpSession);
  76. }
  77. }, cancellationToken);
  78. return Task.CompletedTask;
  79. }
  80. private async Task FillPipeAsync(JT808TcpSession session, PipeWriter writer)
  81. {
  82. while (true)
  83. {
  84. try
  85. {
  86. Memory<byte> memory = writer.GetMemory(Configuration.MiniNumBufferSize);
  87. //设备多久没发数据就断开连接 Receive Timeout.
  88. int bytesRead = await session.Client.ReceiveAsync(memory, SocketFlags.None, session.ReceiveTimeout.Token);
  89. if (bytesRead == 0)
  90. {
  91. break;
  92. }
  93. writer.Advance(bytesRead);
  94. }
  95. catch(OperationCanceledException)
  96. {
  97. Logger.LogError($"[Receive Timeout]:{session.Client.RemoteEndPoint}");
  98. break;
  99. }
  100. catch (System.Net.Sockets.SocketException ex)
  101. {
  102. Logger.LogError($"[{ex.SocketErrorCode.ToString()},{ex.Message}]:{session.Client.RemoteEndPoint}");
  103. break;
  104. }
  105. catch (Exception ex)
  106. {
  107. Logger.LogError(ex, $"[Receive Error]:{session.Client.RemoteEndPoint}");
  108. break;
  109. }
  110. FlushResult result = await writer.FlushAsync();
  111. if (result.IsCompleted)
  112. {
  113. break;
  114. }
  115. }
  116. writer.Complete();
  117. }
  118. private async Task ReadPipeAsync(JT808TcpSession session, PipeReader reader)
  119. {
  120. while (true)
  121. {
  122. ReadResult result = await reader.ReadAsync();
  123. if (result.IsCompleted)
  124. {
  125. break;
  126. }
  127. ReadOnlySequence<byte> buffer = result.Buffer;
  128. SequencePosition consumed = buffer.Start;
  129. SequencePosition examined = buffer.End;
  130. try
  131. {
  132. if (result.IsCanceled) break;
  133. if (buffer.Length > 0)
  134. {
  135. ReaderBuffer(ref buffer, session,out consumed, out examined);
  136. }
  137. }
  138. catch (Exception ex)
  139. {
  140. SessionManager.RemoveBySessionId(session.SessionID);
  141. break;
  142. }
  143. finally
  144. {
  145. reader.AdvanceTo(consumed, examined);
  146. }
  147. }
  148. reader.Complete();
  149. }
  150. private void ReaderBuffer(ref ReadOnlySequence<byte> buffer, JT808TcpSession session, out SequencePosition consumed, out SequencePosition examined)
  151. {
  152. consumed = buffer.Start;
  153. examined = buffer.End;
  154. SequenceReader<byte> seqReader = new SequenceReader<byte>(buffer);
  155. if (seqReader.TryPeek(out byte beginMark))
  156. {
  157. if (beginMark != JT808Package.BeginFlag) throw new ArgumentException("Not JT808 Packages.");
  158. }
  159. byte mark = 0;
  160. long totalConsumed = 0;
  161. while (!seqReader.End)
  162. {
  163. if (seqReader.IsNext(JT808Package.BeginFlag, advancePast: true))
  164. {
  165. if (mark == 1)
  166. {
  167. ReadOnlySpan<byte> contentSpan=ReadOnlySpan<byte>.Empty;
  168. try
  169. {
  170. contentSpan = seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).FirstSpan;
  171. var package = Serializer.HeaderDeserialize(contentSpan,minBufferSize:10240);
  172. AtomicCounterService.MsgSuccessIncrement();
  173. if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Success Counter]:{AtomicCounterService.MsgSuccessCount}");
  174. if (Logger.IsEnabled(LogLevel.Trace)) Logger.LogTrace($"[Accept Hex {session.Client.RemoteEndPoint}]:{package.OriginalData.ToArray().ToHexString()}");
  175. SessionManager.TryLink(package.Header.TerminalPhoneNo, session);
  176. MsgProducer.ProduceAsync(package.Header.TerminalPhoneNo, package.OriginalData.ToArray());
  177. }
  178. catch (JT808Exception ex)
  179. {
  180. AtomicCounterService.MsgFailIncrement();
  181. if (Logger.IsEnabled(LogLevel.Information)) Logger.LogInformation($"[Atomic Fail Counter]:{AtomicCounterService.MsgFailCount}");
  182. Logger.LogError($"[HeaderDeserialize ErrorCode]:{ ex.ErrorCode},[ReaderBuffer]:{contentSpan.ToArray().ToHexString()}");
  183. }
  184. totalConsumed += (seqReader.Consumed - totalConsumed);
  185. if (seqReader.End) break;
  186. seqReader.Advance(1);
  187. mark = 0;
  188. }
  189. mark++;
  190. }
  191. else
  192. {
  193. seqReader.Advance(1);
  194. }
  195. }
  196. if (seqReader.Length== totalConsumed)
  197. {
  198. examined = consumed = buffer.End;
  199. }
  200. else
  201. {
  202. consumed = buffer.GetPosition(totalConsumed);
  203. }
  204. }
  205. public Task StopAsync(CancellationToken cancellationToken)
  206. {
  207. Logger.LogInformation("808 Tcp Server Stop");
  208. if (server?.Connected ?? false)
  209. server.Shutdown(SocketShutdown.Both);
  210. server?.Close();
  211. return Task.CompletedTask;
  212. }
  213. }
  214. }