- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有这个代码...
internal static void Start()
{
TcpListener listenerSocket = new TcpListener(IPAddress.Any, 32599);
listenerSocket.Start();
listenerSocket.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), null);
}
然后我的回调函数看起来像这样......
private static void AcceptClient(IAsyncResult asyncResult)
{
MessageHandler handler = new MessageHandler(listenerSocket.EndAcceptTcpClient(asyncResult));
ThreadPool.QueueUserWorkItem((object state) => handler.Process());
listenerSocket.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), null);
}
现在,我调用 BeginAcceptTcpClient,然后一段时间后我想停止服务器。为此,我一直在调用 TcpListener.Stop() 或 TcpListener.Server.Close()。然而,这两个都执行我的 AcceptClient 函数。当我调用 EndAcceptTcpClient 时,这会引发异常。解决这个问题的最佳做法是什么?我可以在调用 stop 后放入一个标志来停止 AcceptClient 的执行,但我想知道我是否遗漏了什么。
更新 1
目前我已经通过将代码更改为如下所示对其进行了修补。
private static void AcceptClient(IAsyncResult asyncResult)
{
if (!shutdown)
{
MessageHandler handler = new MessageHandler(listenerSocket.EndAcceptTcpClient(asyncResult));
ThreadPool.QueueUserWorkItem((object state) => handler.Process());
listenerSocket.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), null);
}
}
private static bool shutdown = false;
internal static void Stop()
{
shutdown = true;
listenerSocket.Stop();
}
更新 2
我将其更改为暗示 Spencer Ruport 的回答。
private static void AcceptClient(IAsyncResult asyncResult)
{
if (listenerSocket.Server.IsBound)
{
MessageHandler handler = new MessageHandler(listenerSocket.EndAcceptTcpClient(asyncResult));
ThreadPool.QueueUserWorkItem((object state) => handler.Process());
listenerSocket.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), null);
}
}
最佳答案
我自己刚遇到这个问题,我认为您当前的解决方案不完整/不正确。在检查 IsBound
和随后调用 EndAcceptTcpClient()
之间不保证原子性。如果监听器在这两个语句之间 Stop()
,您仍然可以获得异常。您没有说明您得到的是什么异常,但我认为它与我得到的是同一个异常,ObjectDisposedException
(提示底层套接字已被处置)。
您应该能够通过模拟线程调度来检查这一点:
IsBound
检查回调后的行上设置断点TcpListener.Stop()
的代码EndAcceptTcpClient()
调用。您应该会看到 ObjectDisposedException
。在这种情况下,IMO 的理想解决方案是让 Microsoft 抛出与 EndAcceptTcpClient
不同的异常,例如ListenCanceledException
或类似的东西。
实际上,我们必须从 ObjectDisposedException
推断发生了什么。只需捕获异常并相应地进行操作即可。在我的代码中,我默默地吃掉了异常,因为我在其他地方有代码在做真正的关闭工作(即首先调用 TcpListener.Stop()
的代码)。无论如何,您应该已经在该区域进行了异常处理,因为您可以获得各种 SocketExceptions
。这只是将另一个 catch 处理程序附加到该 try block 上。
我承认我对这种方法感到不舒服,因为原则上捕获可能是误报,其中存在真正的“坏”对象访问。但另一方面,EndAcceptTcpClient()
调用中没有太多可能触发此异常的对象访问。我希望。
这是我的代码。这是早期/原型(prototype)的东西,请忽略控制台调用。
private void OnAccept(IAsyncResult iar)
{
TcpListener l = (TcpListener) iar.AsyncState;
TcpClient c;
try
{
c = l.EndAcceptTcpClient(iar);
// keep listening
l.BeginAcceptTcpClient(new AsyncCallback(OnAccept), l);
}
catch (SocketException ex)
{
Console.WriteLine("Error accepting TCP connection: {0}", ex.Message);
// unrecoverable
_doneEvent.Set();
return;
}
catch (ObjectDisposedException)
{
// The listener was Stop()'d, disposing the underlying socket and
// triggering the completion of the callback. We're already exiting,
// so just return.
Console.WriteLine("Listen canceled.");
return;
}
// meanwhile...
SslStream s = new SslStream(c.GetStream());
Console.WriteLine("Authenticating...");
s.BeginAuthenticateAsServer(_cert, new AsyncCallback(OnAuthenticate), s);
}
关于c# - 调用 BeginAcceptTcpClient 后停止 TcpListener,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1173774/
我有这个代码... internal static void Start() { TcpListener listenerSocket = new TcpListener(IPAddress.
我已经知道 BeginXXX(AMP) 或 XXXAsync(TAP) 在 .NetFramework 中使用 IOCP,那么现在我想在 dotnetcore 上构建 httpServer。所以我需要
我是一名优秀的程序员,十分优秀!