Czy TCP otwiera nowe połączenie dla każdego wysyłanego pakietu?

15

To może być głupie pytanie, ale ja i kilku znajomych dyskutowaliśmy o potencjalnych ograniczeniach TCP. Mamy aplikację, która będzie nasłuchiwała klientów (pomyśl o bramie) i kierowała dane wszystkich połączonych klientów przez jednego podłączonego wydawcę kafka do jednego tematu.

Jeden z moich znajomych mówi, że TCP będzie problemem dla tej bramy, ponieważ będzie ustanawiać nowe połączenie dla każdej wysyłanej wiadomości (nie kafka, ale sam protokół transportowy stanowi problem), wymagając za każdym razem nowego portu. W tempie, w jakim będziemy wysyłać te wiadomości klientów (gigabajty), kafce zabraknie portów do odczytu?

Robiłem prace rozwojowe od kilku lat i nigdy wcześniej o tym nie słyszałem i chciałbym uzyskać niższy poziom zrozumienia (jak mi się zdawało), jak działa TCP. Rozumiem, że po ustanowieniu połączenia TCP połączenie to pozostaje otwarte, dopóki nie zostanie przekroczone przez aplikację lub nie zostanie przymusowo zamknięte przez serwer lub klienta. Dane przesyłane przez to połączenie są strumieniem i nie otwierają / zamykają nowych połączeń niezależnie od 3 V (objętość, prędkość, różnorodność).

Jeśli chodzi o porty, jeden port służy do rozgłaszania, a wewnętrzny port deskryptora pliku to aplikacja zarządzana przez program do odczytu / zapisu poszczególnych klientów. Nigdy nie rozumiałem, jak TCP ustanawia nowe połączenia dla każdego zapisywanego pakietu.

Z góry przepraszam, jeśli to pytanie nie jest bezpośrednie i zbyt niejasne. Naprawdę jestem zaskoczony i mam nadzieję, że ktoś może zapewnić więcej kontekstu do tego, co mówią moi koledzy?

użytkownik0000001
źródło
13
Myślę, że źle zrozumiałeś, co mówił twój przyjaciel. TCP nic takiego nie robi, ale możliwe jest, że określony klient nawiąże nowe połączenie TCP dla każdej wiadomości, którą chce przekazać.
hobbs
13
TCP nie może otworzyć nowego połączenia dla każdego pakietu, ponieważ potrzebuje kilku pakietów, aby otworzyć nowe połączenie. I nie mógł otworzyć nowego połączenia dla każdej wiadomości, ponieważ TCP nie ma pojęcia wiadomości. Twój kumpel jest bardzo zdezorientowany. Najważniejszą rzeczą, którą należy zrozumieć o TCP, najbardziej fundamentalnej koncepcji, jest to, że TCP jest protokołem strumienia bajtów.
David Schwartz
1
Argument kumpla niekoniecznie jest zły - jeśli nie użyjesz portów ponownie przez utrzymanie aplikacji na poziomie aplikacji lub jest po prostu zbyt wielu klientów, w twoim systemie mogą zabraknąć efemerycznych portów. Istnieją sposoby obejścia tego problemu: SO_REUSEADDRszybsze zamykanie gniazd, zwiększanie zasięgu portów efemerycznych itp. Ponadto TCP_FASTOPENmożna użyć kilku przełączników na poziomie systemu operacyjnego, aby obejść inne dobrze znane ograniczenia TCP. Tak czy inaczej, nie ma sensu dyskutować o ograniczeniach TCP, gdy nie masz nawet obciążenia do przetestowania.
user1643723

Odpowiedzi:

22

Jeden z moich znajomych mówi, że TCP będzie problemem dla tej bramy, ponieważ będzie ustanawiać nowe połączenie dla każdej wysyłanej wiadomości (nie kafka, ale sam protokół transportowy stanowi problem), wymagając za każdym razem nowego portu. W tempie, w jakim będziemy wysyłać te wiadomości klientów (gigabajty), kafce zabraknie portów do odczytu?

