UdpCommunication.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Newtonsoft.Json;
  8. using TeamAAS.Communication.Attributes;
  9. using TeamAAS.Communication.Base;
  10. using TeamAAS.Communication.Interfaces;
  11. namespace TeamAAS.Communication.Devices
  12. {
  13. /// <summary>
  14. /// UDP 通讯(数据报协议,无连接,广播/多播支持)。
  15. /// </summary>
  16. [Communication("UDP", "基础通讯", "UDP 数据报通讯")]
  17. public class UdpCommunication : BindableCommunicationBase
  18. {
  19. [JsonIgnore]
  20. private UdpClient _udpClient;
  21. private readonly ConcurrentQueue<string> _received = new ConcurrentQueue<string>();
  22. private string _localIp = "0.0.0.0";
  23. public string LocalIp
  24. {
  25. get { return _localIp; }
  26. set { if (SetProperty(ref _localIp, value)) Notify(nameof(EndpointUrl)); }
  27. }
  28. private int _localPort = 8888;
  29. public int LocalPort
  30. {
  31. get { return _localPort; }
  32. set { if (SetProperty(ref _localPort, value)) Notify(nameof(EndpointUrl)); }
  33. }
  34. private string _remoteIp = "127.0.0.1";
  35. public string RemoteIp
  36. {
  37. get { return _remoteIp; }
  38. set { if (SetProperty(ref _remoteIp, value)) Notify(nameof(EndpointUrl)); }
  39. }
  40. private int _remotePort = 9999;
  41. public int RemotePort
  42. {
  43. get { return _remotePort; }
  44. set { if (SetProperty(ref _remotePort, value)) Notify(nameof(EndpointUrl)); }
  45. }
  46. public override string EndpointUrl
  47. {
  48. get { return $"udp://{LocalIp}:{LocalPort} -> {RemoteIp}:{RemotePort}"; }
  49. set
  50. {
  51. if (!string.IsNullOrWhiteSpace(value) && value.StartsWith("udp://"))
  52. {
  53. var uri = new Uri(value);
  54. if (!string.IsNullOrWhiteSpace(uri.Host)) LocalIp = uri.Host;
  55. if (uri.Port > 0) LocalPort = uri.Port;
  56. }
  57. }
  58. }
  59. [JsonIgnore]
  60. public override bool IsConnected => _udpClient != null;
  61. public override event Action<object, bool> ConnectChangedEvent;
  62. public override event Action<object, string> DataReceivedEvent;
  63. public override void Connect()
  64. {
  65. Disconnect();
  66. IPAddress bindIp = IPAddress.Any;
  67. if (!string.IsNullOrWhiteSpace(LocalIp))
  68. {
  69. try { bindIp = IPAddress.Parse(LocalIp.Trim()); }
  70. catch { bindIp = IPAddress.Any; }
  71. }
  72. _udpClient = new UdpClient(LocalPort)
  73. {
  74. ExclusiveAddressUse = false
  75. };
  76. try
  77. {
  78. _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
  79. }
  80. catch { }
  81. _ = Task.Run(ReceiveLoop);
  82. ConnectChangedEvent?.Invoke(this, true);
  83. Notify(nameof(IsConnected));
  84. }
  85. public override Task ConnectAsync()
  86. {
  87. return Task.Run(() => Connect());
  88. }
  89. private async Task ReceiveLoop()
  90. {
  91. try
  92. {
  93. while (_udpClient != null)
  94. {
  95. var result = await _udpClient.ReceiveAsync();
  96. var text = Encoding.UTF8.GetString(result.Buffer, 0, result.Buffer.Length);
  97. _received.Enqueue(text);
  98. DataReceivedEvent?.Invoke(this, text);
  99. }
  100. }
  101. catch
  102. {
  103. }
  104. }
  105. public void Send(string text)
  106. {
  107. if (_udpClient == null)
  108. throw new InvalidOperationException("UDP 未连接。");
  109. var data = Encoding.UTF8.GetBytes(text ?? string.Empty);
  110. var endPoint = new IPEndPoint(IPAddress.Parse(RemoteIp), RemotePort);
  111. _udpClient.Send(data, data.Length, endPoint);
  112. }
  113. public void Send(byte[] data)
  114. {
  115. if (_udpClient == null)
  116. throw new InvalidOperationException("UDP 未连接。");
  117. var endPoint = new IPEndPoint(IPAddress.Parse(RemoteIp), RemotePort);
  118. _udpClient.Send(data, data.Length, endPoint);
  119. }
  120. public override object ReadValue(string address)
  121. {
  122. _received.TryDequeue(out var text);
  123. return text;
  124. }
  125. public override Task<object> ReadValueAsync(string address)
  126. {
  127. return Task.FromResult(ReadValue(address));
  128. }
  129. public override void WriteValue(string address, object value)
  130. {
  131. Send(value?.ToString() ?? string.Empty);
  132. }
  133. public override Task WriteValueAsync(string address, object value)
  134. {
  135. Send(value?.ToString() ?? string.Empty);
  136. return Task.CompletedTask;
  137. }
  138. public override void Disconnect()
  139. {
  140. if (_udpClient != null)
  141. {
  142. try { _udpClient.Close(); } catch { }
  143. _udpClient.Dispose();
  144. _udpClient = null;
  145. }
  146. ConnectChangedEvent?.Invoke(this, false);
  147. Notify(nameof(IsConnected));
  148. }
  149. public override void Dispose()
  150. {
  151. Disconnect();
  152. }
  153. }
  154. }