To może być bardzo podstawowe pytanie, ale wprawia mnie w zakłopotanie.
Czy dwa różne połączone gniazda mogą współużytkować port? Piszę serwer aplikacji, który powinien obsłużyć ponad 100 tys. Jednoczesnych połączeń i wiemy, że liczba portów dostępnych w systemie wynosi około 60 tys. (16 bitów). Połączone gniazdo jest przypisane do nowego (dedykowanego) portu, co oznacza, że liczba jednoczesnych połączeń jest ograniczona liczbą portów, chyba że wiele gniazd może współużytkować ten sam port. Więc pytanie.
Z góry dziękuję za pomoc!
Nasłuchiwanie TCP / HTTP na portach: jak wielu użytkowników może współużytkować ten sam port
Więc co się dzieje, gdy serwer nasłuchuje połączeń przychodzących na porcie TCP? Na przykład, powiedzmy, że masz serwer WWW na porcie 80. Załóżmy, że Twój komputer ma publiczny adres IP 24.14.181.229, a osoba, która próbuje się z tobą połączyć, ma adres IP 10.1.2.3. Ta osoba może się z Tobą połączyć, otwierając gniazdo TCP pod numer 24.14.181.229:80. Wystarczająco proste.
Intuicyjnie (i niesłusznie) większość ludzi zakłada, że wygląda to mniej więcej tak:
Jest to intuicyjne, ponieważ z punktu widzenia klienta ma on adres IP i łączy się z serwerem pod adresem IP: PORT. Skoro klient łączy się z portem 80, to jego port też musi mieć 80? To rozsądna rzecz, aby pomyśleć, ale tak naprawdę nie to, co się dzieje. Gdyby to było poprawne, moglibyśmy obsługiwać tylko jednego użytkownika na obcy adres IP. Gdy komputer zdalny się połączy, wtedy połączy port 80 z portem 80 i nikt inny nie będzie mógł się połączyć.
Należy zrozumieć trzy rzeczy:
1.) Na serwerze proces nasłuchuje na porcie. Gdy uzyska połączenie, przekazuje je innemu wątkowi. Komunikacja nigdy nie blokuje portu nasłuchującego.
2.) Połączenia są jednoznacznie identyfikowane przez system operacyjny za pomocą następujących 5 krotek: (lokalny-IP, lokalny-port, zdalny-IP, zdalny-port, protokół). Jeśli jakikolwiek element w krotce jest inny, jest to całkowicie niezależne połączenie.
3.) Kiedy klient łączy się z serwerem, wybiera losowy, nieużywany port źródłowy wysokiego rzędu . W ten sposób pojedynczy klient może mieć do ~ 64 tys. Połączeń z serwerem dla tego samego portu docelowego.
Tak więc tak naprawdę powstaje, gdy klient łączy się z serwerem:
Patrząc na to, co się właściwie dzieje
Najpierw użyjmy netstat, aby zobaczyć, co się dzieje na tym komputerze. Będziemy używać portu 500 zamiast 80 (ponieważ na porcie 80 dzieje się cała masa rzeczy, ponieważ jest to port wspólny, ale funkcjonalnie nie robi to różnicy).
Zgodnie z oczekiwaniami dane wyjściowe są puste. Teraz uruchommy serwer WWW:
Oto wynik ponownego uruchomienia netstata:
Więc teraz istnieje jeden proces, który aktywnie nasłuchuje (stan: LISTEN) na porcie 500. Lokalny adres to 0.0.0.0, co oznacza kod „nasłuchiwania wszystkich adresów IP”. Łatwym błędem jest nasłuchiwanie tylko na porcie 127.0.0.1, który akceptuje tylko połączenia z bieżącego komputera. Więc to nie jest połączenie, to po prostu oznacza, że proces zażądał powiązania () z adresem IP portu, a ten proces jest odpowiedzialny za obsługę wszystkich połączeń do tego portu. Wskazuje to na ograniczenie polegające na tym, że na jeden komputer może nasłuchiwać tylko jeden proces na porcie (istnieją sposoby obejścia tego problemu za pomocą multipleksowania, ale jest to znacznie bardziej skomplikowany temat). Jeśli serwer WWW nasłuchuje na porcie 80, nie może współdzielić tego portu z innymi serwerami WWW.
Więc teraz połączmy użytkownika z naszą maszyną:
Jest to prosty skrypt ( https://github.com/grokit/quickweb ), który otwiera gniazdo TCP, wysyła ładunek (w tym przypadku „Ładunek testowy”), czeka kilka sekund i rozłącza się. Ponowne wykonanie netstat w tym czasie powoduje wyświetlenie następujących informacji:
Jeśli połączysz się z innym klientem i ponownie wykonasz netstat, zobaczysz następujące informacje:
... to znaczy klient użył innego losowego portu do połączenia. Dlatego nigdy nie ma pomyłki między adresami IP.
źródło
To powszechna intuicja, ale jest niepoprawna. Podłączone gniazdo nie jest przypisane do nowego / dedykowanego portu. Jedynym rzeczywistym ograniczeniem, które musi spełniać stos TCP, jest to, że krotka (adres_lokalny, port_lokalny, adres_zdalny, port_zdalny) musi być unikalna dla każdego połączenia przez gniazdo. W ten sposób serwer może mieć wiele gniazd TCP korzystających z tego samego portu lokalnego, o ile każde z gniazd na tym porcie jest podłączone do innej zdalnej lokalizacji.
Zobacz akapit „Socket Pair” pod adresem : http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA52&dq=socket%20pair%20tuple&pg=PA52#v=onepage&q=socket%20pair%20tuple&f=false
źródło
bind()
operacja poprzedzaconnect()
operację, nawet niejawnie.bind()
był używany tylko po stronie serwera.accept()?
Więc strona klienta będzie również wiązać określony port?bind()
można go było używać po stronie klientaconnect()
.Teoretycznie tak. Nie ćwicz. Większość jąder (łącznie z linuxem) nie pozwala ci ani sekundy
bind()
na już przydzielony port. To nie była naprawdę duża łatka, aby było to dozwolone.Koncepcyjnie powinniśmy rozróżnić gniazdo i port . Gniazda to dwukierunkowe punkty końcowe komunikacji, czyli „rzeczy”, do których możemy wysyłać i odbierać bajty. To kwestia koncepcji, w nagłówku pakietu o nazwie „gniazdo” nie ma takiego pola.
Port to identyfikator umożliwiający identyfikację gniazda. W przypadku TCP, port jest 16-bitową liczbą całkowitą, ale istnieją również inne protokoły (na przykład w gniazdach unix, „port” to zasadniczo ciąg znaków).
Główny problem jest następujący: jeśli przychodzi pakiet, jądro może zidentyfikować swoje gniazdo na podstawie numeru portu docelowego. Jest to najbardziej powszechny sposób, ale nie jedyna możliwość:
Ponieważ pracujesz na serwerze aplikacji, będzie w stanie to zrobić.
źródło
bind()
.bind()
? Mogę to sobie wyobrazić, tak, jest to całkiem możliwe, ale faktem jest, że zarówno WinSock, jak i Posix API używają do tegobind()
wywołania, nawet ich parametryzacja jest praktycznie taka sama. Nawet jeśli API nie ma tego wywołania, jakoś musisz to powiedzieć, skąd chcesz czytać przychodzące bajty .listen()
/accept()
API mogą tworzyć gniazda w taki sposób, że jądro będzie je rozróżniać na podstawie portów przychodzących. Kwestię PO można zinterpretować w sposób, w jaki zasadniczo o to prosi. Myślę, że jest to całkiem realistyczne, ale nie to dosłownie oznacza jego pytanie.Nie. Nie jest możliwe współdzielenie tego samego portu w określonej chwili. Możesz jednak tak skonfigurować swoją aplikację, aby uzyskać dostęp do portu w innym momencie.
źródło