Twój przyjaciel jest bardzo zdezorientowany. TCP to protokół zorientowany na strumień. Nie ma pojęcia wiadomości. Oczywiście wykorzystuje pakiety w warstwie IP, ale dla aplikacji jest to szczegół implementacji. TCP wstawia granice pakietów tam, gdzie ma to sens, i niekoniecznie raz na write()lubsend() . Podobnie, łączy kolejne pakiety razem, jeśli odbierasz więcej niż jeden między połączeniami do read()lub recv().

Nie trzeba dodawać, że ten zorientowany na strumień projekt byłby całkowicie niewykonalny, gdyby każde wysyłanie ustanawiało nowe połączenie. Zatem jedynym sposobem na ustanowienie nowego połączenia jest ręczne zamknięcie i ponowne otwarcie połączenia.

(W praktyce większość protokołów zbudowanych na TCP ma coś, co przypomina wiadomości, takie jak żądania HTTP i odpowiedzi. Ale TCP nie zna ani nie dba o struktury takich rzeczy.)

Możliwe, że twój przyjaciel myślał o UDP, który ma wiadomości, ale jest również bezpołączeniowy. Większość implementacji gniazd pozwala „połączyć” gniazdo UDP ze zdalnym hostem, ale jest to tylko wygodny sposób na uniknięcie konieczności wielokrotnego określania adresu IP i portu. W rzeczywistości nic nie robi na poziomie sieci. Niemniej jednak możesz ręcznie śledzić, z którymi użytkownikami rozmawiasz w ramach UDP. Ale jeśli to zrobisz, to decydowanie o tym, co liczy się jako „połączenie”, jest twoim problemem, a nie systemem operacyjnym. Jeśli chcesz ponownie ustanowić „połączenie” dla każdej wiadomości, możesz to zrobić. Prawdopodobnie nie jest to jednak zbyt dobry pomysł.

Kevin
źródło
9

Rozumiem, że po ustanowieniu połączenia TCP połączenie to pozostaje otwarte, dopóki nie zostanie przekroczone przez aplikację lub nie zostanie przymusowo zamknięte przez serwer lub klienta.

Z punktu widzenia TCP nie ma klienta ani serwera (klient / serwer to koncepcja aplikacji, która jest tutaj nie na temat). TCP ustanawia połączenie między peerami, a oba peer mogą wysyłać i odbierać połączenia, dopóki peer go nie zamknie lub upłynie limit czasu braku aktywności.

Dane przesyłane przez to połączenie są strumieniem i nie otwierają / zamykają nowych połączeń niezależnie od 3 V (objętość, prędkość, różnorodność).

Problemem może być to, że niektóre aplikacje, np. Przeglądarki, otwierają wiele połączeń, aby jednocześnie ładować takie rzeczy, jak elementy strony internetowej.

TCP nie otwiera nowego połączenia dla każdego wysyłanego segmentu, ale aplikacja może otwierać wiele połączeń TCP. Ponadto po zamknięciu połączenia TCP port TCP używany w połączeniu jest zwalniany i można go ponownie użyć. Ta odpowiedź zawiera pewne informacje i wskazuje na RFC dla TCP.

Ron Maupin
źródło
2
Chociaż w TCP jest jeden partner, który zainicjował połączenie (często nazywany „klientem”), a drugi (często nazywany „serwerem”). Oczywiście po ustanowieniu połączenia ta różnica nie ma już znaczenia.
Paŭlo Ebermann
2
@ PaŭloEbermann, w RFC TCP nie ma nic o klientach lub serwerach. Koncepcja klient / serwer to koncepcja aplikacji. Omówiono tu protokoły w warstwie 4 lub poniżej OSI, i nie ma w nich żadnych klientów ani serwerów. W rzeczywistości to, co możesz założyć jako klient (ten, który otwiera połączenie TCP) może w rzeczywistości być serwerem aplikacji. Mamy serwery, które inicjują połączenia TCP z klientami w celu wykonywania takich czynności, jak kontrole bezpieczeństwa i aktualizacje.
Ron Maupin
7

Nie, TCP nie musi otwierać nowego połączenia dla każdego wysyłanego pakietu.

Możesz wysyłać wiele pakietów za pomocą trwałych połączeń HTTP , gdzie:

... jedno połączenie TCP do wysyłania i odbierania wielu żądań / odpowiedzi HTTP [jest używane], w przeciwieństwie do otwierania nowego połączenia dla każdej pary żądań / odpowiedzi.

