TCP отправляет SYN / ACK для каждого пакета или только при первом подключении?

У меня есть TCP-сервер, который прослушивает входящего клиента, а затем отправляет ему один пакет данных каждую секунду. Мне было интересно, пакет SYN / ACK отправляется только при первоначальном подключении, поэтому он выглядит так:

<client connect>
SYN
ACK
DATA
DATA
DATA
<client disconnect>

Или он отправляется с каждым пакетом, вот так?

<client connect>
SYN
ACK
DATA

SYN
ACK
DATA

SYN
ACK
DATA
<client disconnect>

Кроме того, если это первый случай, есть ли какие-либо преимущества UDP по сравнению с TCP, если вы просто сохраняете соединение открытым в течение длительного периода времени?


person Daniel T.    schedule 30.08.2010    source источник
comment
В TCP / IP нет пакетов. См. Правильную терминологию здесь: stackoverflow.com/questions/955369 /   -  person Joe Phillips    schedule 31.08.2010
comment
@Phillips - TCP - это протокол, основанный на IP. Нет понятия сегментов до тех пор, пока они не будут обработаны TCP. В ходе этого процесса определенно допустимо называть входящие данные пакетами, а не сегментами, потому что в такой момент они, в конце концов, являются только IP-пакетами. Входит в TCP в виде IP-пакетов, выходит в виде сегментов, сообщений и т. Д.   -  person JSON    schedule 15.11.2015


Ответы (3)


Это вроде как:

+-------------------------------------------------------+
|     client           network            server        |
+-----------------+                +--------------------|
|    (connect)    | ---- SYN ----> |                    |
|                 | <-- SYN,ACK -- |     (accepted)     |
|   (connected)   | ---- ACK ----> |                    |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

when client sends...
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|                 |                |                    |
|     (send)      | ---- data ---> |                    |
|                 | <---- ACK ---- |  (data received)   |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

when server sends...
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|                 |                |                    |
|                 | <--- data ---- |       (send)       |
| (data received) | ---- ACK ----> |                    |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

...and so on, til the connection is shut down or reset

SYN запускает соединение; вы обычно увидите его только тогда, когда соединение будет установлено. Но для всех данных, отправляемых через TCP, требуется ACK. Каждый отправленный байт должен быть учтен, иначе он будет передан повторно (или сброс соединения (закрытие), в тяжелых случаях).

Однако фактические соединения обычно не в точности такие, как на диаграмме выше, по двум причинам:

  • ACK могут накапливаться, поэтому один ACK может подтверждать все, что было получено до этого момента. Это означает, что вы можете подтвердить две или более отправки одним ACK.
  • ACK - это просто флаг и поле в заголовке TCP. Для его отправки требуется, по крайней мере, пропускная способность заголовка, плюс все, что закреплено на нижних уровнях. Но сегменты данных уже включают все это ... поэтому, если вы отправляете данные, вы можете отправить ACK одновременно бесплатно.

Большинство стеков TCP / IP пытаются уменьшить количество голых ACK без чрезмерного риска повторной передачи или сброса соединения. Так что такой разговор вполне возможен:

\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|                 |                |                    |
|                 | <--- data ---- |       (send)       |
| (data received) |                |                    |
|     (send)      | -- data,ACK -> |                    |
|                 |                |  (data received)   |
|                 | <- data,ACK -- |       (send)       |
| (data received) |                |                    |
|  (wait a bit)   | <--- data ---- |       (send)       |
| (data received) |                |                    |
|     (send)      | -- data,ACK -> |                    |
|                 |                |  (data received)   |
|     (send)      | ---- data ---> |   (wait a bit)     |
|                 |                |  (data received)   |
|                 | <- data,ACK -- |       (send)       |
| (data received) |                |                    |
|  (wait a bit)   |   (dead air)   |                    |
|                 | ---- ACK ----> |                    |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

Что касается UDP, здесь нет встроенной концепции SYN и ACK - UDP по своей природе «ненадежен» и не ориентирован на установление соединения, поэтому эти концепции не применяются в такой степени. Ваше подтверждение обычно будет просто ответом сервера. Но некоторые протоколы прикладного уровня, построенные на основе UDP, будут иметь определенный для протокола способ подтверждения отправленных и полученных данных.

person cHao    schedule 30.08.2010
comment
ACK может усложниться. Это не для каждого пакета данных, но для того, сколько было получено, поэтому может быть один ACK на каждые 8 ​​пакетов. На отправляющей стороне есть окно, в котором указывается, сколько она отправит, прежде чем должна получить ACK. Затем есть выборочный ACK, который используется для обозначения полученных байтов 2000-8000, но не 0-2000. - person Zan Lynx; 31.08.2010
comment
Протокол пользовательских дейтаграмм часто используется в протоколах запрос-ответ, где ответ на запрос демонстрирует, что он был получен, а отсутствие повторного запроса демонстрирует ответчику, что либо его ответ был получен, либо отправитель запроса дал вверх (и ответчику все равно, что, поскольку его правильный ответ в любом случае - больше ничего не делать). - person supercat; 01.05.2013

