Poniższy kod, pomimo pozornie zamknięcia gniazda UDP, pozostawia go zawieszony i nie może ponownie połączyć się z tym samym adresem/portem.(Najwyraźniej) Wdzięcznie zamknięty UDPClient opuszcza gniazdo zablokowane
Są zmienne klasy używam:
Thread t_listener;
List<string> XSensAvailablePorts;
private volatile bool stopT_listener = false;
volatile UdpClient listener;
IPEndPoint groupEP;
tworzę i rozpoczęcie nowego wątku z metody, która będzie obsługiwać połączenia gnieździe i słuchanie:
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();
}
Metoda jest następująca (Używam timeOut na Receive, aby nie zostawiać go zablokowanego, jeśli nic nie jest wysyłane na gniazdo i nie jest wydawane 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;
}
zamówić gwintu/gniazda, aby zatrzymać przy użyciu tej metody:
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";
}
Pomimo sprawdzania w debugowania, że gniazdo zostało zamknięte, gdybym ponownie podłączyć do tego samego portu, jestem w stanie to zrobić, ponieważ to podnosi wyjątek SocketException, który mówi, że dozwolone jest tylko jedno użycie portu/adresu.
Czy to możliwe, czym jest 'listener.Client' po' null' po kliknięciu przycisku? Nie wywołasz wtedy 'listener.Close()'. – Sinatr
@Sinatr Sprawdziłem debugowanie i tak nie jest. –
. Zamknij() powinno całkowicie pozbyć się obiektu. musi to być coś innego, tak jak nie właściwie zamknięcie gniazda (prawdopodobnie z powodu jakiegoś wyjątku, który nie jest obsługiwany i po prostu pomijany). Nie wiem, ponieważ właśnie użyłem metody asynchronicznej .BeginReceive do obsługi danych. ; p – porkchop