You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

105 lines
3.9 KiB

  1. using DotNetty.Buffers;
  2. using DotNetty.Codecs;
  3. using DotNetty.Handlers.Timeout;
  4. using DotNetty.Transport.Bootstrapping;
  5. using DotNetty.Transport.Channels;
  6. using DotNetty.Transport.Channels.Sockets;
  7. using DotNetty.Transport.Libuv;
  8. using JT808.DotNetty.Client.Handlers;
  9. using Microsoft.Extensions.Logging;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Runtime.InteropServices;
  13. using System.Text;
  14. using Microsoft.Extensions.DependencyInjection;
  15. using System.Net;
  16. using System.Threading.Tasks;
  17. using JT808.DotNetty.Client.Metadata;
  18. using JT808.DotNetty.Client.Codecs;
  19. namespace JT808.DotNetty.Client
  20. {
  21. public sealed class JT808TcpClient : IDisposable
  22. {
  23. private MultithreadEventLoopGroup group;
  24. private IChannel clientChannel;
  25. private bool disposed = false;
  26. public DeviceConfig DeviceConfig { get; private set; }
  27. public ILoggerFactory LoggerFactory { get; private set; }
  28. public JT808TcpClient(DeviceConfig deviceConfig, IServiceProvider serviceProvider)
  29. {
  30. DeviceConfig = deviceConfig;
  31. LoggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
  32. group = new MultithreadEventLoopGroup(1);
  33. Bootstrap bootstrap = new Bootstrap();
  34. bootstrap.Group(group);
  35. bootstrap.Channel<TcpSocketChannel>();
  36. if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  37. {
  38. bootstrap.Option(ChannelOption.SoReuseport, true);
  39. }
  40. bootstrap
  41. .Option(ChannelOption.SoBacklog, 8192)
  42. .Handler(new ActionChannelInitializer<IChannel>(channel =>
  43. {
  44. channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue,
  45. Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }),
  46. Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag })));
  47. channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(60, deviceConfig.Heartbeat, 3600));
  48. channel.Pipeline.AddLast("jt808TcpDecode", new JT808ClientTcpDecoder());
  49. channel.Pipeline.AddLast("jt808TcpEncode", new JT808ClientTcpEncoder(LoggerFactory));
  50. channel.Pipeline.AddLast("jt808TcpClientConnection", new JT808TcpClientConnectionHandler(this));
  51. channel.Pipeline.AddLast("jt808TcpService", new JT808TcpClientHandler(this));
  52. }));
  53. clientChannel = bootstrap.ConnectAsync(IPAddress.Parse(DeviceConfig.TcpHost), DeviceConfig.TcpPort).Result;
  54. }
  55. public async void Send(JT808ClientRequest request)
  56. {
  57. if (disposed) return;
  58. if (clientChannel == null) throw new NullReferenceException("Channel is empty.");
  59. if (request == null) throw new ArgumentNullException("JT808ClientRequest Parameter is empty.");
  60. if (clientChannel.Active && clientChannel.Open)
  61. {
  62. await clientChannel.WriteAndFlushAsync(request);
  63. }
  64. }
  65. private void Dispose(bool disposing)
  66. {
  67. if (disposed)
  68. {
  69. return;
  70. }
  71. if (disposing)
  72. {
  73. // 清理托管资源
  74. group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));
  75. }
  76. disposed = true;
  77. }
  78. ~JT808TcpClient()
  79. {
  80. //必须为false
  81. //这表明,隐式清理时,只要处理非托管资源就可以了。
  82. Dispose(false);
  83. }
  84. public void Dispose()
  85. {
  86. //必须为true
  87. Dispose(true);
  88. //通知垃圾回收机制不再调用终结器(析构器)
  89. GC.SuppressFinalize(this);
  90. }
  91. }
  92. }