W załączeniu jest rysunek pokazujący różnicę między wieloma połączeniami (ustanowiono wiele połączeń w celu wysłania jednego obiektu na połączenie) a połączeniem trwałym (ustanowiono jedno połączenie i wysłano do niego wiele obiektów):

Wiele połączeń a połączenie trwałe

Źródło: https://www.vcloudnine.de/how-to-dramatically-improve-website-load-times/


źródło
7
Ta odpowiedź wydaje się myląca. Żądanie / odpowiedź HTTP rzadko jest pojedynczym pakietem.
Barmar
2
Nie wspominając już, że każde „otwarte” to tak naprawdę 3 strzałki (syn, synack, ack), a każde „zamknięcie” to kolejne 4 (fin, ack 2x serwer i klient), więc jeśli rzeczywiście byłoby połączenie na pakiet, to narzut szybko by się sumowało.
htmlcoderexe
5

Twoja interpretacja działania TCP jest poprawna.

Co do tego, co powiedział twój przyjaciel, widzę tutaj dwie możliwości:

  1. Źle zrozumiałeś swojego przyjaciela, który odnosił się do pewnych ograniczeń warstwy aplikacji, które powodują, że każda wiadomość jest wysyłana przez nowe połączenie (i nie jest to niekoniecznie niezwykłe; decyzja o takim zachowaniu może, ale nie musi być możliwa, w zależności od oprogramowania stos, którego używasz);

  2. Twój przyjaciel się myli.

Lekkość Wyścigi z Moniką
źródło
5

Jak zauważyli inni, TCP absolutnie pozwala, aby połączenie pozostawało otwarte przez dowolny czas, wymieniając dowolną liczbę „wiadomości” w obu kierunkach w tym czasie. To powiedziawszy, to ostatecznie do aplikacji (zarówno klienta, jak i serwera) należy określenie, czy ta zdolność zostanie wykorzystana.

Aby ponownie wykorzystać istniejące połączenie TCP (gniazdo), aplikacja kliencka musi pozostawić to gniazdo otwarte i używać go, gdy musi zapisać więcej danych. Jeśli klient tego nie zrobi, ale zamiast tego odrzuci stare gniazdo i otworzy nowe gniazdo za każdym razem, gdy będzie potrzebne, to rzeczywiście wymusi nowe połączenie, które może powodować problemy z zasobami na kliencie lub serwerze, jeśli będzie to wykonywane wystarczająco często, aby wyczerpać albo pula połączeń stosu TCP.

Podobnie, serwer musi być wystarczająco inteligentny, aby pozostawić gniazdo otwarte z boku i czekać na więcej danych. Podobnie jak klient, ma opcję zamknięcia gniazda, w którym to odporny na błędy klient, który chce wysłać więcej danych, nie będzie miał innego wyjścia, jak otworzyć nowe gniazdo, co prowadzi do tego samego problemu.

Wreszcie, jak wspomnieli inni, TCP jest zorientowany na strumień. Nie ma żadnych ramek. Tylko dlatego, że jeden uczestnik zapisał dane w określony sposób (np. Wywołanie zapisu 1 1024 bajtów, a następnie wywołania zapisu 2 256 bajtów), nie gwarantuje to, że drugi uczestnik odczyta je w kawałkach tego samego rozmiaru (np. Może otrzymać wszystkie 1536 bajtów w jednym odczytanym połączeniu). Dlatego jeśli wysyłasz wiele „wiadomości” przez surowe gniazda TCP, musisz podać własny protokół ramkowania, aby nakreślić różne wiadomości. Chociaż z pewnością istnieją proste sposoby, aby to zrobić, jest to generalnie odradzane, ponieważ istnieje wiele protokołów zbudowanych na TCP, aby rozwiązać ten problem. W celu dalszej dyskusji zapoznaj się z tym: https://blog.stephencleary.com/2009/04/message-framing.html

Szkot
źródło
2

Myślę, że twój przyjaciel mówił o HTTP, a nie o TCP.

HTTP był pierwotnie protokołem bezstanowym: każde żądanie HTTP używałoby osobnego połączenia TCP. Dlatego potrzebujemy plików cookie (lub czegoś podobnego) do wdrożenia sesji.

reinierpost
źródło
0

