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.
 
 
 
 

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