UdpServer.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using MediaBrowser.Common.Net;
  2. using MediaBrowser.Model.Logging;
  3. using MediaBrowser.Networking.Management;
  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.Networking.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. _udpClient.Close();
  117. }
  118. /// <summary>
  119. /// Releases unmanaged and - optionally - managed resources.
  120. /// </summary>
  121. /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  122. protected virtual void Dispose(bool dispose)
  123. {
  124. if (dispose)
  125. {
  126. Stop();
  127. }
  128. }
  129. /// <summary>
  130. /// Sends the async.
  131. /// </summary>
  132. /// <param name="data">The data.</param>
  133. /// <param name="ipAddress">The ip address.</param>
  134. /// <param name="port">The port.</param>
  135. /// <returns>Task{System.Int32}.</returns>
  136. /// <exception cref="System.ArgumentNullException">data</exception>
  137. public Task SendAsync(string data, string ipAddress, int port)
  138. {
  139. return SendAsync(Encoding.UTF8.GetBytes(data), ipAddress, port);
  140. }
  141. /// <summary>
  142. /// Sends the async.
  143. /// </summary>
  144. /// <param name="bytes">The bytes.</param>
  145. /// <param name="ipAddress">The ip address.</param>
  146. /// <param name="port">The port.</param>
  147. /// <returns>Task{System.Int32}.</returns>
  148. /// <exception cref="System.ArgumentNullException">bytes</exception>
  149. public Task SendAsync(byte[] bytes, string ipAddress, int port)
  150. {
  151. if (bytes == null)
  152. {
  153. throw new ArgumentNullException("bytes");
  154. }
  155. if (string.IsNullOrEmpty(ipAddress))
  156. {
  157. throw new ArgumentNullException("ipAddress");
  158. }
  159. return _udpClient.SendAsync(bytes, bytes.Length, ipAddress, port);
  160. }
  161. /// <summary>
  162. /// Sends the async.
  163. /// </summary>
  164. /// <param name="bytes">The bytes.</param>
  165. /// <param name="remoteEndPoint">The remote end point.</param>
  166. /// <returns>Task.</returns>
  167. public Task SendAsync(byte[] bytes, string remoteEndPoint)
  168. {
  169. if (bytes == null)
  170. {
  171. throw new ArgumentNullException("bytes");
  172. }
  173. if (string.IsNullOrEmpty(remoteEndPoint))
  174. {
  175. throw new ArgumentNullException("remoteEndPoint");
  176. }
  177. return _udpClient.SendAsync(bytes, bytes.Length, new NetworkManager().Parse(remoteEndPoint));
  178. }
  179. }
  180. }