zamknięcie vs zamknięcie gniazda?
W C, zrozumiałem, że jeśli zamkniemy Gniazdo, oznacza to, że gniazdo zostanie zniszczone i może być ponownie użyte później.
A co z wyłączeniem? Opis mówi, że zamyka połowę połączenia dupleksu z tym gniazdem. Ale czy to gniazdo zostanie zniszczone jak close
wywołanie systemowe?
8 answers
To jest wyjaśnione w przewodniku Beeja dotyczącym sieci. shutdown
jest elastycznym sposobem blokowania komunikacji w jednym lub obu kierunkach. Gdy drugim parametrem jest SHUT_RDWR
, blokuje zarówno wysyłanie, jak i odbieranie (jak close
). Jednak close
jest sposobem na zniszczenie gniazda.
Z shutdown
, nadal będziesz w stanie odbierać oczekujące dane, które już wysłał peer (dzięki Joey Adams za odnotowanie tego).
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
2018-02-01 13:06:32
Żadna z istniejących odpowiedzi nie mówi ludziom, jak shutdown
i close
działają na poziomie protokołu TCP, więc warto to dodać.
- gdy Uczestnik nie ma więcej danych do wysłania, wysyła pakiet FIN do drugiego
- druga strona zwraca ACK dla FIN.
- gdy druga strona również zakończyła transfer danych, wysyła kolejny pakiet FIN
- początkowy uczestnik zwraca ACK i finalizuje transfer.
- uczestnik wysyła pakiet RST i rezygnuje z połączenia
- druga strona otrzymuje RST, a następnie również porzuca połączenie
W moim teście z Wireshark, z domyślnymi opcjami gniazd, shutdown
wysyła pakiet FIN na drugi koniec, ale to wszystko, co robi. Dopóki druga strona nie wyśle Ci pakietu FIN, nadal możesz odbierać dane. Gdy to się stanie, twój Receive
otrzyma wynik o rozmiarze 0. Więc jeśli jesteś pierwszym, który wyłączył "wyślij", powinieneś zamknąć gniazdo po zakończeniu odbierania danych.
Z drugiej strony, Je ¶ li wywo3asz close
, gdy po3 ± czenie jest nadal aktywne (druga strona jest nadal aktywna i mo ¿esz mieæ niezbêdne dane w buforze systemowym), pakiet RST zostanie wys3any do drugiej strony. Jest to dobre dla błędów. Na przykład, jeśli uważasz, że druga strona podała błędne dane lub odmówiła podać dane (atak DOS?), można od razu zamknąć Gniazdo.
Moje zdanie na temat zasad brzmiałoby:
- rozważ
shutdown
przedclose
Kiedy to możliwe - Jeśli odebrałeś (odebrano dane o rozmiarze 0) przed podjęciem decyzji o wyłączeniu, Zamknij połączenie po zakończeniu ostatniego wysłania (jeśli w ogóle).
- Jeśli chcesz normalnie zamknąć połączenie, zamknij je (używając shut_wr, a jeśli nie zależy ci na odbieraniu danych po tym punkcie, używając SHUT_RD jako dobrze), i poczekaj, aż otrzymasz dane o rozmiarze 0, a następnie zamknij Gniazdo.
- w każdym przypadku, jeśli wystąpi jakikolwiek inny błąd (na przykład timeout), po prostu zamknij Gniazdo.
Idealne implementacje dla SHUT_RD i SHUT_WR
Poniższe nie zostały przetestowane, zaufaj na własne ryzyko. Uważam jednak, że jest to rozsądny i praktyczny sposób działania.
Jeśli stos TCP otrzyma zamknięcie tylko z SHUT_RD, oznacza to połączenie jako nie oczekuje się więcej danych. Wszystkie oczekujące i kolejne żądania read
(niezależnie od tego, w którym wątku się znajdują) zostaną zwrócone z wynikiem o rozmiarze zerowym. Jednak połączenie jest nadal aktywne i użyteczne-nadal można na przykład odbierać dane OOB. Ponadto system operacyjny upuści wszelkie dane, które otrzyma za to połączenie. Ale to wszystko, żadne paczki nie będą wysyłane na drugą stronę.
Jeśli stos TCP otrzyma zamknięcie tylko z shut_wr, oznacza to połączenie, ponieważ żadne więcej danych nie może być wysłane. Wszystkie oczekujące żądania zapisu zostaną zakończone, ale kolejne żądania zapisu nie powiodą się. Ponadto, pakiet FIN zostanie wysłany do innej strony, aby poinformować ich, że nie mamy więcej danych do wysłania.
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
2018-07-29 23:29:19
Istnieją pewne ograniczenia z close()
, których można uniknąć, jeśli zamiast tego używa się shutdown()
.
close()
zakończy oba kierunki na połączeniu TCP. Czasami chcesz powiedzieć drugiemu punktowi końcowemu, że wysyłasz dane, ale nadal chcesz je odbierać.
close()
zmniejsza liczbę odwołań deskryptorów (utrzymywaną we wpisie tabeli plików i zlicza liczbę aktualnie otwartych deskryptorów, które odnoszą się do pliku/gniazda) i nie zamyka gniazda / pliku jeśli deskryptor nie jest równy 0. Oznacza to, że jeśli rozwidlasz się, oczyszczanie następuje dopiero po spadku liczby referencji do 0. Za pomocą shutdown()
można zainicjować normalną sekwencję zamkniętą TCP ignorując liczbę referencji.
Parametry są następujące:
int shutdown(int s, int how); // s is socket descriptor
int how
może być:
SHUT_RD
lub 0
Dalsze otrzymywanie jest niedozwolone
SHUT_WR
lub 1
Dalsze wysyłanie nie jest dozwolone
SHUT_RDWR
lub 2
Dalsze wysyłanie i odbieranie są niedozwolone
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
2014-01-17 00:50:05
Może to być specyficzne dla platformy, jakoś w to wątpię, ale w każdym razie najlepsze wyjaśnienie, jakie widziałem, to tutaj na tej stronie msdn, gdzie wyjaśniają o zamykaniu, opcjach pozostawania, zamykaniu gniazd i ogólnych sekwencjach zakończenia połączenia.
Podsumowując, użyj shutdown, aby wysłać sekwencję zamykania na poziomie TCP i użyj close, aby zwolnić zasoby używane przez struktury danych gniazd w procesie. Jeśli nie wydałeś jawnej sekwencji wyłączania do czasu wywołania Zamknij wtedy jeden jest inicjowany dla Ciebie.
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-11-18 08:33:34
Odniosłem również sukces pod Linuksem używając shutdown()
z jednego pthreada, aby zmusić inny pthread aktualnie zablokowany w connect()
do wcześniejszego przerwania.
Pod innymi osami (przynajmniej OSX), stwierdziłem, że wywołanie close()
wystarczyło, aby uzyskać connect()
fail.
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-11-15 08:56:33
"shutdown () nie zamyka deskryptora pliku-po prostu zmienia jego użyteczność. Aby uwolnić deskryptor gniazda, musisz użyć metody close ()."1
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
2014-11-12 01:22:43
Zamknij
Po zakończeniu używania gniazda, możesz po prostu zamknąć jego deskryptor pliku za pomocą close; jeśli nadal istnieją dane oczekujące na przesłanie przez połączenie, normalnie close próbuje zakończyć tę transmisję. Można kontrolować to zachowanie za pomocą opcji so_linger socket, aby określić okres czasu oczekiwania; zobacz Opcje Socket.
ShutDown
Możesz również wyłączyć tylko odbiór lub transmisję na połączeniu, dzwoniąc wyłączenie.
Funkcja shutdown wyłącza połączenie gniazda. Jego argument jak określa jaką akcję wykonać: 0 Przestań odbierać dane dla tego gniazda. Jeśli pojawią się dalsze dane, odrzuć je. 1 Przestań próbować przesyłać dane z tego gniazda. Odrzuć wszystkie dane oczekujące na wysłanie. Przestań szukać potwierdzenia już wysłanych danych; nie przesyłaj ich ponownie, jeśli zostaną utracone. 2 Zatrzymać zarówno odbiór, jak i transmisję.
Wartość zwracana jest równa 0 W przypadku sukcesu i -1 W przypadku niepowodzenia.
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
2016-07-21 11:57:41
W moim teście.
close
wysyła pakiet fin i niszczy FD natychmiast, gdy gniazdo nie jest współdzielone z innymi procesami
shutdown
SHUT_RD, proces nadal może odczytywać dane z gniazda, ale recv
zwróci 0, jeśli bufor TCP jest pusty.Gdy peer wyśle więcej danych, recv
zwróci dane ponownie.
shutdown
SHUT_WR wyśle pakiet fin, aby wskazać, że dalsze wysyłanie nie jest dozwolone. peer może recv danych, ale będzie recv 0, jeśli jego bufor TCP jest empty
shutdown
shut_rdwr (równe obu SHUT_RD i SHUT_WR) wyśle pakiet rst, jeśli peer wyśle więcej danych.
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
2015-09-17 06:06:28