Wspomniałeś o „pojedynczym połączeniu i wymaganiu nowego portu za każdym razem”, i zinterpretowałbym to, ponieważ masz wielu klientów korzystających z techniki PAT w tym samym środowisku sieciowym, aby połączyć się z serwerem spoza twojej organizacji. PAT miałby limit 65535 (limit sesji TCP dla adresu IPv4). Jeśli to prawda, masz limit.

Czy TCP otwiera nowe połączenie dla każdego wysyłanego pakietu? NIE, nie trwa tak długo, jak ważna jest sesja TCP. i ...

Witaj
źródło
0

Podoba mi się doskonała strona wikipedia na TCP . Wyraźnie pokazuje, co dzieje się z numerem portu. Zawiera on również przypadkowo przydatny rozdział na temat wykorzystania zasobów:

Użycie zasobów

Większość implementacji przydziela pozycję w tabeli, która mapuje sesję do działającego procesu systemu operacyjnego. Ponieważ pakiety TCP nie zawierają identyfikatora sesji, oba punkty końcowe identyfikują sesję przy użyciu adresu i portu klienta. Za każdym razem, gdy odbierany jest pakiet, implementacja TCP musi przeprowadzić wyszukiwanie w tej tabeli, aby znaleźć proces docelowy. Każdy wpis w tabeli jest znany jako Blok Kontroli Transmisji lub TCB. Zawiera informacje o punktach końcowych (adres IP i port), status połączenia, uruchamianie danych o wymienianych pakietach oraz bufory do wysyłania i odbierania danych.

Liczba sesji po stronie serwera jest ograniczona tylko pamięcią i może rosnąć wraz z nadejściem nowych połączeń, ale klient musi przydzielić losowy port przed wysłaniem pierwszej SYN do serwera. Ten port pozostaje przydzielony podczas całej rozmowy i skutecznie ogranicza liczbę połączeń wychodzących z każdego adresu IP klienta. Jeśli aplikacja nie zamknie poprawnie niepotrzebnych połączeń, klientowi może zabraknąć zasobów i nie będzie mógł ustanowić nowych połączeń TCP, nawet z innych aplikacji.

Krótko mówiąc, TCP zużywa jeden bardzo skończony zasób, czyli liczbę portów na kliencie (która jest ograniczona rozmiarem pola portu w nagłówku TCP, 16 bitów).

Tak, TCP jest w stanie uruchomić z portów, jeśli klient otwiera wiele połączeń TCP równolegle bez ich zamykania. Problem występuje tylko po stronie klienta i nie ma znaczenia, czy połączenia mają takie same lub różne adresy IP serwera lub porty serwera.

W twoim otoczeniu wydaje się, że masz jedną aplikację, która przyjmuje wiele żądań klientów ( temogą to być pojedyncze żądania TCP, ponieważ być może klienci używają tego do rejestrowania niektórych zdarzeń w aplikacji i nie utrzymują otwartego kanału TCP między nimi) i tworzenia nowego wewnętrznego żądania do brokera Kafka (którym bardzo łatwo mogą być pojedyncze połączenia TCP jeśli zdecydujesz się je wdrożyć w ten sposób). W takim przypadku wąskim gardłem (jeśli chodzi o zasoby, a nie wydajność) byłoby, gdyby udało się uzyskać ogromną liczbę żądań w tym samym czasie od klientów (bez problemu, ponieważ po stronie serwera potrzebny jest tylko jeden port do wszystkie), a Ty otworzysz ogromną liczbę żądań przesyłania dalej do swojej Kafki, a Kafka nie jest w stanie przetworzyć ich wystarczająco szybko, co kończy się tym, że masz więcej niż 16 bitów połączeń otwartych jednocześnie.

Jesteś tutaj własnym sędzią; sprawdź swoją aplikację i spróbuj za każdym razem dowiedzieć się, czy łączysz się z Kafką za pomocą osobnego żądania (być może za pośrednictwem proxy REST API). Jeśli to zrobisz i masz ogromną liczbę klientów, z pewnością jesteś w niebezpieczeństwie.

Jeśli masz tylko garstkę klientów, mniej niż 65 tys. I / lub utrzymujesz jedno połączenie z przeglądarką Kafka, nic ci nie będzie.

AnoE
źródło