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

DefaultUdpSocket.cs 4.1 kB

8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. namespace Discord.Net.Udp
  7. {
  8. internal class DefaultUdpSocket : IUdpSocket, IDisposable
  9. {
  10. public event Func<byte[], int, int, Task> ReceivedDatagram;
  11. private readonly SemaphoreSlim _lock;
  12. private UdpClient _udp;
  13. private IPEndPoint _destination;
  14. private CancellationTokenSource _cancelTokenSource;
  15. private CancellationToken _cancelToken, _parentToken;
  16. private Task _task;
  17. private bool _isDisposed;
  18. public ushort Port => (ushort)((_udp?.Client.LocalEndPoint as IPEndPoint)?.Port ?? 0);
  19. public DefaultUdpSocket()
  20. {
  21. _lock = new SemaphoreSlim(1, 1);
  22. _cancelTokenSource = new CancellationTokenSource();
  23. }
  24. private void Dispose(bool disposing)
  25. {
  26. if (!_isDisposed)
  27. {
  28. if (disposing)
  29. StopInternalAsync(true).GetAwaiter().GetResult();
  30. _isDisposed = true;
  31. }
  32. }
  33. public void Dispose()
  34. {
  35. Dispose(true);
  36. }
  37. public async Task StartAsync()
  38. {
  39. await _lock.WaitAsync().ConfigureAwait(false);
  40. try
  41. {
  42. await StartInternalAsync(_cancelToken).ConfigureAwait(false);
  43. }
  44. finally
  45. {
  46. _lock.Release();
  47. }
  48. }
  49. public async Task StartInternalAsync(CancellationToken cancelToken)
  50. {
  51. await StopInternalAsync().ConfigureAwait(false);
  52. _cancelTokenSource = new CancellationTokenSource();
  53. _cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_parentToken, _cancelTokenSource.Token).Token;
  54. _udp = new UdpClient(0);
  55. _task = RunAsync(_cancelToken);
  56. }
  57. public async Task StopAsync()
  58. {
  59. await _lock.WaitAsync().ConfigureAwait(false);
  60. try
  61. {
  62. await StopInternalAsync().ConfigureAwait(false);
  63. }
  64. finally
  65. {
  66. _lock.Release();
  67. }
  68. }
  69. public async Task StopInternalAsync(bool isDisposing = false)
  70. {
  71. try { _cancelTokenSource.Cancel(false); } catch { }
  72. if (!isDisposing)
  73. await (_task ?? Task.Delay(0)).ConfigureAwait(false);
  74. if (_udp != null)
  75. {
  76. #if UDPDISPOSE
  77. try { _udp.Dispose(); }
  78. #else
  79. try { _udp.Close(); }
  80. #endif
  81. catch { }
  82. _udp = null;
  83. }
  84. }
  85. public void SetDestination(string ip, int port)
  86. {
  87. _destination = new IPEndPoint(IPAddress.Parse(ip), port);
  88. }
  89. public void SetCancelToken(CancellationToken cancelToken)
  90. {
  91. _parentToken = cancelToken;
  92. _cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_parentToken, _cancelTokenSource.Token).Token;
  93. }
  94. public async Task SendAsync(byte[] data, int index, int count)
  95. {
  96. if (index != 0) //Should never happen?
  97. {
  98. var newData = new byte[count];
  99. Buffer.BlockCopy(data, index, newData, 0, count);
  100. data = newData;
  101. }
  102. await _udp.SendAsync(data, count, _destination).ConfigureAwait(false);
  103. }
  104. private async Task RunAsync(CancellationToken cancelToken)
  105. {
  106. var closeTask = Task.Delay(-1, cancelToken);
  107. while (!cancelToken.IsCancellationRequested)
  108. {
  109. var receiveTask = _udp.ReceiveAsync();
  110. var task = await Task.WhenAny(closeTask, receiveTask).ConfigureAwait(false);
  111. if (task == closeTask)
  112. break;
  113. var result = receiveTask.Result;
  114. await ReceivedDatagram(result.Buffer, 0, result.Buffer.Length).ConfigureAwait(false);
  115. }
  116. }
  117. }
  118. }