воскресенье, 17 января 2010 г.

Где ваши гарантии?

На сайте IT Happens есть одна поучительная история о тупом завкафе и умном студенте. В ней есть одна интересная фраза, которая "как бы" говорит о том, насколько недалек завкаф и насколько умен студент.
Вот она: "C каких пор протокол TCP гарантирует доставку пакетов?"

Давайте разберемся. Честно ответьте на вопрос: а гарантирует ли TCP доставку пакетов? Все, кто ответил "да", станьте справа, те кто ответил "нет" (или "нет, но...") - слева.

Ребята слева, вы можете пока расходиться, с вами нам еще предстоит провести множество славных часов, ковыряясь в коде, играя в крокодила и контакт или просто за чашкой хорошего чая.

Ребята справа (те, кто ответил "да, гарантирует"), эта встреча у нас, увы, последняя. Возможно наши дороги еще пересекутся, но сегодня нам явно не по пути. Напоследок, давайте разберемся.

Я разделил наши "разбирательства" на три этапа:

Этап первый: философский.
Я не буду приводить сейчас общечеловеческих и философских соображений о том, что дом выстроенный на зыбком фундаменте может пошатываться, а один протокол базирующийся на другом протоколе не предоставляющем гарантий доставки (IP), сам не будет гарантировать ровным счетом ничего.

Этап второй: переводческий.
Будем прагматичны, обратимся к RFC.
В частности к RFC1122. Для начала я захотел понять, откуда же взялось выражение "гарантирует доставку" и произвел поиск по включению "guar". Итак, слово "guarantees" встречается в документе:

1. В разделе "1.1.3 Internet Protocol Suite" (1.1.3 Стек протоколов Internet) в описании Internet Layer, где говорится о том, что протокол IP не гарантирует доставки пакета.

2. В разделе "3.3.1.4 Dead Gateway Detection" (3.3.1.4 Обнаружение мертвых шлюзов), где говорится о том, что успешный пинг гарантирует то, что адресный интерфейс и сама машина включена, но не гарантирует того, что она будет выполнять роль шлюза.

3. В разделе "4.1.1 USER DATAGRAM PROTOCOL - UDP (INTRODUCTION)", где говорится что протокол UDP не гарантирует доставку дейтаграмм и практически предоставляет приложениям прямой доступ к протоколу IP.

На этом "гарантии" упомянутые в RFC заканчиваются. Т.е. мы понимаем, что в оригинальном документе нам никто ничего не гарантирует. Значит? Обратимся к переводу. Не уверен, существуют ли какие-то "праведные" переводы RFC (вроде Муравьевского перевода Толкиена или Маршаковского Бернса), но нам подойдет первый же выдаваемый Яндексом с сайта rfc.com.ru: RFC1122 на русском.

Поступим аналогичным образом, поищем включения "гаран". Слово "гарантированной" (и подобные), встречаются примерно в тех же местах, где и в английской версии плюс еще кое-где. Давайте посмотим эти отличающиеся моменты.

Первый раз мы сталкиваемся в том же разделе 1.1.3, но на один пункт раньше, на транспортном уровне:

TCP представляет собой основанный на соединениях (connection-oriented) транспортный сервис с гарантированной доставкой пакетов, обеспечивающий надежную доставку с сохранением порядка пакетов и управлением потоком данных.Протокол UDP не использует соединений (connectionless) и передает данные в виде дейтаграмм (datagram) без гарантии доставки.
Этот же абзац в английской версии выглядит так:

TCP is a reliable connection-oriented transport service that provides end-to-end reliability, resequencing, and flow control. UDP is a connectionless ("datagram") transport service.
Уважаемый Drop-bear и здравая логика буквально переводят это так:

TCP это надежная модель обмена данными от точки к точке с повторным упорядочиванием и управлением. UDP это модель обмена данными без установки соединения (дейтаграммами).
Заметьте, никаких гарантий.

Второе упоминание (про настройку параметров и их загрузку я опустил) мы встречаем в разделе 4.2.1 (Протокол управления передачей TCP - Введение):

Протокол управления передачей - TCP (Transmission Control Protocol) [TCP:1] представляет собой транспортный протокол стека Internet для работы с виртуальными соединениями. TCP обеспечивает гарантированную доставку с сохранением порядка для полнодуплексных потоков данных (октеты или байты).Протокол TCP используется теми приложениями, которым нужен ориентированный на соединения транспортный сервис с гарантией доставки (например, электронная почта SMTP, передача файлов по протоколу FTP, служба виртуальных терминалов Telnet); требования к таким протоколам прикладного уровня описаны в работе [INTRO:1].

