AsyncSocketListener.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Threading;
  5. namespace Renci.SshNet.Tests.Common
  6. {
  7. public class AsyncSocketListener : IDisposable
  8. {
  9. private readonly IPEndPoint _endPoint;
  10. private readonly string _id;
  11. private readonly ManualResetEvent _acceptCallbackDone;
  12. private Socket _listener;
  13. private Thread _receiveThread;
  14. private bool _started;
  15. public delegate void BytesReceivedHandler(byte[] bytesReceived, Socket socket);
  16. public event BytesReceivedHandler BytesReceived;
  17. public AsyncSocketListener(IPEndPoint endPoint, string id)
  18. {
  19. _endPoint = endPoint;
  20. _id = id;
  21. _acceptCallbackDone = new ManualResetEvent(false);
  22. }
  23. public void Start()
  24. {
  25. _listener = new Socket(_endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  26. _listener.Bind(_endPoint);
  27. _listener.Listen(1);
  28. _started = true;
  29. _receiveThread = new Thread(StartListener);
  30. _receiveThread.Start(_listener);
  31. }
  32. public void Stop()
  33. {
  34. _started = false;
  35. if (_listener != null)
  36. {
  37. _listener.Dispose();
  38. _listener = null;
  39. }
  40. if (_receiveThread != null)
  41. {
  42. _receiveThread.Join();
  43. _receiveThread = null;
  44. }
  45. }
  46. public void Dispose()
  47. {
  48. Stop();
  49. GC.SuppressFinalize(this);
  50. }
  51. private void StartListener(object state)
  52. {
  53. var listener = (Socket)state;
  54. while (_started)
  55. {
  56. _acceptCallbackDone.Reset();
  57. listener.BeginAccept(AcceptCallback, listener);
  58. _acceptCallbackDone.WaitOne();
  59. }
  60. }
  61. private void AcceptCallback(IAsyncResult ar)
  62. {
  63. // Signal the main thread to continue.
  64. _acceptCallbackDone.Set();
  65. // Get the socket that handles the client request.
  66. var listener = (Socket)ar.AsyncState;
  67. try
  68. {
  69. var handler = listener.EndAccept(ar);
  70. var state = new SocketStateObject(handler);
  71. handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
  72. }
  73. catch (ObjectDisposedException)
  74. {
  75. // when the socket is closed, an ObjectDisposedException is thrown
  76. // by Socket.EndAccept(IAsyncResult)
  77. }
  78. }
  79. private void ReadCallback(IAsyncResult ar)
  80. {
  81. // Retrieve the state object and the handler socket
  82. // from the asynchronous state object.
  83. var state = (SocketStateObject)ar.AsyncState;
  84. var handler = state.Socket;
  85. // Read data from the client socket.
  86. var bytesRead = handler.EndReceive(ar);
  87. if (bytesRead > 0)
  88. {
  89. var bytesReceived = new byte[bytesRead];
  90. Array.Copy(state.Buffer, bytesReceived, bytesRead);
  91. SignalBytesReceived(bytesReceived, handler);
  92. // prepare to receive more bytes
  93. try
  94. {
  95. handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
  96. }
  97. catch (ObjectDisposedException)
  98. {
  99. // when the socket is closed, an ObjectDisposedException is thrown
  100. }
  101. }
  102. }
  103. private void SignalBytesReceived(byte[] bytesReceived, Socket client)
  104. {
  105. var subscribers = BytesReceived;
  106. if (subscribers != null)
  107. subscribers(bytesReceived, client);
  108. }
  109. private class SocketStateObject
  110. {
  111. public Socket Socket { get; private set; }
  112. public readonly byte[] Buffer = new byte[1024];
  113. public SocketStateObject(Socket handler)
  114. {
  115. Socket = handler;
  116. }
  117. }
  118. }
  119. }