Литмир - Электронная Библиотека
Содержание  
A
A

Два значения, идентифицирующих конечную точку, — IP-адрес и номер порта — часто называют сокетом.

Мы можем распространить понятие пары сокетов на UDP, даже учитывая то, что этот протокол не ориентирован на установление соединения. Когда мы будем говорить о функциях сокетов (

bind
,
connect
,
getpeername
и т.д.), мы увидим, какими функциями задаются конкретные элементы пары сокетов. Например, функция bind позволяет приложению задавать локальный IP-адрес и локальный порт для сокетов TCP, UDP и SCRIPT.

2.10. Номера портов TCP и параллельные серверы

Представим себе параллельный сервер, основной цикл которого порождает дочерний процесс для обработки каждого нового соединения. Что случится, если дочерний процесс будет продолжать использовать заранее известный номер порта при обслуживании длительного запроса? Давайте проанализируем типичную последовательность. Пусть сервер запускается на узле freebsd, поддерживающем множественную адресацию (IP-адреса 12.106.32.254 и 192.168.42.1), и выполняет пассивное открытие, используя свой заранее известный номер порта (в данном примере 21). Теперь он ожидает запрос клиента. Эта ситуация изображена на рис. 2.11.

UNIX: разработка сетевых приложений - img_18.png

Рис. 2.11. Сервер TCP с пассивным открытием на порте 21

Мы используем обозначение (

*:21,*:*
) для указания пары сокетов сервера. Сервер ожидает запроса соединения на любом локальном интерфейсе (первая звездочка) на порт 21. Удаленный IP-адрес и удаленный порт не определены, поэтому мы обозначаем их как
*.*
. Такая структура называется прослушиваемым сокетом (listening socket).

ПРИМЕЧАНИЕ

Мы отделяем IP-адрес от номера порта символом «:», потому что это обозначение используется в HTTP и часто встречается в других местах. Программа netstat отделяет номер порта от IP-адреса точкой, но иногда это приводит к затруднениям, потому что точки используются как в доменных именах (freebsd.unpbook.com.21), так и в записи IPv4 (12.106.32.254.21).

Когда мы обозначаем звездочкой локальный IP-адрес, такое обозначение называется универсальным адресом, а звездочка — символом подстановки (wildcard). Если узел, на котором запущен сервер, поддерживает множественную адресацию (как в нашем примере), сервер может указать, что он хочет принимать входящие соединения, которые приходят только для одного определенного локального интерфейса. Сервер должен выбрать либо один определенный интерфейс, либо принимать запросы от всех интерфейсов, то есть сервер не может задать список, состоящий из нескольких адресов. Локальный адрес, заданный с помощью символа подстановки, соответствует выбору произвольного адреса из определенного множества. В листинге 1.5 перед вызовом функции bind произвольный IP-адрес в структуре адреса сокета задан с помощью константы

INADDR_ANY
.

Через некоторое время на узле с IP-адресом 206.168.112.219 запускается клиент и выполняет активное открытие соединения с IP-адресом сервера 12.106.32.254. В этом примере мы считаем, что динамически назначаемый порт, выбранный клиентом TCP, — это порт 1500, что отражено на рис. 2.12. Под клиентом мы показываем его пару сокетов.

UNIX: разработка сетевых приложений - img_19.png

Рис. 2.12. Запрос на соединение от клиента к серверу

Когда сервер получает и принимает соединение клиента, он с помощью функции

fork
создает свою копию, давая возможность дочернему процессу обработать запрос клиента, как показано на рис. 2.13 (функцию
fork
мы описываем в разделе 4.7).

UNIX: разработка сетевых приложений - img_20.png

Рис. 2.13. Параллельный сервер, дочерний процесс которого обрабатывает запрос клиента

На этом этапе мы должны провести различие между прослушиваемым сокетом и присоединенным сокетом на сервере. Заметьте, что присоединенный сокет использует тот же локальный порт (21), что и прослушиваемый сокет. Также заметьте, что на многоадресном сервере локальный адрес заполняется для присоединенного сокета (206.62.226.35), как только устанавливается соединение.

При выполнении следующего шага предполагается, что другой клиентский процесс на клиентском узле запрашивает соединение с тем же сервером. Код TCP клиента задает новому сокету клиента неиспользованный номер динамически назначаемого порта, скажем 1501. Мы получаем сценарий, представленный на рис. 2.14. На сервере различаются два соединения: пара сокетов для первого соединения отличается от пары сокетов для второго соединения, поскольку TCP клиента выбирает неиспользованный порт (1501) для второго соединения.

UNIX: разработка сетевых приложений - img_21.png

Рис. 2.14. Второе соединение клиента с тем же сервером

Из этого примера видно, что TCP не может демультиплексировать входящие сегменты, просматривая только номера портов назначения. TCP должен обращать внимание на все четыре элемента в паре сокетов, чтобы определить, какая конечная точка получает приходящий сегмент. На рис. 2.14 представлены три сокета с одним и тем же локальным портом (21). Если сегмент приходит с IP- адреса 206.168.112.219, порт 1500 и предназначен для IP-адреса 12.106.32.254, порт 21, он доставляется первому дочернему процессу. Если сегмент приходит с IP- адреса 206.168.112.219, порт 1501 и предназначен для IP-адреса 12.106.32.254, порт 21, он доставляется второму дочернему процессу. Все другие сегменты TCP, предназначенные для порта 21, доставляются исходному серверу с прослушиваемым сокетом.

2.11. Размеры буфера и ограничения

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

■ Максимальный размер дейтаграммы IPv4 — 65 535 байт, включая заголовок IPv4. Это связано с тем, что размер дейтаграммы ограничен 16-разрядным полем общей длины (см. рис. А.1).

■ Максимальный размер дейтаграммы IPv6 — 65 575 байт, включая 40-байтовый заголовок IPv6. Это ограничение связано с 16-разрядным полем длины полезных данных на рис. А.2. Заметьте, что поле длины IPv6 не включает размер заголовка IPv6, в то время как в случае IPv4 длина заголовка включается.

IPv6 поддерживает возможность передачи полезных данных увеличенного объема (jumbo payload), при этом поле длины полезных данных расширяется до 32 бит, но эта функция поддерживается только на тех канальных уровнях, на которых максимальная единица передачи (MTU) превышает 65 535. Это свойство разработано для соединений между двумя узлами, таких как HIPPI (High-Performance Parallel Interface — высокоскоростной параллельный интерфейс), у которых часто нет собственных ограничений на MTU.

■ Во многих сетях определена MTU (maximum transmission unit — максимальная единица передачи), величина которой диктуется возможностями оборудования. Например, размер MTU для Ethernet равен 1500 байт. Другие канальные уровни, такие как соединения «точка-точка» с использованием протокола PPP, имеют конфигурируемую MTU. Более ранние соединения по протоколу SLIP (Serial Line Internet Protocol — межсетевой протокол для последовательного канала) часто использовали MTU, равную 296 или 1006 байт.

Минимальная величина канальной MTU (link MTU) для IPv4 — 68 байт. Это сумма размера заголовка IPv4 максимальной длины (20 байт фиксированных полей и 30 байт параметров) и фрагмента минимального размера (сдвиг фрагмента должен быть кратен 8 байтам). Минимальная величина MTU для IPv6 — 1280 байт. IPv6 может работать и в сетях с меньшей MTU, но при условии фрагментации и последующей сборки на канальном уровне, чтобы извне сеть казалась имеющей большую MTU (RFC 2460 [27]).

21
{"b":"225366","o":1}