Чи відкриває TCP нове з'єднання для кожного відправленого пакету?


15

Це може бути дурним питанням, але я та кілька приятелів обговорювали потенційні обмеження TCP. У нас є додаток, який збирається слухати клієнтів (придумайте шлюз) і спрямовує всі дані підключених клієнтів через одного підключеного видавця kafka до однієї теми.

Один з моїх приятелів говорить, що TCP буде проблемою для цього шлюзу, оскільки він буде встановлювати нове з'єднання для кожного повідомлення, яке він надсилає (не кафка, а сам базовий протокол транспортування - це проблема), вимагаючи кожного порту кожного разу. За швидкістю, коли ми будемо надсилати цим клієнтам повідомлення (гігабайти), у кафки не вистачить портів для читання ??

Я займався розробкою протягом декількох років і ніколи раніше про це не чув і хотів би зрозуміти нижчий рівень (як я вважав, що маю) того, як працює TCP. Я розумію, що коли ви встановлюєте TCP-з'єднання, це з'єднання залишається відкритим, поки його програма не вимкне або примусово закриває або сервер, або клієнт. Дані, що надсилаються через це з'єднання, є потоком і не відкриватимуть / закриватимуть нові з'єднання незалежно від 3 V (об'єм, швидкість, різноманітність).

Що стосується портів, один порт використовується для трансляції, а внутрішній порт дескриптора файлів - це те, що програма управляє для читання / запису окремих клієнтів. Я ніколи не розумів TCP для встановлення нових з'єднань для кожного пакету, який він пише.

Прошу вибачення заздалегідь, якщо це питання не є прямим і або занадто розпливчастим. Я справді збентежений і сподіваюся, що хтось може дати ще якийсь контекст тому, що говорять мої колеги?


13
Я думаю, ти неправильно зрозумів, що говорив твій друг. TCP не робить цього, але можливо, що певний клієнт встановить нове з'єднання TCP для кожного повідомлення, яке він хоче передати.
варення

13
TCP не міг відкрити нове з'єднання для кожного пакету, оскільки для відкриття нового з'єднання йому потрібно кілька пакетів. І не вдалося відкрити нове з'єднання для кожного повідомлення, оскільки TCP не має поняття повідомлення. Ваш приятель дуже розгублений. Найважливіше, що потрібно зрозуміти про TCP, найбільш фундаментальну концепцію, - це те, що TCP є протоколом потоку байтів.
Девід Шварц

1
Аргумент вашого приятеля не обов’язково помиляється - якщо ви не повторно використовуєте порти через підтримку на рівні додатків або просто занадто багато клієнтів, у вашій системі може не вистачити ефемерних портів. Існують способи подолати цю проблему: використання SO_REUSEADDRдля швидшого закриття сокетів, збільшення діапазону ефемерних портів тощо. Крім того, TCP_FASTOPENкілька перемикачів на рівні ОС можна використовувати для подолання інших відомих обмежень TCP. Так чи інакше, немає сенсу обговорювати обмеження TCP, коли у вас навіть немає навантаження для тестування.
user1643723

Відповіді:


22

Один з моїх приятелів говорить, що TCP буде проблемою для цього шлюзу, оскільки він буде встановлювати нове з'єднання для кожного повідомлення, яке він надсилає (не кафка, а сам базовий протокол транспортування - це проблема), вимагаючи кожного порту кожного разу. За швидкістю, коли ми будемо надсилати цим клієнтам повідомлення (гігабайти), у кафки не вистачить портів для читання ??

Твій друг сильно розгублений. TCP - протокольно орієнтований протокол. Він не має поняття повідомлень. Звичайно, він використовує пакети на рівні IP, але для програми це деталь реалізації. TCP вставляє межі пакетів, де це має сенс робити, а не обов'язково один раз на write()абоsend() . Аналогічно, він поєднує послідовні пакети разом, якщо ви отримуєте більше одного між дзвінками до read()або recv().

Потрібно сказати, що ця орієнтована на потоки конструкція була б абсолютно непрацездатною, якби кожен поштовий зв’язок встановлював нове з'єднання. Отже, єдиний спосіб встановити нове з'єднання - це закрити та знову відкрити з'єднання вручну.

(На практиці більшість протоколів, побудованих поверх TCP, мають щось подібне до повідомлень, таких як HTTP-запити та відповіді. Але TCP не знає і не піклується про структури таких речей.)

Цілком можливо, що ваш друг думав про UDP, у якому є повідомлення, але він також без зв'язку. Більшість реалізацій сокета дозволяють "підключити" UDP-сокет до віддаленого хоста, але це лише зручний спосіб уникнути необхідності неодноразово вказувати IP-адресу та порт. Це насправді нічого не робить на рівні мереж. Тим не менш, ви можете вручну відстежувати, з якими однолітками ви спілкуєтесь в рамках UDP. Але якщо ви це зробите, то вирішити, що вважається "з'єднанням" - це ваша проблема, а не ОС. Якщо ви хочете відновити "з'єднання" у кожному повідомленні, ви можете це зробити. Це, мабуть, не дуже гарна ідея.


9

Я розумію, що коли ви встановлюєте TCP-з'єднання, це з'єднання залишається відкритим, поки його програма не вимкне або примусово закриває або сервер, або клієнт.

З точки зору TCP, немає клієнта чи сервера (клієнт / сервер - це концепція програми, яка тут поза темою). TCP встановлює зв'язок між одноранговими, і обидва однорангові можуть надсилати та приймати по з’єднанню, поки будь-який одноранговий канал не закриє його, або він не вичерпається.

Дані, що надсилаються через це з'єднання, є потоком і не відкриватимуть / закриватимуть нові з'єднання незалежно від 3 V (об'єм, швидкість, різноманітність).

Що може бентежити ситуацію, це те, що деякі програми, наприклад браузери, відкриють безліч з'єднань, щоб одночасно завантажувати такі речі, як елементи веб-сторінки.

TCP не відкриває нове з'єднання для кожного сегменту, який він надсилає, але програма може відкрити кілька з'єднань TCP. Крім того, коли з'єднання TCP закрите, порт TCP, який використовується в з'єднанні, звільняється, і він може бути використаний знову. Ця відповідь дає деяку інформацію, і вона вказує на RFC для TCP.


2
Хоча в TCP є один партнер, який ініціював з'єднання (часто його називають "клієнтом"), а інший (часто його називають "сервер"). Звичайно, після встановлення зв'язку ця різниця вже не має значення.
Paŭlo Ebermann

2
@ PaŭloEbermann, у TCP RFC немає нічого про клієнтів чи серверів. Концепція клієнт / сервер - це концепція програми. Тема тут - це протоколи на рівні OSI 4 або нижче, і в цих протоколах немає клієнтів і серверів. Насправді те, що ви можете вважати клієнтом (тим, що відкриває TCP-з'єднання), насправді може бути сервером додатків. У нас є сервери, які ініціюють підключення TCP до клієнтів, щоб робити такі дії, як перевірка безпеки та оновлення.
Рон Моупін

7

Ні, TCP не потрібно відкривати нове з'єднання для кожного надісланого пакету.

Ви можете надіслати кілька пакетів за допомогою стійких HTTP-з'єднань , де:

... використовується одне TCP-з'єднання для надсилання та отримання декількох запитів / відповідей HTTP [використовується], на відміну від відкриття нового з'єднання для кожної пари запитів / відповідей.

Додано фігуру, яка показує різницю між декількома з'єднаннями (безліч з'єднань, встановлених для надсилання одного об’єкта на з'єднання) та стійким з'єднанням (встановлено одне з'єднання та декілька об'єктів, що надсилаються в ньому):

Кілька з'єднань проти постійного з'єднання

Джерело: https://www.vcloudnine.de/how-to-dramatic-improve-website-load-times/


7
Ця відповідь схоже на заплутані шари. Запит / відповідь HTTP рідко є одним пакетом.
Бармар

2
Не кажучи вже про кожен "відкритий" - це насправді 3 стрілки (syn, synack, ack), а кожен "close" - це ще 4 (fin, ack 2x сервер і клієнт), тож якщо насправді було би з'єднання на пакет, накладні витрати швидко складеться.
htmlcoderexe

5

Ваша інтерпретація того, як працює TCP, є правильною.

Щодо того, що сказав ваш друг, я бачу тут дві можливості:

  1. Ви неправильно зрозуміли свого друга, який мав на увазі обмеження на рівні додатків, що призводить до того, що кожне повідомлення надсилається через нове з'єднання (і це необов'язково незвично; це може бути, а може і не бути можливим, щоб визначитися з такою поведінкою, залежно від програмного забезпечення стек, який ви використовуєте);

  2. Твій друг помиляється.


5

Як зазначали інші, TCP абсолютно дозволяє з'єднанню залишатися відкритим протягом будь-якої кількості часу, обмінюючись будь-якою кількістю "повідомлень" у будь-якому напрямку за цей час. Однак, в кінцевому підсумку, додатки (і клієнтські, і серверні) визначають, чи використовується ця можливість.

Для повторного використання існуючого TCP-з'єднання (сокета) клієнтська програма повинна тримати цей сокет відкритим і використовувати його, коли йому потрібно записати більше даних. Якщо клієнт цього не робить, а замість цього відкидає старий сокет і відкриває новий розетку кожного разу, коли він потребує, він дійсно примусить нове з'єднання, яке може спричинити проблеми з ресурсами або у клієнта, або на сервері, якщо зробити це досить часто, щоб вичерпати або пул підключення стека TCP.

Аналогічно, сервер повинен бути достатньо розумним, щоб тримати сокет відкритим на боці і чекати додаткових даних. Як і у клієнта, у нього є можливість закрити сокет, і в цей момент у клієнта, який не має помилок, який бажає надіслати більше даних, не залишиться іншого вибору, як відкрити новий розетку, що призведе до тієї ж проблеми.

Нарешті, як уже згадували інші, TCP орієнтована на потоки. Немає жодного обрамлення. Тільки тому, що один одноранговий записував дані певним чином (наприклад, 1 1024 байт виклику запису, наступного за 2 256 дзвінками запису запису), це не гарантує, що інший одноранговий читатиме їх у однакових розмірах (наприклад, він може отримати всі 1536 байт в одному читаному дзвінку). Таким чином, якщо ви надсилаєте кілька "повідомлень" через необроблені сокети TCP, ви повинні надати свій власний протокол обрамлення для розмежування різних повідомлень. Хоча, звичайно, є прості способи зробити це, як правило, недоцільно, оскільки існує багато протоколів, побудованих поверх TCP для вирішення цієї проблеми. Для подальшої дискусії зверніться до цього: https://blog.stephencleary.com/2009/04/message-framing.html


2

Я думаю, що твій друг говорив про HTTP, а не про TCP.

Спочатку HTTP був протоколом без стану: кожен запит HTTP використовував би окреме TCP-з'єднання. Ось чому нам потрібні файли cookie (або щось подібне) для впровадження сеансів.


0

Ви згадали про "єдине підключення та вимагаєте нового порту кожного разу", і я би трактував, як у вас є багато клієнтів, що використовують техніку PAT в тому ж мережевому середовищі для підключення до сервера поза вашою організацією. PAT матиме обмеження 65535 (ліміт сеансу TCP для адреси IPv4). Якщо це правда, у вас є межа.

Чи відкриває TCP нове з'єднання для кожного відправленого пакету? НІ, це не доки дійсний сеанс TCP. і ...


0

Мені подобається відмінна сторінка wikipedia на TCP . Це чітко показує, що відбувається з номером порту. Він, випадково, також містить корисну главу про використання ресурсів:

Використання ресурсів

Більшість реалізацій виділяють запис у таблиці, який відображає сеанс у запущеному процесі операційної системи. Оскільки пакети TCP не містять ідентифікатор сеансу, обидві кінцеві точки ідентифікують сеанс, використовуючи адресу клієнта та порт. Щоразу, коли пакет отримується, реалізація TCP повинна виконати пошук у цій таблиці, щоб знайти процес призначення. Кожен запис у таблиці відомий як Блок управління передачею або TCB. Він містить інформацію про кінцеві точки (IP та порт), стан з'єднання, запущені дані про пакети, що обмінюються, та буфери для надсилання та прийому даних.

Кількість сеансів на стороні сервера обмежена лише пам'яттю і може зростати в міру надходження нових з'єднань, але клієнт повинен виділити випадковий порт перед відправкою першого SYN на сервер. Цей порт залишається виділеним протягом усієї розмови і фактично обмежує кількість вихідних з'єднань з кожної IP-адреси клієнта. Якщо програма не зможе належним чином закрити непотрібні з'єднання, клієнт може не вистачати ресурсів і не зможе встановити нові TCP-з'єднання навіть з інших програм.

Коротше кажучи, TCP використовує один дуже обмежений ресурс, який є кількістю портів клієнта (який обмежений розміром поля порту в заголовку TCP, 16 біт).

Таким чином, TCP є можливість запускати з портів, якщо клієнт відкриває багато TCP з'єднань паралельно , не закриваючи їх. Проблема виникає лише на стороні клієнта, і не має значення, чи є з'єднання з однаковими або різними IP-адресами сервера або портами сервера.

У вашому налаштуванні, здається, у вас є одна програма, яка містить багато запитів клієнтів ( ціце можуть бути індивідуальні запити TCP, оскільки, можливо, ваші клієнти використовують це для реєстрації деяких подій у вашій програмі та не тримають канал TCP відкритим між ними) та створюють новий внутрішній запит до свого брокера Kafka (який дуже легко може бути індивідуальним TCP-з'єднанням якщо ви вирішили їх реалізувати так). У цьому випадку вузьке місце (з точки зору ресурсів, а не продуктивності) було б, якщо вам вдасться отримати величезну кількість запитів одночасно від своїх клієнтів (для вас це не проблема, оскільки на сервері вам потрібен лише один порт для усі вони), і ви відкриваєте величезну кількість переадресаційних запитів до вашої Кафки, і Кафка не в змозі обробити їх досить швидко, і в кінцевому підсумку ви матимете одночасно відкриті з’єднання на суму понад 16 біт.

Ви тут власний суддя; перевірте свою програму та спробуйте з’ясувати, чи підключаєте Ви до Кафки окремий запит кожного разу (можливо, через якийсь проксі-сервер API REST). Якщо ви так зробите, і у вас є величезна кількість клієнтів, то вам неодмінно загрожує небезпека.

Якщо у вас є лише кілька клієнтів, менших ніж 65 кш, та / або ви підтримуєте єдине з'єднання зі своїм браузером Kafka, тоді ви будете добре.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.