SYN находится только в начале.

ACK находится на последующих сегментах в любом направлении. ACK также определяет размер окна. Например, если размер окна равен 100, отправитель может отправить 100 сегментов, прежде чем он ожидает получить ACK. Например, если отправитель отправляет 100 сегментов, но сегмент 50 теряется, то получатель получит 1-49 и 51-100. Получатель затем ACK для 50 (следующий сегмент, который он ожидает) и установит размер окна на 1. Отправитель повторно отправит 1 сегмент с порядковым номером 50. Затем получатель будет ACK для 101 и снова установит размер окна на большее число.

Оба фактически являются полями в заголовке TCP и могут быть отправлены с данными, хотя SYN и первый ACK обычно не содержат данных.

Так что ни один из описанных вами сценариев не совсем верен. Первый на самом деле ближе к реальности, но все пакеты данных после SYN действительно должны включать ACK, а также поле номера подтверждения, которое идентифицирует номер следующего ожидаемого пакета.

Конец сеанса также включает в себя рукопожатия с пакетами с флагом FIN и связанными с ними ACK.

Обмениваемые порядковые номера используются для идентификации потерянных пакетов и включения механизма повторной попытки, а также для повторной сборки всего потока пакетов в правильном порядке.

Кроме того, если это первый случай, есть ли какие-либо преимущества UDP по сравнению с TCP, если вы просто сохраняете соединение открытым в течение длительного периода времени?

С UDP вы не можете просто поддерживать соединение открытым в течение длительного периода времени. Нет подключения.

Эта последовательность флагов SYN / ACK / FIN - это то, что устанавливает соединение.

В UDP отсутствуют SYN или ACK, поэтому связь является односторонней, доставка не гарантируется, а порядок не сохраняется. Но у него меньше накладных расходов, поэтому он полезен, когда скорость важнее надежности, например, при потоковой передаче мультимедиа.

Это еще немного упрощено, но это лучшее, что я могу сделать на данный момент.

Подробнее об этом можно прочитать в статье в Википедии о TCP и, конечно же, в RFC.

person Don Roby    schedule 30.08.2010
comment
Я также порекомендовал бы книгу У. Ричарда Стивенса TCP / IP Illustrated, Volume 1 - The Protocols, в дополнение к чтению Wikipedia и RFC. С мозгом чуть проще :) - person Michael J. Gray; 20.06.2014
comment
Отправитель повторно отправит 1 сегмент с порядковым номером 50. Тогда получатель будет ACK для 101, если это не будет Получатель затем будет ACK для 51, поскольку последний полученный сегмент был 50? - person Rafael Eyng; 17.06.2016
comment
Я не понимаю комментарий о «общении в одну сторону». В этом нет никакого смысла. UDP - это просто тривиальный, чрезвычайно тонкий слой поверх IP, и поскольку это просто IP с небольшим количеством шоколадного соуса поверх, вы можете отправлять пакеты UDP в обоих направлениях. - person Cecil Ward; 19.07.2017
comment
Если разработчик решает использовать UDP, это делается для получения более высоких скоростных характеристик и минимизации объема передаваемого трафика или, в качестве альтернативы, для обеспечения полного контроля над методами связи. Используя UDP, разработчик может при желании построить новый тип протокола с полной свободой выбора. Некоторым приложениям может не потребоваться надежная доставка, гарантии доставки в порядке или другие преимущества, которые предоставляют такие протоколы, как TCP или SCTP. Однако разработчику, возможно, придется проделать гораздо больше проектной работы, если он использует UDP, усложняя код приложения или заканчивая изобретением собственного протокола. - person Cecil Ward; 19.07.2017
comment
@RafaelEyng нет, поскольку сегменты 51-100 буферизуются на стороне получателя. Когда он получает недостающий сегмент посередине, он размещает их в правильном порядке и теперь имеет все от 1 до 100. Нет необходимости запрашивать сегменты, которые у вас уже есть. - person Jan; 02.11.2018

Представьте себе: исходный стандарт TCP RFC 793 позволял отправлять данные с первым пакетом SYN. Однако сегодня это не так. Вы получаете отдельный SYN-пакет во время инициирования трехстороннего рукопожатия от запрашивающего соединения. Предположим, A запрашивает соединение с B, таким образом, A отправляет пакет с установленным битом SYN. B отвечает ACK, чтобы подтвердить получение, и отправляет A пакеты ACK + SYN. После этого данные можно будет передавать.

У Дордала есть очень хорошее объяснение по этому поводу. Щелкните здесь по этой ссылке.

person StacknormalFlow    schedule 30.12.2017
comment
Эта ссылка не работает. Вот почему вы не должны ссылаться на внешние материалы для получения ответов. - person neuhaus; 08.06.2021