(Apparently) Gracefully closed UDPClient leaves socket blocked

The following code, although it obviously closes the UDP socket, leaves it hanging and cannot reconnect to the same address / port.

These are the class variables that I use:

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

I create and start a new thread using a method that will handle the Socket connection and listening:

 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(); } 

The method is as follows (I use timeOut in Receive so as not to leave it blocked if nothing is sent on the socket and Stop is issued):

  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; } 

I command to stop the stream / socket with this method:

 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"; } 

Although the debugging check that the socket was closed if I try to connect to the same port, I cannot do this because it raises a SocketException, which usually only allows one port / address use.

+6
source share
5 answers

I put the code you provided in a simple form to run it and ... I cannot directly reproduce your problem. However, I did not send any data to the client, but, as I understand it, it should not change anything like UDP, and we are investigating (re) opening the socket, not transmitting the data.

When you press the "Start / Stop" buttons, the slot always opens and closes correctly, reopening works as intended. For me, the only way to force the SocketException that you mentioned is to introduce some explicit abuse of the socket logic:

  • Launch two instances of the application and click "Start" in both.
  • Remove the BOTH occurrences of Shutdown and Close (Stop does not close the socket).
  • Launching the application, opening the socket, closing the application without closing the socket, starting the application again, trying to open the socket.

Only the changes I made to the code were removing the ParseData (...) line and adding some ports to the XSensAvailablePorts list.

Can you check if the port is open after you close it? You can use netstat -an or the excellent ProcessExplorer tool. You can also check the correct completion of the t_listener stream (the standard task manager or ProcessExplorer can help you).

0
source

Set the listener object to NULL to free the resource, which should also free the connection.

0
source

I have the same problem and the problem is in UDPClient.Receive (), it keeps the socket in use state even you call Close / shutdown / ... `

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

EDIT:

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

`

it is safe to close the socket and thread ( http://msdn.microsoft.com/en-us/library/system.threading.threadstart(v=vs.110).aspx )

0
source

I have the same problem, I am the safest programmer, I always close everything perfectly. but I found that the .net class does not close the socket fast enough. because if I go slowly, this will not happen, but if I open and close (completely clear) and quickly open it, I get the same error. especially if the user wants to run the same code again and open the port again.

0
source

Perhaps this is an old answer, but when I try to find a useful port, but which failed, I would select the listener instance that you tested before the next iteration.

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

All Articles