Jak mogę sprawdzić, czy gniazdo (TCP) jest (dis) podłączone w C#?

Jak sprawdzić Gniazdo (TCP), aby sprawdzić, czy jest podłączone?

Czytałem o właściwości Socket.Connectedw MSDN , ale mówi, że pokazuje tylko stan według ostatniego wejścia/wyjścia.nie jest to dla mnie przydatne, ponieważ chcę to zrobić przed próbując odczytać z gniazda. Sekcja uwagi zwraca również uwagę, że:

Jeśli chcesz określić aktualny stan połączenia, wykonaj niezablokowane, zero-bajtowe połączenie. Jeśli wezwanie powraca pomyślnie lub rzuca kod błędu WAEWOULDBLOCK (10035), wówczas gniazdo jest nadal podłączony; w przeciwnym razie gniazdo nie dłuższe połączenie.

Przykład na tej samej stronie pokazuje, jak to zrobić.(1) ale post Ian Griffiths mówi, że powinienem czytać z gniazda, a nie wysyłać przez niego.

Another post by Pete Duniho says:

... po wywołaniu Shutdown(), call Receive() until it returns 0 (zakładając, że zdalny punkt końcowy nie jest właściwie to wyślę ci cokolwiek., stanie się tak, jak tylko zdalny punkt końcowy otrzymał wszystkie danych). Jeśli tego nie zrobisz, masz brak pewności, że zdalny punkt końcowy rzeczywiście otrzymał wszystkie dane wysłałeś, nawet korzystając z trwającego Gniazdo.

Nie bardzo rozumiem jego oświadczenie o wywołaniu Receive(), aby upewnić się, że zdalny punkt końcowy rzeczywiście otrzymał wszystkie dane, które wysłałem . (Do gniazda blokują odbieranie, dopóki bufor wysyłający nie będzie pusty?)

Jestem zdezorientowany różnymi zaproponowanymi metodami. Możesz je wyjaśnić?


(1) zastanawiam się dlaczego przykład dla właściwości Socket.Connected przydziela 1-bajtową tablicę, mimo że wywołuje Send o długości 0?

Author: Hosam Aly, 2009-02-05

4 answers

Śmierć gniazda zmienia jego zachowanie na kilka sposobów, więc te metody są ważne:)

Obie metody sprawdzają te części zachowania gniazda, które zmieniają się po rozłączeniu.

Naprawdę nie rozumiem jego oświadczenia o wywołaniu Receive (), aby upewnić się, że zdalny punkt końcowy rzeczywiście otrzymał wszystkie dane, które wysłałem. (Czy gniazda blokują odbiór do momentu opróżnienia bufora wysyłającego?)

TCP jest niezawodnym protokołem, oznacza to, że każda przesyłana paczka musi zostać potwierdzona. Potwierdzenie oznacza wysłanie pakietów z ustawionym bitem ACK. Pakiety te mogą lub nie mogą zawierać dodatkowych danych (ładunku).

Gdy gniazdo jest podłączone, Receive() zablokuje się, dopóki gniazdo nie otrzyma pakietu z niepustym ładunkiem. Ale gdy gniazdo jest odłączone, Receive() powróci, gdy tylko dotrze ostatni ACK pakiet.

Wywołanie Receive() zapewnia, że albo otrzymasz ten ostatni ACK pakiet ze zdalnego punktu końcowego lub limitu czasu rozłączenia nastąpi i będziesz mógł odbierać nic więcej na tym gnieździe.

Przykład na tej samej stronie pokazuje, jak to zrobić. (Zastanawiam się, dlaczego przydziela 1-bajtową tablicę, mimo że wywołuje Send o długości 0?) Ale post Ian Griffiths mówi, że Powinienem czytać z gniazdka, a nie wysyłać przez niego.

Kiedy send()ing do gniazda, w rzeczywistości próbujesz dołączyć niektóre dane do końca kolejki gniazd. Na w buforze zostało jakieś miejsce, wtedy Send() natychmiast powraca, jeśli nie, Send() blokuje, dopóki nie znajdzie się jakieś miejsce.

Gdy gniazdo jest w stanie rozłączonym, TCP/IP stos uniemożliwia wszystkie dalsze operacje z buforem, dlatego Send() zwraca błąd.