Английский текст:

The Transmission Control Protocol TCP [TCP:1] is the primary virtual-circuit transport protocol for the Internet suite. TCP provides reliable, in-sequence delivery of a full-duplex stream of octets (8-bit bytes). TCP is used by those applications needing reliable, connection-oriented transport service, e.g., mail (SMTP), file transfer (FTP), and virtual terminal service (Telnet); requirements for these application-layer protocols are described in [INTRO:1].

Который можно было бы перевести как (опять спасибо John-1123 и Drop-bear):

Transmission Control Protocol TCP [TCP: 1] является основным виртуальным протоколом транспортной схемы для сети Интернет. TCP обеспечивает надежную, последовательную полнодуплексную доставку потока октетов (8-битный байт). TCP используется приложениями, нуждающимися в надежных способах доставки, ориентированных на соединения между клиентами, например, электронной почтой (SMTP), при передаче файлов (FTP), службы виртуального терминала (Telnet); требования к этим протоколам прикладного уровня описаны в [INTRO:1].
Снова никаких гарантий.

Можно предположить зачем же переводчик добавил эти мнимые гарантии. Возможно, он хотел подчеркнуть отличие TCP от UDP (а как следствие и от IP), а может решил обобщить слова "надежность", "контроль" и другие хорошие (и надежные) слова  в хорошее (и надежное) слово "гарантии".

"И что из этого?" - спросите вы.

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

А из этого следует:

Этап третий: практический.

Если предыдущий этап не убедил вас в том, что TCP все-таки не гарантирует доставки, то давайте проведем эксперимент:
Откройте любое приложение использующее TCP и начните обмен данными (скачивание музыки, получение почты подойдет). TCP гарантирует доставку? Похоже, что да? А теперь вытащите кабель подключения к сети, выключите модем и отключите WiFi (или что у вас там?) Ну, как? Гарантии TCP все еще в силе? =)

Вот в этом-то и проблема. На самом деле при отправке данных нет никаких гарантий, что они будут доставлены и поэтому хороший программист обязательно предусматривает вариант, когда данные НЕ будут доставлены.

Т.е. просто написать TCPSocket.Send(*data); и ожидать, что все будет хорошо, строить дальнейший код исходя из посылки о том, что есть "гарантия доставки" в корне не верно.

Представляете, если бы для осуществления ремонта линии электропередач вы бы послали команду "отключить подачу ста тысяч вольт" по TCP и думая о гарантированной доставке сразу полезли бы на столб? Есть среди оставшихся хоть один, кто бы рискнул?

Друзья, читайте RFC в оригинале. Это действительно хороший совет.
(Да, перестаньте плеваться те, кто УЖЕ читают RFC в оригинале, я и сам знаю, что оно сложно переваривается и не менее сложно усваивается. Тем не менее это RFC)

Эпилог: правильные гарантии.

Что же на самом деле гарантирует протокол TCP? Об этом очень хорошо сказано в статье википедии о TCP/IP:
TCP — «гарантированный» транспортный механизм с предварительным установлением соединения, предоставляющий приложению надёжный поток данных, дающий уверенность в безошибочности получаемых данных, перезапрашивающий данные в случае потери и устраняющий дублирование данных. TCP позволяет регулировать нагрузку на сеть, а также уменьшать время ожидания данных при передаче на большие расстояния. Более того, TCP гарантирует, что полученные данные были отправлены точно в такой же последовательности. В этом его главное отличие от UDP.
Слово "гарантированный" (вначале) забрано  в кавычки и все остальное определение на редкость точно и лаконично.

И особенно вкусен конец абзаца, не удержусь и повторю его еще раз:

Более того, TCP гарантирует, что полученные данные были отправлены точно в такой же последовательности. В этом его главное отличие от UDP.

Вот это - правильные гарантии.


Спасибо.

Спасибо всем, кто дочитал до конца. Возможно для опытных программистов моя заметка не была слишком уж полезна, поскольку так или иначе с практикой становится интуитивно понятно, что "любое чертово сетевое соединение нужно так или иначе непрерывно контролировать", а новичкам все это покажется бесполезным философствованием. Но я надеюсь, что все мы будем делать действительно хороший код и с каждым днем все лучше. Возможно не без помощи этого поста.

