AsyncSocketListener.cs 4.2 KB

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