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.
 
 
 
 

105 lines
3.1 KiB

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