Рис. 6.3 Поля номеров портов отправителя и получателя в сегменте транспортного уровня

Номер порта представляет собой 16-разрядное число, принимающее значения от 0 до 65 535.Номера в диапазоне от 0 до 1023 предназначены для использования в популярных протоколах прикладного уровня (таких, как HTTP и FTP, имеющих порты с номерами 80 и 21 соответственно). Список зарезервированных номеров портов приведен в документе RFC 1700, а его регулярно обновляемая версия находится в Интернете по адресу http://www. iana. org (RFC 3232). При разработке новых приложений (примеры которых приведены в разделах «Программирование ТСР-сокетов», «Программирование UDP-сокетов» и «Разработка простого web-сервера» главы 2) необходимо присваивать им собственные номера портов.

Теперь становится ясен один из вариантов организации службы демультиплексирования: каждому сокету сопоставляется номер порта, а сегмент направляется тому сокету, чей номер совпадает со значением, содержащимся в поле номера порта получателя. Затем данные сегмента передаются через сокет соответствующему процессу. Как мы увидим, подобная схема характерна для протокола UDP; процесс мультиплексирования/демультиплексирования в протоколе TCP несколько сложнее.

Мультиплексирование и демультиплексирование без установления логического соединения

Вспомним о том, что в программе на языке Java, выполняющейся на оконечной системе, создание UDP-сокета производится командой

DatagramSocket mySocket = new DatagramSocket();

При выполнении этой команды транспортный уровень автоматически связывает номер порта с создаваемым сокетом. Номером порта является любое число от 1024 до 65 535, не используемое в текущий момент другим UDP-портом. Номер порта может быть задан явно:

НЕ нашли? Не то? Что вы ищете?

DatagramSocket mySocket = new DatagramSocket(19157);

В этом случае UDP-сокету будет сопоставлен номер порта 19 157. Явное указание номера порта необходимо в случаях, когда разработчик создает приложение, поддерживаемое каким-либо популярным протоколом, занимающим один из «хорошо известных» номеров порта. Обычно на клиентской стороне приложения транспортный уровень связывает сокет с номером порта автоматически, в то время как на серверной стороне требуется явное указание последнего.

После того как номера портов UDP-сокетов определены, мы можем точно описать процедуру мультиплексирования и демультиплексирования протокола UDP. Предположим, что процесс с номером сокета 19 157, выполняющийся на хосте А, пытается передать массив данных процессу с номером сокета 46 428, выполняющемуся на хосте В. Транспортный уровень хоста А создает сегмент, включающий данные процесса, номер порта отправи, номер порта получа, а также две другие величины, которые сейчас не представляют для нас интереса и будут рассмотрены позже. Сформированный сегмент передается сетевому уровню, который создает IP-дейтаграмму и «по-возможности» доставляет ее хосту В. В случае успешного получения сегмента хостом-получателем последний анализирует значение поля номера порта получателя и направляет сегмент сокету с номером 46 428. Обратите внимание, что на хосте В могут одновременно выполняться несколько процессов, каждый из которых обладает сокетом с уникальным номером порта. Каждый получаемый сегмент анализируется и направляется тому сокету, номер порта которого совпадает со значением поля номера порта получателя сегмента.

Отметим, что любой UDP-сокет однозначно идентифицируется совокупностью IP-адреса хоста назначения и номера порта. Таким образом, если два UDP-сегмен-та имеют разные IP-адреса и/или номера портов отправителя, но одинаковые IP-адреса и номера портов получателя, оба сегмента будут переданы одному и тому же процессу.

Не удивительно, если у вас сразу возник вопрос: для чего нужен номер порта отправителя? Как показано на рис. 3.4, номер порта отправителя используется как часть «обратного адреса». Если у получателя возникнет необходимость в отправке ответа, он скопирует значение поля номера порта отправителя полученного сегмента в поле номера порта получателя ответного сегмента (мы назвали номер порта частью «обратного адреса» потому, что полный адрес также включает IP-адрес отправителя). В качестве примера обратимся к серверной программе UDPServer. java, созданной в разделе «Разработка простого web-сервера». В ней используется специальный метод для извлечения номера порта отправителя из принятого сегмента; извлеченный номер порта служит в качестве номера порта получателя для создаваемого ответного сегмента.

Рис. 6.4 При передаче в обратном направлении номера портов отправителя и получателя меняются местами