Всем счастливо, а умному студенту привет и удачно делать свои снежинки.

12 комментариев:

Анонимный комментирует...

Этак ты всю науку к хуям сведешь.

Исходя из этого слово "гарантированный" надо ваще вычеркнуть из лексикона. Ибо никто ничего никогда гарантировать не может. Гарантирую. Ибо 2012 и песец.

Green FiLin комментирует...

Да, ладно, вычеркнуть! Просто одна неудачная формулировка поражает в мозг множество людей.

Анонимный комментирует...

Хм. А чего ж ты не докопался до фразы "reliable ... connection". Какое же оно нафиг reliable, когда роутер упал и песец. Нет нифига надежности.

Green FiLin комментирует...

Во-первых от того, что соответствующей истории не было на ithappens. =)
А во-вторых, скажи, ты не согласен с тем, что в этом вопросе акценты надо переставить на "правильные гарантии" или тебе просто не нравится, что я к RFC докапываюсь? =)

Unknown комментирует...

Не, в этой истории надо правильно выделить и заострить внимание на такой категории как "форс-мажор". До возникновения форс-мажора РФЦ, как собсно и любой договор, действует и гарантирует. А вот при возникновении...

А ты все это покидал в одну кучку

Green FiLin комментирует...

Ну, в принципе, я согласен с тем, что форс-мажор это важно и его следует выделить, однако аналогичные (роутер отключили, кабель порвался) форс-мажоры действуют и для протокола IP, но никто не пытается утверждать, что протокол IP гарантирует доставку пакета. А ведь обычно (например при обучении) акцентируют внимание именно на этом "различии в гарантиях" между протоколами. Что не верно, как я уже написал выше.

Unknown комментирует...

Блин, перечитал еще раз и кажется понял, до чего именно ты докапываешься. До тонкости между "гарантия доставки" и "гарантированная доставка".

Green FiLin комментирует...

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

Unknown комментирует...

О! наконец добрались до глубинного общефилософского камня - что есть исключительная ситуация. Где он, уровень исключительности? Когда можно вернуть флаг, а когда надо уже поднимать эксепшн?

Green FiLin комментирует...

Ну, куда тебя опять понесло-то? =)
Причем тут "глубинные проблемы"? Все ж ясно.

AKrapov комментирует...

Всё это буквоедство.

Если мы говорим о "последовательности доставки", это не просто сортировка 0,1,2,3,4...
Это именно доставка всех членов, где существует чёткое последование членов.

Поэтому механизм подтверждения доставки существует.

"Протокол TCP требует, чтобы все отправленные данные были подтверждены принявшей их стороной. Он использует таймауты и повторные передачи для обеспечения надежной доставки. Отправителю разрешается передавать некоторое количество данных, не дожидаясь подтверждения приема ранее отправленных данных. Таким образом, между отправленными и подтвержденными данными существует окно уже отправленных, но еще неподтвержденных данных. Количество байт, которые можно передавать без подтверждения, называется размером окна. Как правило, размер окна устанавливается в стартовых файлах сетевого программного обеспечения. Так как TCP-канал является дуплексным, то подтверждения для данных, идущих в одном направлении, могут передаваться вместе с данными, идущими в противоположном направлении. Приемники на обеих сторонах виртуального канала выполняют управление потоком передаваемых данных для того, чтобы не допускать переполнения буферов. "


И ещё:
"
TCP Receive Window
Протокол TCP работает с установкой соединения, что обязывает его отправлять уведомления об успешно принятых сегментах. Неподтвержденные сегменты спустя некоторое время передаются узлом вновь.

Промежуток времени между отправкой пакета и его получением называется задержкой (latency), и эта латентность в зависимости от типа и загруженности сети варьируется от 20 мс (и менее) до 100 мс (и более).

Cоздатели TCP/IP и разрешили узлу отправлять более одного сегмента, не дожидаясь подтверждения. Максимальное количество сегментов, которое можно передать до прихода подтверждения, и называется размером TCP-окна
"

Green FiLin комментирует...

Ага! Спасибо за хорошие замечания.

А откуда цитаты, если не секрет?

P.S.: Буквоедство? Да, почему бы и нет. ;-)

Отправить комментарий

Примечание. Отправлять комментарии могут только участники этого блога.