(显然)正常关闭UDPClient使套接字被阻止

以下代码尽管显然关闭了UDP套接字,但仍然挂起并且无法重新连接到同一地址/端口。

这些是我使用的类变量:

Thread t_listener; List XSensAvailablePorts; private volatile bool stopT_listener = false; volatile UdpClient listener; IPEndPoint groupEP; 

我用一个处理Socket连接和监听的方法创建并启动一个新线程:

 private void startSocketButton_Click(object sender, RoutedEventArgs e) { stopT_listener = false; closeSocketButton.IsEnabled = true; startSocketButton.IsEnabled = false; t_listener = new Thread(UDPListener); t_listener.Name = "UDPListenerThread"; t_listener.Start(); } 

方法如下(我在Receive上使用超时,以便在套接字上没有发送任何内容并且发出Stop不会Stop它):

  private void UDPListener() { int numberOfPorts = XSensAvailablePorts.Count(); int currAttempt = 0; int currPort = 0; bool successfullAttempt = false; while (!successfullAttempt && currAttempt < numberOfPorts) { try { currPort = Int32.Parse(XSensAvailablePorts[currAttempt]); listener = new UdpClient(currPort); successfullAttempt = true; } catch (Exception e) { currAttempt++; } } if (successfullAttempt) { //timeout = 2000 millis listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000); //Tried with and without, no change: listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Connected on port:" + currPort; }); groupEP = new IPEndPoint(IPAddress.Parse("143.225.85.130"), currPort); byte[] receive_byte_array; try { while (!stopT_listener) { try { receive_byte_array = listener.Receive(ref groupEP); if (receive_byte_array.Length == 0 || receive_byte_array == null) continue; ParseData(receive_byte_array, samplingDatagramCounter); } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.TimedOut) continue; } } } catch (Exception e) { Debug.Print(e.Message); } finally { if (listener != null) { listener.Client.Shutdown(SocketShutdown.Both); listener.Close(); } } } statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Not Connected"; }); return; } 

我命令线程/套接字停止使用此方法:

 private void closeSocketButton_Click(object sender, RoutedEventArgs e) { stopT_listener = true; closeSocketButton.IsEnabled = false; startSocketButton.IsEnabled = true; t_listener.Join(); if (listener.Client != null) { listener.Client.Shutdown(SocketShutdown.Both); listener.Close(); } if (t_listener.IsAlive) { t_listener.Abort(); statusTB.Text = "Aborted"; } else statusTB.Text = "Not Connected"; } 

尽管在调试中检查套接字是否已关闭,但如果我重试连接到同一端口,我无法这样做,因为它引发了一个SocketException说通常只允许使用一个端口/地址。

我把你提供的代码用一个简单的forms来运行它……我不能直接重现你的问题。 我没有向客户端发送任何数据,但据我所知,它不应该改变任何东西,因为它是UDP,我们正在调查(重新)打开套接字,而不是传输数据。

单击开始/停止按钮时,套接字始终正确打开和关闭,重新打开按预期工作。 对我来说,强制你提到的SocketException的唯一方法是引入一些明显的套接字逻辑误用:

  1. 运行两个应用程序实例并单击两者中的“开始”。
  2. 删除关闭和关闭的两次出现(停止不关闭套接字)。
  3. 运行应用程序,打开套接字,关闭应用程序而不关闭套接字,再次运行应用程序,尝试打开套接字。

我在代码中所做的更改只是删除ParseData(…)行并将一些端口添加到XSensAvailablePorts列表中。

你明显关闭后,能否检查一下端口是否仍然打开? 您可以使用netstat -an或一个出色的工具ProcessExplorer。 您还可以检查t_listener线程是否正确终止(标准任务管理器或ProcessExplorer可以帮助您)。

将侦听器对象设置为NULL,以便释放资源,该资源也应该释放连接。

我有同样的问题,问题出在UDPClient.Receive(),即使你调用Close / shutdown / …,她仍然保持套接字处于使用状态。

 try{ // receive loop} catch{} finally { UDP_Listner.Close(); UDP_Listner = null; } 

编辑:

 t_listener = new Thread(UDPListener);//replace by : t_listener = new Thread(new ThreadStart(UDPListener)); 

`

安全地关闭套接字和线程( http://msdn.microsoft.com/en-us/library/system.threading.threadstart(v=vs.110).aspx )

我有同样的问题,我是最安全的程序员,我总是很好地关闭一切。 但我发现.net类没有足够快地关闭套接字。 因为如果我变慢,它就不会发生,但如果我打开和关闭(完全清理)并快速打开它,我会得到同样的错误。 特别是如果用户想要再次运行相同的代码并再次打开端口。

可能是一个旧答案,但在您尝试找到可用端口但失败时,我会在下一次迭代之前处置您测试的侦听器实例。

  try { currPort = Int32.Parse(XSensAvailablePorts[currAttempt]); listener = new UdpClient(currPort); successfullAttempt = true; } catch (Exception e) { currAttempt++; if(listener != null) { listener.Close(); } } 

我认为绑定或重用可以解决这个问题(即使套接字没有关闭但它可以重用并且不会抛出任何错误)示例代码:

 udpClient = new UdpClient(); udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, p));