Send() implementuje podstawowe sprawdzanie wskaźnika, oznacza to, że nie powiedzie się, gdy wskaźnik NULL zostanie do niego przekazany. Prawdopodobnie możesz przekazać jako wskaźnik dowolną stałą non-null, ale lepiej przydziel 1 bajt zamiast tworzyć stały up-na wszelki wypadek.


Możesz używać dowolnej metody, ponieważ żadna z nich nie zużywa zasobów. Tak długo, jak są one używane do sprawdzania połączenia z gniazdem, są identyczne.

Jeśli chodzi o mnie, wolałbym Receive(), ponieważ to jest to, co normalnie biegasz w cyklu i czekasz. Otrzymujesz niezerową wartość z Receive(), przetwarzasz dane; otrzymujesz zero, przetwarzasz rozłączenie.

 21
Author: Quassnoi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-05 14:49:02

" jeśli chcesz określić aktualny stan połączenia, wykonaj niezablokowane, 0-bajtowe połączenie Send. Jeśli wywołanie zakończy się pomyślnie lub wyświetli kod błędu WAEWOULDBLOCK (10035), wtedy gniazdo jest nadal podłączone; w przeciwnym razie gniazdo nie jest już podłączone."- niestety, to nawet nie działa!

mySocket.Blocking = false;
byte[] buffer = new byte[1];
int iSent = mySocket.Send(buffer, 0, SocketFlags.None);
bConnected = mySocket.Connected;

BConnected zawsze kończy się jako true, a wywołanie zawsze powraca pomyślnie, nawet jeśli kabel Ethernet został odłączony.

Ponadto, i niestety = = wysyłanie jakichkolwiek rzeczywistych danych również nie wykrywa przerwanego połączenia.

buffer[0] = 0xff ;
int iSent = mySocket.Send(buffer, 1, SocketFlags.None);

Wielokrotnie zwraca 1, tak jakby rzeczywiście coś wysłał. Podczas gdy dane urządzenie nie jest już nawet podłączone.

 4
Author: loaf of bread,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-31 20:42:19

Zazwyczaj używa się gniazda.Wybierz metodę, aby określić stan zestawu gniazd (Socket.Ankieta dla pojedynczego gniazda).

Obie te metody pozwalają na odpytywanie stanu gniazda. Teraz, zakładając, że wyśledziłeś, że gniazdo jest podłączone, zazwyczaj wywołasz Select / Poll na gnieździe przed próbą odczytu. Jeśli Select / Poll wskaże, że gniazdo jest czytelne, oznacza to, że:

  • albo gniazdo ma dane dostępne top read w takim przypadku Receive zwróci dane dostępne do odczytu.
  • gniazdo gniazdo zostało zamknięte, w którym to przypadku, gdy wywołasz Receive 0 bajtów zostanie zwrócone natychmiast (tzn. jeśli Select / Poll wskaże, że gniazdo jest czytelne i wywołasz Receive, ale wróci natychmiast z 0 bajtami, to wiesz, że połączenie zostało zamknięte, zresetowane lub Zakończone.

Osobiście nigdy nie korzystałem z ankiety - zawsze korzystałem z Select, ale MSDN wydaje się sugerować, że ankieta jest prawie taki sam jak Select, ale dla pojedynczych gniazd.

Dodam również, że w większości przypadków użycie Select jest najbardziej efektywnym i najlepszym sposobem obsługi połączeń z gniazdami.

 1
Author: ng5000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-05 11:45:55

Naprawdę nie rozumiem jego oświadczenia o wywołaniu Receive (), aby upewnić się, że zdalny punkt końcowy rzeczywiście otrzymał wszystkie dane, które wysłałem.

Post by @ PeteDuniho nie chodzi o ustalenie stanu połączenia, chodzi o zakończenie połączenia w taki sposób, że wiesz, kiedy peer otrzymał wszystkie Twoje dane.

(czy gniazda blokują odbiór do momentu opróżnienia bufora wysyłającego?)

Nie, ale jeśli wyłączysz Gniazdo a potem czytaj do EOS, czekasz, aż peer odczyta wszystkie dane, dopóki on dostanie EOS, a następnie zamknie Gniazdo. Masz więc gwarancję, że wszystkie dane dostały się do aplikacji peer.
 1
Author: user207421,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-04 00:08:30