UdpServer.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using MediaBrowser.Common.Implementations.NetworkManagement;
  2. using MediaBrowser.Common.Net;
  3. using MediaBrowser.Model.Logging;
  4. using System;
  5. using System.Net;
  6. using System.Net.Sockets;
  7. using System.Reactive.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace MediaBrowser.Server.Implementations.Udp
  11. {
  12. /// <summary>
  13. /// Provides a Udp Server
  14. /// </summary>
  15. public class UdpServer : IUdpServer
  16. {
  17. /// <summary>
  18. /// Occurs when [message received].
  19. /// </summary>
  20. public event EventHandler<UdpMessageReceivedEventArgs> MessageReceived;
  21. /// <summary>
  22. /// Gets or sets the logger.
  23. /// </summary>
  24. /// <value>The logger.</value>
  25. private ILogger Logger { get; set; }
  26. /// <summary>
  27. /// Initializes a new instance of the <see cref="UdpServer" /> class.
  28. /// </summary>
  29. /// <param name="logger">The logger.</param>
  30. public UdpServer(ILogger logger)
  31. {
  32. Logger = logger;
  33. }
  34. /// <summary>
  35. /// Raises the <see cref="E:MessageReceived" /> event.
  36. /// </summary>
  37. /// <param name="e">The <see cref="UdpMessageReceivedEventArgs" /> instance containing the event data.</param>
  38. protected virtual void OnMessageReceived(UdpMessageReceivedEventArgs e)
  39. {
  40. EventHandler<UdpMessageReceivedEventArgs> handler = MessageReceived;
  41. if (handler != null) handler(this, e);
  42. }
  43. /// <summary>
  44. /// The _udp client
  45. /// </summary>
  46. private UdpClient _udpClient;
  47. /// <summary>
  48. /// Starts the specified port.
  49. /// </summary>
  50. /// <param name="port">The port.</param>
  51. public void Start(int port)
  52. {
  53. _udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, port));
  54. _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
  55. CreateObservable().Subscribe(OnMessageReceived);
  56. }
  57. /// <summary>
  58. /// Creates the observable.
  59. /// </summary>
  60. /// <returns>IObservable{UdpReceiveResult}.</returns>
  61. private IObservable<UdpReceiveResult> CreateObservable()
  62. {
  63. return Observable.Create<UdpReceiveResult>(obs =>
  64. Observable.FromAsync(() =>
  65. {
  66. try
  67. {
  68. return _udpClient.ReceiveAsync();
  69. }
  70. catch (ObjectDisposedException)
  71. {
  72. return Task.FromResult(new UdpReceiveResult(new byte[]{}, new IPEndPoint(IPAddress.Any, 0)));
  73. }
  74. catch (Exception ex)
  75. {
  76. Logger.ErrorException("Error receiving udp message", ex);
  77. return Task.FromResult(new UdpReceiveResult(new byte[] { }, new IPEndPoint(IPAddress.Any, 0)));
  78. }
  79. })
  80. .Subscribe(obs))
  81. .Repeat()
  82. .Retry()
  83. .Publish()
  84. .RefCount();
  85. }
  86. /// <summary>
  87. /// Called when [message received].
  88. /// </summary>
  89. /// <param name="message">The message.</param>
  90. private void OnMessageReceived(UdpReceiveResult message)
  91. {
  92. if (message.RemoteEndPoint.Port == 0)
  93. {
  94. return;
  95. }
  96. var bytes = message.Buffer;
  97. OnMessageReceived(new UdpMessageReceivedEventArgs
  98. {
  99. Bytes = bytes,
  100. RemoteEndPoint = message.RemoteEndPoint.ToString()
  101. });
  102. }
  103. /// <summary>
  104. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  105. /// </summary>
  106. public void Dispose()
  107. {
  108. Dispose(true);
  109. GC.SuppressFinalize(this);
  110. }
  111. /// <summary>
  112. /// Stops this instance.
  113. /// </summary>
  114. public void Stop()
  115. {
  116. if (_udpClient != null)
  117. {
  118. _udpClient.Close();
  119. }
  120. }
  121. /// <summary>
  122. /// Releases unmanaged and - optionally - managed resources.
  123. /// </summary>
  124. /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  125. protected virtual void Dispose(bool dispose)
  126. {
  127. if (dispose)
  128. {
  129. Stop();
  130. }
  131. }
  132. /// <summary>
  133. /// Sends the async.
  134. /// </summary>
  135. /// <param name="data">The data.</param>
  136. /// <param name="ipAddress">The ip address.</param>
  137. /// <param name="port">The port.</param>
  138. /// <returns>Task{System.Int32}.</returns>
  139. /// <exception cref="System.ArgumentNullException">data</exception>
  140. public Task SendAsync(string data, string ipAddress, int port)
  141. {
  142. return SendAsync(Encoding.UTF8.GetBytes(data), ipAddress, port);
  143. }
  144. /// <summary>
  145. /// Sends the async.
  146. /// </summary>
  147. /// <param name="bytes">The bytes.</param>
  148. /// <param name="ipAddress">The ip address.</param>
  149. /// <param name="port">The port.</param>
  150. /// <returns>Task{System.Int32}.</returns>
  151. /// <exception cref="System.ArgumentNullException">bytes</exception>
  152. public Task SendAsync(byte[] bytes, string ipAddress, int port)
  153. {
  154. if (bytes == null)
  155. {
  156. throw new ArgumentNullException("bytes");
  157. }
  158. if (string.IsNullOrEmpty(ipAddress))
  159. {
  160. throw new ArgumentNullException("ipAddress");
  161. }
  162. return _udpClient.SendAsync(bytes, bytes.Length, ipAddress, port);
  163. }
  164. /// <summary>
  165. /// Sends the async.
  166. /// </summary>
  167. /// <param name="bytes">The bytes.</param>
  168. /// <param name="remoteEndPoint">The remote end point.</param>
  169. /// <returns>Task.</returns>
  170. public Task SendAsync(byte[] bytes, string remoteEndPoint)
  171. {
  172. if (bytes == null)
  173. {
  174. throw new ArgumentNullException("bytes");
  175. }
  176. if (string.IsNullOrEmpty(remoteEndPoint))
  177. {
  178. throw new ArgumentNullException("remoteEndPoint");
  179. }
  180. return _udpClient.SendAsync(bytes, bytes.Length, new NetworkManager().Parse(remoteEndPoint));
  181. }
  182. }
  183. }