UNIX: разработка сетевых приложений
Шрифт:
Проблема, с которой мы сталкиваемся в процессе сетевого программирования с использованием UDP, заключается в его недостаточной надежности. Если мы хотим быть уверены в том, что дейтаграмма дошла до места назначения, мы должны встроить в наше приложение множество функций: подтверждение приема, тайм-ауты, повторные передачи и т.п.
Каждая дейтаграмма UDP имеет конкретную длину, и мы можем рассматривать дейтаграмму как запись( record). Если дейтаграмма корректно доходит до места назначения (то есть пакет приходит без ошибки контрольной суммы), длина дейтаграммы передается принимающему приложению. Мы уже отмечали, что TCP является потоковым( byte-stream)
Мы также отметили, что UDP предоставляет сервис, не ориентированный на установление соединения( connectionless), поскольку нет необходимости в установлении долгосрочной связи между клиентом и сервером UDP. Например, клиент UDP может создать сокет и послать дейтаграмму данному серверу, а затем срезу же послать через тот же сокет дейтаграмму другому серверу. Аналогично, сервер UDP может получить пять дейтаграмм подряд через один и тот же сокет UDP от пяти различных клиентов.
2.4. TCP: протокол контроля передачи
Сервис, предоставляемый приложению протоколом TCP, отличается от сервиса, предоставляемого протоколом UDP. TCP описывается в документах RFC 793 [96], RFC 1323 [53], RFC 2581 [4], RFC 2988 [91] и RFC 3390 [2]. Прежде всего, TCP обеспечивает установление соединений( connections) между клиентами и серверами. Клиент TCP устанавливает соединение с выбранным сервером, обменивается с ним данными по этому соединению и затем разрывает соединение.
TCP также обеспечивает надежность( reliability). Когда TCP отправляет данные на другой конец соединения, он требует, чтобы ему было выслано подтверждение получения. Если подтверждение не приходит, TCP автоматически передает данные повторно и ждет в течение большего количества времени. После некоторого числа повторных передач TCP оставляет эти попытки. В среднем суммарное время попыток отправки данных занимает от 4 до 10 минут (в зависимости от реализации).
TCP не гарантирует получение данных адресатом, поскольку это в принципе невозможно. Если доставка оказывается невозможной, TCP уведомляет об этом пользователя, прекращая повторную передачу и разрывая соединение. Следовательно, TCP нельзя считать протоколом, надежным на 100%: он обеспечивает надежную доставку данных или надежное уведомление о неудаче.
TCP содержит алгоритмы, позволяющие динамически прогнозировать время (период) обращения( round-trip time, RTT) между клиентом и сервером, и таким образом определять, сколько времени необходимо для получения подтверждения. Например, RTT в локальной сети может иметь значение порядка миллисекунд, в то время как для глобальной сети (WAN) эта величина может достигать нескольких секунд. Более того, TCP постоянно пересчитывает величину RTT, поскольку она зависит от сетевого трафика.
TCP также упорядочивает( sequences) данные, связывая некоторый порядковый номер с каждым отправляемым им байтом. Предположим, например, что приложение записывает 2048 байт в сокет TCP, что приводит к отправке двух сегментов TCP. Первый из них содержит данные с порядковыми номерами 1-1024, второй — с номерами 1025-2048. ( Сегмент( segment) — это блок данных, передаваемых протоколом TCP протоколу IP.) Если какой-либо сегмент приходит вне очереди (то есть если нарушается последовательность сегментов), принимающий TCP заново упорядочит сегменты, основываясь на их порядковых номерах, перед тем как отправить данные принимающему приложению. Если TCP получает дублированные данные (допустим, компьютер на другом конце ошибочно решил, что сегмент был потерян, и передал его заново, когда на самом деле он потерян не был, просто сеть была перегружена), он может определить, что данные были дублированы (исходя из порядковых номеров), и дублированные данные будут проигнорированы.
Протокол UDP не обеспечивает надежности. UDP сам по себе не имеет ничего похожего на описанные подтверждения передачи, порядковые номера, определение RTT, тайм-ауты или повторные передачи. Если дейтаграмма UDP дублируется в сети, на принимающий узел могут быть доставлены два экземпляра. Также, если клиент UDP отправляет две дейтаграммы в одно и то же место назначения, их порядок может быть изменен сетью, и они будут доставлены с нарушением исходного порядка. Приложения UDP должны самостоятельно обрабатывать все подобные случаи, как это показано в разделе 22.5.
TCP обеспечивает управление потоком( flow control). TCP всегда сообщает своему собеседнику, сколько именно байтов он хочет получить от него. Это называется объявлением окна( window). В любой момент времени окно соответствует свободному пространству в буфере получателя. Управление потоком гарантирует, что отправитель не переполнит этот буфер. Окно изменяется динамически с течением времени: по мере того как приходят данные от отправителя, размер окна уменьшается, но по мере считывания принимающим приложением данных из буфера окно увеличивается. Возможно, что окно станет нулевым: если принимающий буфер TCP для данного сокета заполнен, отправитель должен подождать, когда приложение считает данные из буфера.
UDP не обеспечивает управления потоком. Быстрый отправитель UDP может передавать дейтаграммы с такой скоростью, с которой не может работать получатель UDP, как это показано в разделе 8.13.
Наконец, соединение TCP также является двусторонним( full-duplex). Это значит, что приложение может отправлять и принимать данные в обоих направлениях на заданном соединении в любой момент времени. Иначе говоря, TCP должен отслеживать состояние таких характеристик, как порядковые номера и размеры окна, для каждого направления потока данных: отправки и приема. После установления двустороннее соединение может быть преобразовано в одностороннее (см. раздел 6.6).
UDP может быть (а может и не быть) двусторонним.
2.5. SCRIPT: протокол управления передачей потоков
Сервисы, предоставляемые SCRIPT, имеют много общего с сервисами TCP и UDP. Протокол SCRIPT описывается в RFC 2960 [118] и RFC 3309 [119]. Введение в SCRIPT приводится в RFC 3286 [85]. SCRIPT ориентирован на создание ассоциаций между клиентами и серверами. Кроме того, SCRIPT предоставляет приложениям надежность, упорядочение данных, управление передачей и двустороннюю связь, подобно TCP. Слово «ассоциация» используется вместо слова «соединение» намеренно, потому что соединение всегда устанавливалось между двумя IP-адресами. Ассоциация означает взаимодействие двух систем, которые могут иметь по несколько адресов (это называется multihoming — множественная адресация).