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.
 
 
 
 

97 lines
2.8 KiB

  1. using System;
  2. using System.Buffers;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO.Pipelines;
  6. using System.Net.Sockets;
  7. namespace MQTTnet.AspNetCore.Client.Tcp
  8. {
  9. public class SocketSender
  10. {
  11. private readonly Socket _socket;
  12. private readonly SocketAsyncEventArgs _eventArgs = new SocketAsyncEventArgs();
  13. private readonly SocketAwaitable _awaitable;
  14. private List<ArraySegment<byte>> _bufferList;
  15. public SocketSender(Socket socket, PipeScheduler scheduler)
  16. {
  17. _socket = socket;
  18. _awaitable = new SocketAwaitable(scheduler);
  19. _eventArgs.UserToken = _awaitable;
  20. _eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError);
  21. }
  22. public SocketAwaitable SendAsync(in ReadOnlySequence<byte> buffers)
  23. {
  24. if (buffers.IsSingleSegment)
  25. {
  26. return SendAsync(buffers.First);
  27. }
  28. #if NETCOREAPP2_1
  29. if (!_eventArgs.MemoryBuffer.Equals(Memory<byte>.Empty))
  30. #else
  31. if (_eventArgs.Buffer != null)
  32. #endif
  33. {
  34. _eventArgs.SetBuffer(null, 0, 0);
  35. }
  36. _eventArgs.BufferList = GetBufferList(buffers);
  37. if (!_socket.SendAsync(_eventArgs))
  38. {
  39. _awaitable.Complete(_eventArgs.BytesTransferred, _eventArgs.SocketError);
  40. }
  41. return _awaitable;
  42. }
  43. private SocketAwaitable SendAsync(ReadOnlyMemory<byte> memory)
  44. {
  45. // The BufferList getter is much less expensive then the setter.
  46. if (_eventArgs.BufferList != null)
  47. {
  48. _eventArgs.BufferList = null;
  49. }
  50. #if NETCOREAPP2_1
  51. _eventArgs.SetBuffer(MemoryMarshal.AsMemory(memory));
  52. #else
  53. var segment = memory.GetArray();
  54. _eventArgs.SetBuffer(segment.Array, segment.Offset, segment.Count);
  55. #endif
  56. if (!_socket.SendAsync(_eventArgs))
  57. {
  58. _awaitable.Complete(_eventArgs.BytesTransferred, _eventArgs.SocketError);
  59. }
  60. return _awaitable;
  61. }
  62. private List<ArraySegment<byte>> GetBufferList(in ReadOnlySequence<byte> buffer)
  63. {
  64. Debug.Assert(!buffer.IsEmpty);
  65. Debug.Assert(!buffer.IsSingleSegment);
  66. if (_bufferList == null)
  67. {
  68. _bufferList = new List<ArraySegment<byte>>();
  69. }
  70. else
  71. {
  72. // Buffers are pooled, so it's OK to root them until the next multi-buffer write.
  73. _bufferList.Clear();
  74. }
  75. foreach (var b in buffer)
  76. {
  77. _bufferList.Add(b.GetArray());
  78. }
  79. return _bufferList;
  80. }
  81. }
  82. }