Транспортный уровень: TCP и UDP
Цели:
- Цельность передаваемых данных и надёжность передачи
- Различение потоков и управление ими
Задачи:
- Передано == принято
Порядок пакетов или один пакет
- Управление процессом передачи
Двустороннее соединение (с проверкой доступности) или один пакет
Подтверждение доставки / ошибки / и т. п. или один пакет
Обмен данными о состоянии канала или один пакет
⇒ Поток или датаграмма
- Идентификация потоков и датаграмм
- Адрес отправителя, адрес получателя
- Порт отправителя, порт получателя
UDP — «один пакет», TCP — поток
Порт + поток ⇒ клиент/сервер. Асимметричная (клиент-серверная) природа транспортных протоколов.
- «Клиент» — инициатор передачи данных, он посылает запрос «серверу»
- «Сервер» — второй участник обмена данными, он «ждёт запроса от клиента»
- ⇒ кто там из них в действительности клиент, а кто сервер, неважно!
TCP |
vs |
UDP |
есть |
подключение |
нет |
есть |
подтверждения |
нет |
есть |
отслеживание цельности потока |
нет |
есть |
отслеживание качества потока |
нет |
несколько |
количество пакетов |
один |
TCP
- Установление (и завершение) соединения
- Подтверждение доставки каждого пакета
- Уведомление об ошибках
- Повторная передача при отсутствии уведомлений
- Окно «одновременно» пересылаемых пакетов
- Поддержка цельности потока / порядка пакетов с помощью Sequential Number
Двунаправленное (т. е. состоит из двух встречных потоков)
Понятие «порт»
- Идентификатор соединения — IP+порт отправителя, IP+порт получателя
Привязка портов: /etc/services и временный порт отправителя.
Sequential Number
Задачи:
- Порядковая нумерация пакетов в потоке (на случай переупорядочивания)
- Контроль целостности потока пакетов (на случай удвоения / потери)
Решение:
- SEQN (Sequential Number) — объём переданных байтов в потоке:
- передаётся в каждом пакете,
- изначально выбирается случайным,
- прирастает на объём переданных байтов.
- ⇒ это и нумерация (последовательность), и проверка потерь (несовпадение SEQN и действительного объёма)
Подключение
Пакеты могут носить с собой т. н. флаги — это способ управления соединением
3-way handshake — установление двунаправленного соединения (флаг SYN — запрос на подключение, флаг FIN — запрос на отключение, флаг ACK — подтверждение получения пакета):
Client → (SYN1) → Server
Client ← (ACK1+SYN2) ← Server
Client → (ACK2+PAYLOAD) → Server
- …
Кто-то первый → (FIN1) → Кто-то второй
Кто-то первый ← (ACK1+FIN2) ← Кто-то второй
Кто-то первый → (ACK2) → Кто-то второй
Завершение соединение может инициировать любая сторона.
- У этого алгоритма есть несколько модификаций
(Пример: tcpdump tcp-соединения)
Демо на YouTube
Обработка ошибок и обеспечение надёжности
Получение каждого пакета в каждую сторону нужно подтвердить (ACK)
- Обработка ошибок TCP (если пакет испортился; возможно, если не дошёл)
- Повторная пересылка после тайм-аута (если не пришло подтверждение)
Sliding Window
Средство от всего — Sliding window protocol и «низкий старт».
Статья Лохматого Мамонта на Хабре
На Студопедии (цитата из CCNA)
Больше адаПодробнее на Википедии
Окно — это последовательная группа пакетов из потока, которую можно передавать/получать «одновременно», не дожидаясь подтверждения каждого.
При получении очередного пакета окно «сдвигается» на следующий ещё не полученный. Если пакеты идут с разной скоростью или пропадают, в окне получателя образуется «недопринятая» область:
- Непрерывное начало потока уже получено целиком
- Окно приёма из N пакетов
- Первый пакет в окне ещё не получен (сразу после получения начало окна сдвигается)
- Далее — какие-то пакеты в окне получены (вне очереди), какие-то — нет
- Остальные пакеты потока пока только предполагаются ☺
При отправлении TCP дожидается, пока каджому отправленному пакету придёт подтверждение (годится и подтверждение о приёме одного из следующих пакетов, см. далее). Если некоторые подтверждения по тем или иным причинам не пришли, образуется «недопереданная» область.
- Непрерывное начало потока уже передано.
- Окно передачи из N пакетов
- Первый пакет в окне отправлен, но ещё не подтверждён (как только подтверждение пришло, начало окна сдвигается)
- Далее — какие-то пакеты в окне уже отправлены, какие-то — ещё нет, но подтверждённых среди них не (подтверждение пакета M автоматически означает, что пакеты M-k тоже уже получены)
- Остальные пакеты потока пока только предполагаются ☺
TODO перейти с Flash на что-нибудь из этого:
https://github.com/nikhildsahu/Sliding-window-simulator (два алгоритма: Go Back N / Selective Repeat)
https://www2.tkn.tu-berlin.de/teaching/rn/animations/gbn_sr/ (тоже два алгоритма)
Фиксированное окно
Будем называть «очередными» пакеты, принадлежащие уже полученному потоку, а «внеочередными» — пакеты, принадлежащие недопринятой области окна, т. е. полученные раньше, чем какой-то предыдущий пакет потока.
- Отправитель:
- Передаёт все непереданные пакеты в окне
- Параллельно ждёт получения подтверждения каждому из пакетов
- Подтверждение пакета N означает также подтверждение всех пакетов N-k
- При получении подтверждения пакета N начало окна перемещается на N+1 (появляются ещё непереданные пакеты)
- Для каждого ещё неподтверждённого пакета отслеживается тайм-аут. По истечении тайм-аута пакет посылается повторно.
- При получении диагностики «перешли пакет N» пакет посылается повторно
- Получатель:
- Ждет получения пакетов в окне
- При получении пакета:
Если в окне перед полученным пакетом есть непринятый — получен внеочередной пакет:
Посылается (повторно) подтверждение о получении последнего очередного пакета
Если получен первый пакет в окне (он же — первый непринятый), это очередной пакет:
- Высчитываются новые границы окна: окно начинается с первого непринятого пакета, то есть сдвигается вперёд на количество принятых. Их может быть более одного: если, скажем, пакеты N+1 и N+2 получены вне очереди, а затем только получен пакет N, и сразу три пакета переходят в категорию принятых.
изменяется указатель последнего очередного пакета (в примере выше — на N+2)
Посылается подтверждение о получении последнего очередного пакета (в примере выше — сразу N+2-го)
- Повторно полученные пакеты игнорируются.
- Если с пакетом что-то не так (не совпадает контрольная сумма и т. п.), отсылается просьба повторной пересылки
Этот алгоритм содержит несколько избыточное количество подтверждений, но:
- Это результат очень простой логики «пакет → подтверждение/ошибка»
- Это позволяет терять (некоторые) подтверждения без влияния на поток
Демо:
В виде .SWF-файла настолько старого, что в современных flash-эмуляторах работает неправильно
Масштабируемое окно
Чем больше окно, тем больше потенциальная пропускная способность:
- Если канал передачи данных готов столько передавать, хорошо!
- Если какое-то устройство на пути передачи данных столько передавать не готово — плохо:
Это устройство будет всегда терять пакеты из большого окна,
…что приведёт в посылке ещё большего количества пакетов (ошибки и повторная передача)
Чем меньше окно, тем меньше пропускная способность (спасибо, Кэп).
Поэтому размер окна может изменяться в зависимости от «качества» канала передачи данных.
На отправителе (т. н. Congestion window)
- Договаривается с получателем о максимальном и минимальном размерах окна
- Начинает с минимального размера
- При каждом сдвиге окна:
Если все пакеты в области сдвига были отосланы с первого раза (без повторов по тайм-ауту или ошибке), окно не только сдвигается, но и увеличивается (например, в два раза, но не больше чем максимальный размер)
- Если со времени последнего сдвига окна были повторные передачи пакетов, или получен анонс уменьшения размера окна, окно уменьшается до минимального
Если получен анонс нулевого размера окна, передача дополнительно приостанавливается на некоторый тайм-аут или до получения другого анонса (что случится раньше)
На получателе (т. н. Receive window)
- Если получатель не справляется с обработкой, он анонсирует меньший максимальный размер окна
Если получатель совсем не справляется с обработкой, он анонсирует нулевой размер окна
Напомним, что TCP — двунаправленное соединение, и во встречном потоке данных действуют те же правила, а абоненты меняются ролями.
Linux: sysctl net.ipv4.tcp_adv_win_scale
кроме того, TCP_window_scale_option
Дурацкое маленькое окошко на медленных / ненадёжных каналах.
Пример масштабирования окна (без обработки ошибок)
В виде .SWF-файла (тоже античного)
У скользящего окна ∃ ещё «быстрый старт» и много-много модификаций…
UDP
- Весь сеанс — одна датаграмма
- Нет шторма подтверждений
- Всё остальное делает прикладной уровень
Применение: DNS, traceroute, DHCP, SNMP, NTP
Использование netcat и socat
TCP-соединение предоставляет поток данных, так что все сетевые приложения написаны примерно одинаково:
- «Клиентские»
- устанавливают подключение по определённому порту+адресу сервера
вторая пара, порт+адрес клиента, генерируется автоматически, причём прот выбирается случайный, но большой, > 32767
- обменивается с сервером данными
- либо сама закрывается соединение, либо это делает сервер
- устанавливают подключение по определённому порту+адресу сервера
- «Серверные»
- Регистрируются в системе как процессы, принимающие подключение на определённом порту (и, возможно, адресе)
- Ждут подключения
- После того, как подключение произошло, начинают обмениваться данными с клиентом
- При этом обработчик соединения может быть отдельным процессом / тредом / корутиной, а основной поток управления в это время уже джёт следующего подключения
- Закрывает соединение, если клиент его не закрыл сам
С точки зрения ОС двунаправленный поток данных (как сложный, типа TCP-соединения, так и более простой, например, между двум процессами или вырожденный, типа датаграмм UDP) — это сокет.
Универсальные инструменты умеют в оба сценария — и клиентский и серверный, они просто перенаправляют поток данных откуда-то куда-то, наподобие утилиты cat. Содержимое потока (прикладной уровень) их не волнует, зато, как видно из описания выше, даже в самых простых случаях есть множество вариантов (например, по UDP доставлять только одну датаграмму или все, и что такое «все»).
Netcat — приём-передача данных по сети на стандартный В/В
- Установление TCP-подключения / Однократный приём подключения на TCP-порту
- Установление и приём UDP-«подключения»
- Проблема «окончания сеанса» (нет никакого сеанса, просто поток датаграмм, так что убивать руками)
- немножко умеет в Unix domain сокеты (сокеты в файловой системе)
пример TCP-клиента и сервера
Socat — приём-передача данных по сети самыми разнообразными способами
руководство, есть статьи попроще ☺
пример TCP-клиента и сервера
О незакрытых сокетах. Если использовать TCP-LISTEN:порт, то при падении процесса-сервера сокет не закрывается и висит в системе какое-то время; в течение этого времени нельзя запустить новый сервер, который слушает на том же порту. Надо использовать TCP-LISTEN:порт,reuseaddr.
Как используется soсat в наших скриптах: ../VirtualBoxTools/vbconnect
socat -,cfmakeraw,echo=0,escape=15 TCP4:localhost:порт
- — то же, что и STDIO:
cfmakeraw — raw режим (с control flow)
echo=0 — не отображать символы сразу при вводе
escape=15 — символ с кодом 15 (Ctrl+O) закрывает ввод
… socat
- Главное — не бояться ☺
Другие варианты транспорта?
Идентификатор потока нужен
Порядок пакетов отслеживается, но не гарантируется:
- Цельность желательна, но не полученные вовремя пакеты уже не важны (напр., видео или синхронизация игровых вселенных)
Интеграция с ECN (ACK-и могут быть помечены как предупреждение о забивании канала)
(also, DCCP+UDP для очень старых сетевых устройств и NAT)
SCTP:
Сеанс состоит из «сообщений» произвольного размера (TCP: либо несколько отдельных соединений, непонятно как объединяющихся в один сеанс, либо непрерывный поток, в котором сообщения выделяются уже на прикладном уровне)
Несколько параллельных потоков и multihoming (наконец-то из ID транспортного уровня открутили IP: абоненты рассказывают все свои адреса, а ID служит т. н. «association» и порт)
Двусторонняя готовность к сеансу (4-way handshake вместо 3-way — для отсечения syn flood)
- Порядок сообщений можно отключить
- Дешёвая (не порождающая паразитного трафика) / управляемая / прогнозируемая защита от забивания канала
RSVP (IPv6)
- Резервирование объёмов / пропускной способности / других свойств на всём маршруте
- …
Д/З
Обновлён образ:
Исправлен недочёт в autonet, приводящий к конфликтам с сетью 10.0.2.*/24, которая по умолчанию приезжает на интерфейс eth0, если использовать dhcpcd
Задание 6
Суть: Почитать документацию по socat (руководство, есть статьи попроще ☺) и организовать проброс TCP-соединения и UDP-датаграммы без использования маршрутизации.
- Площадка: Клиент-1 ←сеть1→ Клиент-2 ←Сеть-2→ Клиент-3
Настроить сеть на всех хостах заранее, в отчёт не входит
- Отчёт:
(на Клиенте-1) report 6 client1
Запустить socat в режиме listen на каком-нибудь TCP-порту с перенаправлением вывода на стандартный вывод
(на Клиенте-2) report 6 client2
Запустить socat в режиме listen на каком-нибудь TCP-порту и выводом на TCP-порт Клиента-1
(на Клиенте-3) report 6 client3
Запустить cal и перенаправить с помощью socat вывод на TCP-порт Клиента-2
В результате этой команды на Клиенте-1 появится вывод cal и все socat-ы остановятся
- (снова на Клиенте-1, report не останавливаем)
Запустить socat в режиме UDP-RECVFROM: (см. документацию) на каком-нибудь UDP-порту с перенаправлением вывода на стандартный вывод
- (снова на Клиенте-2, report не останавливаем)
Запустить socat в режиме UDP-RECVFROM: на каком-нибудь UDP-порту с выводом на UDP-порт Клиента-1 (режим UDP-SENDTO:)
- (снова на Клиенте-3)
Запустить cal и перенаправить с помощью socat (режим UDP-SENDTO:) вывод на UDP-порт Клиента-2
В результате этой команды на Клиенте-1 появится вывод cal и все socat-ы остановятся
- Остановить все report-ы
Три отчёта (названия сохранить, должно быть: report.06.client1, report.06.client2 и report.06.client3) переслать одним письмом в качестве приложений на uneexlectures@cs.msu.ru
В теме письма должно встречаться слово LinuxNetwork2024