TCP-IP крупным планом

Как самому собрать кубик Рубик.          

Вывод программы tcpdump для примера использования backlog.



Рисунок 18.24 Вывод программы tcpdump для примера использования backlog.

Мы попытались стартовать третьего клиента в сегменте 7 (порт 1092) и четвертого в сегменте 8 (порт 1093). TCP игнорировало оба SYN, так как очередь для этой слушающей конечной точки заполнена. Оба клиента повторно передали свои SYN в сегментах 9, 10, 11, 12 и 15. Третья повторная передача четвертого клиента принята (сегменты 12-14), потому что 30-секундная пауза сервера закончилась, и сервер удалил два соединения, которые были приняты, очистив очередь. (Причина, по которой это произошло, заключается в том, что это соединение было принято сервером в момент времени 28.19, а не в момент времени, который больше чем 30; это произошло потому, что потребовалось несколько секунд, чтобы стартовать первого клиента [сегмент 1, время старта в выводе] после старта сервера.) Четвертая повторная передача третьего клиента также принята (сегменты 15-17). Соединение четвертого клиента (порт 1093) принято сервером перед соединением третьего клиента (порт 1092) из-за совпадения времени между окончанием 30-секундной паузы и повторной передачей клиента.

Мы могли ожидать, что очередь принятых соединений будет обработана приложением в соответствии с принципом FIFO (первый вошел, первый вышел). Таким образом, после того как TCP принял приложение на порты 1090 и 1091, мы ожидали, что приложение получит соединение сначала на порт 1090, а затем соединение на порт 1091. Однако, в большинстве реализаций Berkeley существует ошибка (bug), в результате чего используется порядок LIFO (последний вошел, первый вышел). Производители много раз пытались исправить эту ошибку, однако она до сих пор существует в таких системах как SunOS 4.1.3.

TCP игнорирует входящее SYN, когда очередь заполнена, и не отвечает с использованием RST, из-за ошибки. Обычно очередь заполнена, потому что приложение или операционная система заняты, поэтому приложение не может обработать входящие соединения. Подобное состояние может измениться за короткий промежуток времени. Однако, если TCP сервер ответил сбросом (reset), активное открытие клиента будет прервано (как раз это произойдет, если сервер не был стартован). Так как SYN игнорирован, TCP клиент будет вынужден повторно передать SYN позже, в надежде на то, что в очереди появится место для нового соединения.

В этом месте необходимо обсудить еще одну очень важную деталь, которая присутствует практически во всех реализациях TCP/IP. Она заключается в том, что TCP принимает входящий запрос на соединение (SYN) в том случае, если в очереди есть место. При этом приложение не может посмотреть, от кого пришел запрос (IP адрес источника и номер порта источника). Это не требуется TCP, это всего лишь общая техника, используемая в реализациях. Если API, такой как TLI (раздел "Интерфейсы прикладного программирования" главы 1), уведомляет приложение о прибытии запроса на соединение и позволяет приложению выбрать, принять это соединение или нет, то при использовании TCP получается так, что когда приложению сообщается, что соединение только что прибыло, в действительности TCP уже завершил "трехразовое рукопожатие"! В других транспортных уровнях существует возможность разграничить прибывшее и принятое соединения (OSI транспортный уровень), однако TCP такой возможности не предоставляет.

Solaris 2.2 предоставляет опцию, которая не позволяет TCP принимать входящий запрос на соединение до тех пор, пока ему это не разрешит приложение (tcp_eager_listeners в разделе "Solaris 2.2" приложения E).

Это поведение также означает, что TCP сервер не может сделать так что активное открытие клиента будет прервано. Когда соединение от нового клиента попадает к приложению сервера, "трехстороннее рукопожатие" TCP уже закончено и активное открытие клиента завершено успешно. Если сервер затем смотрит на IP адрес клиента и номер порта и решает, что он не хочет обслуживать этого клиента, все сервера могут просто закрыть соединение (при этом будет послан FIN) или сбросить соединение (будет послан RST). В любом случае клиент будет считать, что с сервером все нормально, так как завершилось активное открытие, и, вполне возможно, уже послал серверу какой-либо запрос.



Содержание раздела