Jak działa funkcja socket API accept ()?


126

Interfejs API gniazd jest de facto standardem komunikacji TCP / IP i UDP / IP (czyli znanym nam kodem sieciowym). Jednak jedna z jego podstawowych funkcji accept()jest nieco magiczna.

Aby pożyczyć definicję półformalną:

accept () jest używana po stronie serwera. Akceptuje odebraną próbę utworzenia nowego połączenia TCP od klienta zdalnego i tworzy nowe gniazdo skojarzone z parą adresów gniazda tego połączenia.

Innymi słowy, acceptzwraca nowe gniazdo, przez które serwer może komunikować się z nowo podłączonym klientem. Stare gniazdo (na którym acceptzostało wywołane) pozostaje otwarte, na tym samym porcie, nasłuchując nowych połączeń.

Jak to acceptdziała? Jak to jest realizowane? W tym temacie jest wiele nieporozumień. Wiele osób twierdzi, że akceptacja otwiera nowy port i za jego pośrednictwem komunikujesz się z klientem. Ale to oczywiście nieprawda, ponieważ żaden nowy port nie jest otwierany. W rzeczywistości możesz komunikować się przez ten sam port z różnymi klientami, ale jak? Kiedy kilka wątków łączy się recvz tym samym portem, skąd dane mają wiedzieć, gdzie iść?

Wydaje mi się, że jest to coś w rodzaju adresu klienta związanego z deskryptorem gniazda, a ilekroć dane przechodzą recv, są kierowane do właściwego gniazda, ale nie jestem pewien.

Byłoby wspaniale uzyskać dokładne wyjaśnienie wewnętrznego działania tego mechanizmu.


2
tak więc na każde żądanie klienta otwierane jest zupełnie NOWE połączenie przez gniazdo na końcu serwera. Serwer musi być zawsze otwarty na 80, aby nasłuchiwać połączeń przychodzących. Jeśli odbierze połączenie, natychmiast tworzy nowe gniazdo z czterema krotkami, jak wspomniano poniżej, które utworzą połączenie TCP między klientem a serwerem. Czy moje rozumienie jest prawidłowe?
burza mózgów

1
Jest to bardzo podstawowe pytanie, a ja niedawno został przetestowany na ten temat w wywiadzie: stackoverflow.com/questions/24871827/... Jeśli masz jakieś uwagi na ten temat, proszę pisać
burzę mózgów

@brainstorm Tylko jeśli całkowicie zignorujesz istnienie podtrzymania aktywności HTTP.
Markiz Lorne

Odpowiedzi:


140

Twoje zamieszanie polega na myśleniu, że gniazdo jest identyfikowane przez adres IP serwera: port serwera. W rzeczywistości gniazda są jednoznacznie identyfikowane przez kwartet informacji:

Client IP : Client Port i Server IP : Server Port

Tak więc podczas gdy adres IP serwera i port serwera są stałe we wszystkich akceptowanych połączeniach, informacje po stronie klienta pozwalają mu śledzić, dokąd wszystko zmierza.

Przykład wyjaśnienia rzeczy:

Powiedzmy, że mamy serwer pod adresem 192.168.1.1:80i dwóch klientów 10.0.0.1i 10.0.0.2.

10.0.0.1otwiera połączenie na porcie lokalnym 1234i łączy się z serwerem. Teraz serwer ma jedno gniazdo zidentyfikowane w następujący sposób:

10.0.0.1:1234 - 192.168.1.1:80  

Teraz 10.0.0.2otwiera połączenie na porcie lokalnym 5678i łączy się z serwerem. Teraz serwer ma dwa gniazda zidentyfikowane w następujący sposób:

10.0.0.1:1234 - 192.168.1.1:80  
10.0.0.2:5678 - 192.168.1.1:80

3
Nie znam szczegółów implementacji (które prawdopodobnie różnią się w zależności od platformy), po prostu wiem, że koncepcyjnie gniazda są identyfikowane przez kwartet informacji, które opisałem.
17 z 26

3
Czy masz jakieś informacje na ten temat?
qeek

3
Losowe pytanie: Co się stanie, jeśli używany jest NAT, a dwóch klientów w tej samej sieci próbuje używać tego samego portu lokalnego podczas łączenia się z serwerem? Na przykład, jeśli 10.0.0.1 i 10.0.0.2 są połączone z routerem z zewnętrznym adresem IP 192.168.0.1, więc serwer pod adresem 192.168.1.1 widzi dwa połączenia z adresu 192.168.0.1. Co się stanie w takim przypadku, jeśli jakiś przypadek generatora liczb losowych zarówno 10.0.0.1, jak i 10.0.0.2 wybierze ten sam port lokalny?
aroth

4
Obsługa NAT w routerze zajmuje się tam szczegółami. Ruch sieciowy przechodzi w rzeczywistości przez dwa połączenia - klient do routera i router do serwera. Router wykonuje połączenia wychodzące na dwóch różnych portach 192.168.0.1:1234 i 192.168.0.1:5678. Ruch przychodzący jest następnie przekierowywany przez router do właściwego klienta.
17 z 26

3
Jeśli gniazdo jest identyfikowane przez kwartet, jakie są informacje kwartetu dotyczące gniazda nasłuchującego?
Eric Zheng

74

Wystarczy dodać do odpowiedzi udzielonej przez użytkownika „17 z 26”

