AsyncSocketListener.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 delegate void ConnectedHandler(Socket socket);
  16. public event BytesReceivedHandler BytesReceived;
  17. public event ConnectedHandler Connected;
  18. public AsyncSocketListener(IPEndPoint endPoint)
  19. {
  20. _endPoint = endPoint;
  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. SignalConnected(handler);
  71. var state = new SocketStateObject(handler);
  72. handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
  73. }
  74. catch (ObjectDisposedException)
  75. {
  76. // when the socket is closed, an ObjectDisposedException is thrown
  77. // by Socket.EndAccept(IAsyncResult)
  78. }
  79. }
  80. private void ReadCallback(IAsyncResult ar)
  81. {
  82. // Retrieve the state object and the handler socket
  83. // from the asynchronous state object.
  84. var state = (SocketStateObject)ar.AsyncState;
  85. var handler = state.Socket;
  86. // Read data from the client socket.
  87. var bytesRead = handler.EndReceive(ar);
  88. if (bytesRead > 0)
  89. {
  90. var bytesReceived = new byte[bytesRead];
  91. Array.Copy(state.Buffer, bytesReceived, bytesRead);
  92. SignalBytesReceived(bytesReceived, handler);
  93. // prepare to receive more bytes
  94. try
  95. {
  96. handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
  97. }
  98. catch (ObjectDisposedException)
  99. {
  100. // when the socket is closed, an ObjectDisposedException is thrown
  101. }
  102. }
  103. }
  104. private void SignalBytesReceived(byte[] bytesReceived, Socket client)
  105. {
  106. var subscribers = BytesReceived;
  107. if (subscribers != null)
  108. subscribers(bytesReceived, client);
  109. }
  110. private void SignalConnected(Socket client)
  111. {
  112. var subscribers = Connected;
  113. if (subscribers != null)
  114. subscribers(client);
  115. }
  116. private class SocketStateObject
  117. {
  118. public Socket Socket { get; private set; }
  119. public readonly byte[] Buffer = new byte[1024];
  120. public SocketStateObject(Socket handler)
  121. {
  122. Socket = handler;
  123. }
  124. }
  125. }
  126. }