Мультиплексирование и демультиплексирование с установлением логического соединения

Для того чтобы понять суть демультиплексирования в протоколе TCP, необходимо сначала подробнее рассмотреть ТСР-сокеты и процесс установления ТСР-соедине-ния. Отличие ТСР-сокета от UDP-сокета заключается в том, что ТСР-сокет идентифицируется при помощи не двух, а четырех составляющих: IP-адреса отправителя, номера порта отправителя, IP-адреса получателя и номера порта получателя. Все четыре компонента используются хостом-получателем в процессе демультиплексирования (направления в нужный сокет) получаемых сегментов. В отличие от протокола TCP, сегменты с разными IP-адресами или номерами порта отправителя будут переданы разным сокетам даже при совпадении IP-адресов и номеров портов получателя. Обратимся к программам, приведенным в разделе «Программирование ТСР-сокетов» главы 2. Эти программы обладают следующими особенностями.

□ Программа-сервер использует «впускающий» сокет с номером порта 6789, принимающий запросы от клиентов на установление ТСР-соединения.

□ Программа-клиент генерирует запрос на установление соединения командой

Socket clientSocket = new SocketC’serverHostName”, 6789);

□ Запрос на установление логического соединения представляет собой не что иное, как TCP-сегмент с номером порта 6789 и специальным битовым набором в заголовке (более подробное описание будет приведено в разделе «Протокол TCP — передача с установлением соединения» этой главы). Кроме того, сегмент также включает номер порта отправителя, определяемый программой-клиентом. Команда, приведенная выше, создает ТСР-сокет клиентского процесса, через который клиент осуществляет обмен информацией с сервером.

□ Получив запрос на установление соединения, серверный процесс создает сокет соединения командой

Socket connectionSocket = welcomeSocket. accept();

□ При обработке сегмента с запросом на установление логического соединения сервер использует четыре параметра: номер порта отправителя, IP-адрес отправителя, номер порта получателя и собственный IP-адрес. Создаваемый сокет соединения идентифицируется совокупностью этих четырех параметров. Все сегменты, содержащие в соответствующих полях значения, совпадающие с параметрами сокета соединения, направляются (демультиплексируются) в этот сокет. После того как TCP-соединение установлено, клиент и сервер могут начинать обмен данными.

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

Рисунок 6.5 иллюстрирует ситуацию открытия трех HTTP-сеансов с сервером В: двух сеансов клиентом С и одного клиентом А. Все три хоста, А, В и, С, имеют уникальные IP-адреса. Для двух HTTP-соединений хост С использует номера портов 26 145 и 7532. Поскольку хост А выбирает номера портов независимо от хоста С, возможна ситуация, когда для своего HTTP-соединения с сервером В хост А также использует порт с номером 26 145. Тем не менее процесс демультиплексирования будет выполняться сервером корректно, поскольку IP-адреса отправителей сегментов для хостов А и С различны.

Рис. 6.5 Два клиента используют порт с номером 80 для взаимодействия с web-сервером

Web-серверы и TCP

Перед тем как завершить разговор о мультиплексировании и демультиплексировании, необходимо сказать несколько слов о web-серверах и об использовании ими номеров портов. Предположим, что на хосте выполняется web-сервер (например, Apache) с портом номер 80. Когда клиенты (к примеру, браузеры) формируют сегменты для передачи серверу, во всех сегментах номер порта получателя получает значение 80. Как упоминалось выше, сервер различает подобные сегменты по IP-адресам и номерам портов отправителей.

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

Современные высокопроизводительные web-серверы зачастую используют единственный процесс, создающий потоки выполнения для соединений с клиентами, при этом каждый поток располагает собственным сокетом (поток выполнения можно рассматривать как упрощенный процесс в рамках «нормального» процесса). В первом задании по программированию главы 2 требовалось создать сервер, который функционирует именно таким образом. Подобные серверы позволяют одному процессу задействовать несколько сокетов соединения с разными идентификаторами.

Если клиент и сервер используют протокол HTTP с постоянными ТСР-соединени-ями, то они могут многократно обмениваться сообщениями через один и тот же сокет сервера. В противном случае для каждой пары запрос/ответ устанавливается новое TCP-соединение, которое разрывается по окончании процесса передачи ответа. Такой механизм привносит дополнительную нагрузку на сервер, ухудшая качество обслуживания (несмотря на то, что некоторые операционные системы имеют средства борьбы с этой проблемой).

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76