Ant*_*y D 20 c# sockets tcpclient
我有这个代码......
internal static void Start()
{
TcpListener listenerSocket = new TcpListener(IPAddress.Any, 32599);
listenerSocket.Start();
listenerSocket.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), null);
}
Run Code Online (Sandbox Code Playgroud)
然后我的回调函数看起来像这样......
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);
}
Run Code Online (Sandbox Code Playgroud)
现在,我调用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();
}
Run Code Online (Sandbox Code Playgroud)
更新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);
}
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*ope 17
我自己也遇到了这个问题,我相信你当前的解决方案是不完整/不正确的.检查IsBound和后续调用之间无法保证原子性EndAcceptTcpClient().如果侦听器Stop()位于这两个语句之间,您仍然可以获得异常.你没有说你得到了什么异常,但我认为它与我得到的相同,ObjectDisposedException(抱怨底层套接字已被处理掉).
您应该能够通过模拟线程调度来检查:
IsBound检查回调后在行上设置断点TcpListener.Stop()EndAcceptTcpClient()电话.你应该看到了ObjectDisposedException.IMO理想的解决方案是让微软EndAcceptTcpClient在这种情况下抛出一个不同的例外,例如ListenCanceledException或类似的东西.
事实上,我们必须推断出发生了什么ObjectDisposedException.只是捕获异常并相应地表现.在我的代码中,我默默地吃异常,因为我在其他地方有代码执行真正的关闭工作(即TcpListener.Stop()首先调用的代码).无论如何,您应该已经在该区域进行了异常处理,因为您可以获得各种异常处理SocketExceptions.这只是在该try块上添加另一个catch处理程序.
我承认我对这种方法感到不舒服,因为原则上捕获可能是误报,在那里有真正的"坏"对象访问.但另一方面,EndAcceptTcpClient()调用中没有太多的对象访问,否则会触发此异常.我希望.
这是我的代码.这是早期/原型的东西,忽略Console调用.
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);
}
Run Code Online (Sandbox Code Playgroud)
不,你没有遗漏任何东西.您可以检查Socket对象的IsBound属性.至少对于TCP连接,当套接字正在侦听时,它将被设置为true,并且在您调用close之后,它的值将为false.但是,您自己的实现也可以正常工作.
| 归档时间: |
|
| 查看次数: |
25917 次 |
| 最近记录: |