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.

MqttWebSocketChannel.cs 3.6 KiB

7 年之前
7 年之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using MQTTnet.Core.Channel;
  2. using MQTTnet.Core.Client;
  3. using MQTTnet.Core.Exceptions;
  4. using System;
  5. using System.Net.WebSockets;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace MQTTnet.Implementations
  9. {
  10. public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable
  11. {
  12. private ClientWebSocket _webSocket = new ClientWebSocket();
  13. private const int BufferSize = 4096;
  14. private const int BufferAmplifier = 20;
  15. private readonly byte[] WebSocketBuffer = new byte[BufferSize * BufferAmplifier];
  16. private int WebSocketBufferSize;
  17. private int WebSocketBufferOffset;
  18. public Task ConnectAsync(MqttClientOptions options)
  19. {
  20. _webSocket = null;
  21. try
  22. {
  23. _webSocket = new ClientWebSocket();
  24. return _webSocket.ConnectAsync(new Uri(options.Server), CancellationToken.None);
  25. }
  26. catch (WebSocketException exception)
  27. {
  28. throw new MqttCommunicationException(exception);
  29. }
  30. }
  31. public Task DisconnectAsync()
  32. {
  33. return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
  34. }
  35. public void Dispose()
  36. {
  37. _webSocket?.Dispose();
  38. }
  39. public Task ReadAsync(byte[] buffer)
  40. {
  41. return Task.WhenAll(ReadToBufferAsync(buffer));
  42. }
  43. private async Task ReadToBufferAsync(byte[] buffer)
  44. {
  45. var temporaryBuffer = new byte[BufferSize];
  46. var offset = 0;
  47. while (_webSocket.State == WebSocketState.Open)
  48. {
  49. if (WebSocketBufferSize == 0)
  50. {
  51. WebSocketBufferOffset = 0;
  52. WebSocketReceiveResult response;
  53. do
  54. {
  55. response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(temporaryBuffer), CancellationToken.None).ConfigureAwait(false);
  56. temporaryBuffer.CopyTo(WebSocketBuffer, offset);
  57. offset += response.Count;
  58. temporaryBuffer = new byte[BufferSize];
  59. } while (!response.EndOfMessage);
  60. WebSocketBufferSize = response.Count;
  61. if (response.MessageType == WebSocketMessageType.Close)
  62. {
  63. await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false);
  64. }
  65. Buffer.BlockCopy(WebSocketBuffer, 0, buffer, 0, buffer.Length);
  66. WebSocketBufferSize -= buffer.Length;
  67. WebSocketBufferOffset += buffer.Length;
  68. }
  69. else
  70. {
  71. Buffer.BlockCopy(WebSocketBuffer, WebSocketBufferOffset, buffer, 0, buffer.Length);
  72. WebSocketBufferSize -= buffer.Length;
  73. WebSocketBufferOffset += buffer.Length;
  74. }
  75. return;
  76. }
  77. }
  78. public Task WriteAsync(byte[] buffer)
  79. {
  80. if (buffer == null) {
  81. throw new ArgumentNullException(nameof(buffer));
  82. }
  83. try
  84. {
  85. return _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Binary, true,
  86. CancellationToken.None);
  87. }
  88. catch (WebSocketException exception)
  89. {
  90. throw new MqttCommunicationException(exception);
  91. }
  92. }
  93. }
  94. }