Gniazdo w rzeczywistości składa się z 5 krotek - (źródłowy adres IP, źródłowy port, docelowy adres IP, docelowy port, protokół). Tutaj protokół może TCP lub UDP lub dowolny protokół warstwy transportowej. Ten protokół jest identyfikowany w pakiecie w polu „protokół” w datagramie IP.

W ten sposób możliwe jest, aby różne aplikacje na serwerze komunikowały się z tym samym klientem na dokładnie tych samych 4-krotkach, ale różniących się w polu protokołu. Na przykład

Apache po stronie serwera rozmawia przez (server1.com:880-client1:1234 na TCP) i World of Warcraft rozmawia przez (server1.com:880-client1:1234 na UDP)

Zarówno klient, jak i serwer będą obsługiwać to, ponieważ pole protokołu w pakiecie IP w obu przypadkach jest różne, nawet jeśli wszystkie pozostałe 4 pola są takie same.


13

To, co mnie zdezorientowało, kiedy się tego uczyłem, to fakt, że terminy socketi portsugerują, że są czymś fizycznym, podczas gdy w rzeczywistości są to tylko struktury danych, których jądro używa do abstrakcji szczegółów sieci.

W związku z tym struktury danych są zaimplementowane w celu oddzielenia połączeń od różnych klientów. Jeśli chodzi o sposób ich implementacji, odpowiedź brzmi: a.) Nie ma znaczenia, celem API gniazd jest właśnie to, że implementacja nie powinna mieć znaczenia lub b.) Po prostu spójrz. Oprócz wysoce polecanych książek Stevensa zawierających szczegółowy opis jednej implementacji, sprawdź źródła w Linuksie lub Solarisie lub jednym z BSD.


Tak, większość terminologii sieciowej polega po prostu na przypisywaniu nazw pewnym zbiorom bitów i decyzjom podejmowanym na podstawie ich wartości („identyfikator protokołu”, „routing”, „wiązanie”, „gniazdo” itp.). Wszystkie karty sieciowej za sprzętowy przeznaczony jest do odbioru jest strumień bitów. O tym, co się z nimi stanie w odniesieniu do programów na Twoim komputerze, decyduje sterownik i system operacyjny. Moglibyśmy się jutro pozbyć całej tej terminologii, gdybyśmy chcieli, ale zasada dostarczania strumienia bitów wydaje się fundamentalna ...
masterxilo

-1

Jak powiedział drugi facet, gniazdo jest jednoznacznie identyfikowane przez 4 krotki (IP klienta, port klienta, adres IP serwera, port serwera).

Proces serwera działający na serwerze IP utrzymuje bazę danych (co oznacza, że ​​nie obchodzi mnie, jakiego rodzaju tabeli / listy / drzewa / tablicy / magicznej struktury danych używa) aktywnych gniazd i nasłuchuje na porcie serwera. Kiedy otrzyma wiadomość (za pośrednictwem stosu TCP / IP serwera), sprawdza IP klienta i port w bazie danych. Jeśli adres IP klienta i port klienta zostaną znalezione we wpisie bazy danych, wiadomość jest przekazywana do istniejącej procedury obsługi, w przeciwnym razie zostanie utworzony nowy wpis bazy danych i zostanie utworzony nowy program obsługi do obsługi tego gniazda.

We wczesnych dniach ARPAnet, niektóre protokoły (jeden z nich to FTP) nasłuchiwały na określonym porcie żądań połączenia i odpowiadały portem przekazywania. Dalsza komunikacja dla tego połączenia przebiegałaby przez port przekazywania. Zrobiono to w celu poprawy wydajności na pakiet: w tamtych czasach komputery były o kilka rzędów wielkości wolniejsze.


czy możesz rozwinąć część dotyczącą „portu przekazania”?
Eli Bendersky

1
To jest opis jakiegoś protokołu sprzed TCP lub zbytnio uproszczony. Klient próbujący połączyć się z gniazdem nasłuchującym wysyła specjalny pakiet w celu ustanowienia połączenia (ustawiony bit SYN). Istnieje wyraźna różnica między pakietem tworzącym nowe gniazdo a pakietem wykorzystującym istniejące gniazdo.
John M

... wysyła specjalny pakiet do ustanowienia połączenia (ustawiony bit SYN). Co (jak rozumiem) powoduje, że stos protokołów przekazuje go `` słuchaczowi '' (jeśli istnieje), dlatego może istnieć tylko jeden port nasłuchiwania na kombinację adresu / portu / protokołu. Nie jestem jednak pewien, czy jest to w specyfikacji, czy tylko w konwencji implementacji.
Peter wygrał

1
Drugi akapit nie opisuje poprawnie tego, co dzieje się w warstwie TCP lub w procesie serwera. Procesy serwera nie muszą utrzymywać żadnych struktur danych gniazd ani sprawdzać przychodzących par IP: port z czymkolwiek. Do tego służą gniazda. FTP używa oddzielnego portu do przesyłania danych, a nie do całej „dalszej komunikacji”, i nakrycia głowy mają na celu uproszczenie protokołu, a nie wydajność. Korzystanie z nowego portu nie poprawia w żaden sposób wydajności.
Markiz Lorne

"utrzymuje bazę danych (co oznacza, że ​​nie obchodzi mnie jakiego rodzaju tabeli / listy / drzewa / tablicy / magicznej struktury danych używa)" :) Zwykle nazywam to "tabelą" (a może "wykresem" lub "drzewem decyzyjnym") ). „Baza danych” sugeruje mi jakąś implementację.
masterxilo
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.