AsyncSocketListener.cs 4.9 KB

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