355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Уильям Ричард Стивенс » UNIX: разработка сетевых приложений » Текст книги (страница 22)
UNIX: разработка сетевых приложений
  • Текст добавлен: 17 сентября 2016, 20:42

Текст книги "UNIX: разработка сетевых приложений"


Автор книги: Уильям Ричард Стивенс


Соавторы: Эндрю М. Рудофф,Билл Феннер

Жанр:

   

ОС и Сети


сообщить о нарушении

Текущая страница: 22 (всего у книги 88 страниц) [доступный отрывок для чтения: 32 страниц]

Параметр сокета SO_TYPE

Этот параметр возвращает тип сокета. Возвращаемое целое число – константа SOCK_STREAMили SOCK_DGRAM. Этот параметр обычно используется процессом, наследующим сокет при запуске.

Параметр сокета SO_USELOOPBACK

Этот параметр применяется только к маршрутизирующим сокетам ( AF_ROUTE). По умолчанию он включен на этих сокетах (единственный из параметров SO_ xxx, по умолчанию включенный). В этом случае сокет получает копию всего, что отправляется на сокет.

ПРИМЕЧАНИЕ

Другой способ отключить получение этих копий – вызвать функцию shutdown со вторым аргументом SHUT_RD.

7.6. Параметры сокетов IPv4

Эти параметры сокетов обрабатываются IPv4 и для них аргумент levelравен IPPROTO_IP. Обсуждение пяти параметров сокетов многоадресной передачи мы отложим до раздела 19.5.

Параметр сокета IP_HRDINCL

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

Когда установлен этот параметр, мы создаем полный заголовок IP со следующими исключениями:

■ IP всегда сам вычисляет и записывает контрольную сумму заголовка IP.

■ Если мы устанавливаем поле идентификации IP в 0, ядро устанавливает это поле самостоятельно.

■ Если IP-адрес отправителя (source address) – INADDR_ANY, IP устанавливает его равным основному IP-адресу исходящего интерфейса.

■ Как устанавливать параметры IP, зависит от реализации. Некоторые реализации добавляют любые параметры IP, установленные с использованием параметра сокета IP_OPTIONS, к создаваемому нами заголовку, в то время как другие требуют, чтобы мы сами добавили в заголовок все необходимые параметры IP.

■ Некоторые поля должны располагаться в порядке байтов узла, тогда как другие – в сетевом порядке байтов. Это тоже зависит от реализации, из-за чего программы, работающие с символьными сокетами с параметром IP_HDRINCL, становятся не такими переносимыми, как хотелось бы.

Пример использования этого параметра показан в разделе 29.7. Дополнительная информация об этом параметре представлена в [128, с. 1056–1057].

Параметр сокета IP_OPTIONS

Установка этого параметра позволяет нам задавать параметры IP в заголовке IPv4. Это требует точного знания формата параметров IP в заголовке IP. Мы рассмотрим этот параметр в контексте маршрутизации от отправителя IPv4 в разделе 27.3.

Параметр сокета IP_RECVDSTADDR

Этот параметр сокета заставляет функцию recvmsgвозвращать IP-адрес получателя в получаемой дейтаграмме UDP в качестве вспомогательных данных. Пример использования этого параметра мы приводим в разделе 22.2.

Параметр сокета IP_RECVIF

Этот параметр сокета заставляет функцию recvmsgвозвращать индекс интерфейса, на котором принимается дейтаграмма UDP, в качестве вспомогательных данных. Пример использования этого параметра мы приводим в разделе 22.2.

Параметр сокета IP_TOS

Этот параметр позволяет нам устанавливать поле тип службы( тип сервиса) (TOS, type-of-service) (рис. А.1) в заголовке IP для сокета TCP или UDP. Если мы вызываем для этого сокета функцию getsockopt, возвращается текущее значение, которое будет помещено в поля DSCP и ECN заголовка IP (по умолчанию значение нулевое). Не существует способа извлечь это значение из полученной дейтаграммы IP.

Приложение может установить DSCP равным одному из значений, о которых существует договоренность с провайдером. Каждому значению соответствует определенный тип обслуживания, например IP-телефонии требуется низкая задержка, а передачи больших объемов данных требуют повышенной пропускной способности. Документ RFC 2474 [82] определяет архитектуру diffserv, которая обеспечивает лишь ограниченную обратную совместимость с историческим определением поля TOS (RFC 1349 [5]). Приложения, устанавливающие параметр IP_TOSравным одной из констант, определенных в файле (например, IPTOS_LOWDELAYили IPTOS_THROUGHPUT), должны вместо этого использовать различные значения DSCP. Архитектура diffserv сохраняет только два значения (6 и 7, что соответствует константам IPTOS_PREC_NETCONTROLи IPTOS_PREC_INTERNETCONTROL), так что только те приложения, которые используют именно эти константы, будут работать в сетях diffserv.

Документ RFC 3168 [100] определяет поле ECN. Приложениям рекомендуется предоставлять установку этого поля ядру и сбрасывать в нуль два младших бита значения, заданного IP_TOS.

Параметр сокета IP_TTL

С помощью этого параметра мы можем устанавливать и получать заданное по умолчанию значение TTL (time-to-live field – поле времени жизни, рис. А.1), которое система будет использовать для данного сокета. (TTL для многоадресной передачи устанавливается при помощи параметра сокета IP_MULTICAST_TTL, который описывается в разделе 21.6.) В системе 4.4BSD, например, значение TTL по умолчанию для сокетов TCP и UDP равно 64 (оно определяется в RFC 1700), а для символьных сокетов – 255. Как и в случае поля TOS, вызов функции getsockoptвозвращает значение поля по умолчанию, которое система будет использовать в исходящих дейтаграммах, и не существует способа определить это значение по полученной дейтаграмме. Мы устанавливаем этот параметр сокета в нашей программе tracerouteв листинге 28.15.

7.7. Параметр сокета ICMPv6

Единственный параметр сокета, обрабатываемый ICMPv6, имеет аргумент level, равный IPPROTO_ICMPV6.

Параметр сокета ICMP6_FILTER

Этот параметр позволяет нам получать и устанавливать структуру icmp6_filter, которая определяет, какие из 256 возможных типов сообщений ICMPv6 передаются для обработки на символьный сокет. Мы обсудим этот параметр в разделе 28.4.

7.8. Параметры сокетов IPv6

Эти параметры сокетов обрабатываются IPv6 и имеют аргумент level, равный IPPROTO_IPV6. Мы отложим обсуждение пяти параметров сокетов многоадресной передачи до раздела 21.6. Отметим, что многие из этих параметров используют вспомогательные данныес функцией recvmsg, и мы покажем это в разделе 14.6. Все параметры сокетов IPv6 определены в RFC 3493 [36] и RFC 3542 [114].

Параметр сокета IPV6_CHECKSUM

Этот параметр сокета задает байтовое смещение поля контрольной суммы внутри данных пользователя. Если значение неотрицательное, ядро, во-первых, вычисляет и хранит контрольную сумму для всех исходящих пакетов и, во-вторых, проверяет полученную контрольную сумму на вводе, игнорируя пакеты с неверной контрольной суммой. Этот параметр влияет на символьные сокеты IPv6, отличные от символьных сокетов ICMPv6. (Ядро всегда вычисляет и хранит контрольную сумму для символьных сокетов ICMPv6.) Если задано значение -1 (значение по умолчанию), ядро не будет вычислять и хранить контрольную сумму для исходящих пакетов на этом символьном сокете и не будет проверять контрольную сумму для получаемых пакетов.

ПРИМЕЧАНИЕ

Все протоколы, использующие IPv6, должны иметь контрольную сумму в своих собственных заголовках. Эти контрольные суммы включают псевдозаголовок (RFC 2460 [27]), куда входит IPv6-адрес отправителя (что отличает IPv6 от всех остальных протоколов, которые обычно реализуются с использованием символьного сокета IPv4). Ядро не заставляет приложение, использующее символьный сокет, выбирать адрес отправителя, но делает это самостоятельно и затем вычисляет и сохраняет контрольную сумму, включающую псевдозаголовок IPv6.

Параметр сокета IPV6_DONTFRAG

Установка этого параметра запрещает автоматическое включение заголовка фрагментации для UDP и символьных сокетов. При этом исходящие пакеты, размер которых превышает MTU исходящего интерфейса, просто сбрасываются. Системный вызов ошибку не возвращает, так как пакет может быть сброшен и на промежуточном маршрутизаторе, если он превысит MTU одной из промежуточных линий. Чтобы получать уведомления об изменении маршрутной MTU, приложению следует включить параметр сокета IPV6_RECVPATHMTU(см. раздел 22.9).

Параметр сокета IPV6_NEXTHOP

Этот параметр задает адрес следующего транзитного узла для дейтаграммы в виде структуры адреса сокета. Подробнее о нем рассказывается в разделе 22.8.

Параметр сокета IPV6_PATHMTU

Этот параметр может быть только получен, но не установлен. При его считывании система возвращает текущее значение маршрутной MTU, определенное соответствующим методом (см. раздел 22.9).

Параметр сокета IPV6_RECVDSTOPTS

Установка этого параметра означает, что любые полученные IPv6-параметры получателя должны быть возвращены в качестве вспомогательных данных функцией recvmsg. По умолчанию параметр отключен. Мы опишем функции, используемые для создания и обработки этих параметров, в разделе 27.5.

Параметр сокета IPV6_RECVHOPLIMIT

Установка этого параметра определяет, что полученное поле предельного количества транзитных узлов (hop limit field) должно быть возвращено в качестве вспомогательных данных функцией recvmsg. По умолчанию параметр отключен. Мы опишем функции, используемые для создания и обработки этого параметра, в разделе 22.8.

ПРИМЕЧАНИЕ

В IPv4 не существует способа определить значение получаемого поля TTL.

Параметр сокета IPV6_RECVHOPOPTS

Установка этого параметра означает, что любые полученные параметры транзитных узлов (hop-by-hop options) IPv6 должны быть возвращены в качестве вспомогательных данных функцией recvmsg. По умолчанию параметр отключен. Мы опишем функции, используемые для создания и обработки этого параметра, в разделе 27.5.

Параметр сокета IPV6_RECVPATHMTU

Установка этого параметра означает, что маршрутная MTU должна быть возвращена в качестве вспомогательных данных функцией recvmsg, при условии, что ее значение изменилось. Параметр будет описан в разделе 22.9.

Параметр сокета IPV6_RECVPKTINFO

Установка этого параметра означает, что два фрагмента информации о полученной дейтаграмме IPv6 – IPv6-адрес получателя и индекс принимающего интерфейса – должны быть возвращены в качестве вспомогательных данных функцией recvmsg. Мы опишем этот параметр в разделе 22.8.

Параметр сокета IPV6_RECVRTHDR

Установка этого параметра означает, что получаемый заголовок маршрутизации IPv6 должен быть возвращен в качестве вспомогательных данных функцией recvmsg. По умолчанию этот параметр отключен. Мы опишем функции, которые используются для создания и обработки заголовка маршрутизации IPv6, в разделе 27.6.

Параметр сокета IPV6_RECVTCLASS

Установка этого параметра означает, что функция recvmsgдолжна вернуть сведения о классе трафика полученного сообщения (то есть содержимое полей DSCP и ECN) в качестве внешних данных. По умолчанию параметр отключен. Подробнее о нем будет рассказано в разделе 22.8.

Параметр сокета IPV6_UNICAST_HOPS

Этот параметр аналогичен параметру сокета IPv4 IP_TTL. Он определяет предельное количество транзитных узлов, заданное по умолчанию для исходящих дейтаграмм, отправляемых через этот сокет. При получении значения этого параметра сокета возвращается предельное количество транзитных узлов, которое ядро будет использовать для сокета. Чтобы определить действительное значение предельного количества транзитных узлов из полученной дейтаграммы IPv6, требуется использовать параметр сокета IPV6_RECVHOPLIMIT. Мы устанавливаем этот параметр сокета в нашей программе tracerouteв листинге 28.15.

Параметр сокета IPV6_USE_MIN_MTU

Установка этого параметра равным 1 указывает на то, что определять маршрутную MTU не следует, а пакеты должны отправляться с минимальным значением MTU для IPv6, что предотвращает их фрагментацию. Если же значение параметра равно 0, определение маршрутной MTU выполняется для всех адресов назначения. Значение -1 (установленное по умолчанию) указывает на необходимость определения маршрутной MTU для направленной передачи, но для многоадресной передачи в этом случае используется минимально возможная MTU. Подробнее об этом параметре рассказывается в разделе 22.9.

Параметр сокета IPV6_V6ONLY

Включение этого параметра для сокета семейства AF_INET6ограничивает его использование исключительно протоколом IPv6. По умолчанию параметр отключен, хотя в некоторых системах существует возможность включить его по умолчанию. Взаимодействие по IPv4 и IPv6 через сокеты AF_INET6будет описано в разделах 12.2 и 12.3.

Параметры сокета IPV6_XXX

Большинство параметров IPv6, предназначенных для изменения содержимого заголовка, предполагают, что приложение использует сокет UDP и взаимодействует с ядром при помощи функций recvmsgи sendmsg. Сокет TCP получает и устанавливает значения параметров при помощи специальных функций getsockoptи setsockopt. Параметр сокета TCP совпадает с типом вспомогательных данных для UDP, а в буфере после вызова функций getsockoptи setsockoptоказывается та же информация, что и во вспомогательных данных. Подробнее см. раздел 27.7.

7.9. Параметры сокетов TCP

Для сокетов TCP предусмотрены два специальных параметра. Для них необходимо указывать levelIPPROTO_TCP.

Параметр сокета TCP_MAXSEG

Этот параметр сокета позволяет нам получать или устанавливать максимальный размер сегмента( maximum segment size, MSS) для соединения TCP. Возвращаемое значение – это количество данных, которые наш TCP будет отправлять на другой конец соединения. Часто это значение равно MSS, анонсируемому другим концом соединения в его сегменте SYN, если наш TCP не выбирает меньшее значение, чем объявленный MSS собеседника. Если это значение получено до того, как сокет присоединился, возвращаемым значением будет значение по умолчанию, которое используется в том случае, когда параметр MSS не получен с другого конца соединения. Также помните о том, что значение меньше возвращаемого действительно может использоваться для соединения, если, например, задействуется параметр отметки времени (timestamp), поскольку в каждом сегменте он занимает 12 байт области, отведенной под параметры TCP.

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

В табл. 7.2 мы отметили, что этот параметр сокета может быть также установлен приложением. Это возможно не во всех системах: изначально параметр был доступен только для чтения. 4.4BSD позволяет приложению только лишь уменьшать это значение, но мы не можем его увеличивать [128, с. 1023]. Поскольку этот параметр управляет количеством данных, которое TCP посылает в каждом сегменте, имеет смысл запретить приложению увеличивать значение. После установления соединения это значение задается величиной MSS, которую объявил собеседник, и мы не можем превысить его. Однако наш TCP всегда может отправить меньше данных, чем было анонсировано собеседником.

Параметр сокета TCP_NODELAY

Если этот параметр установлен, он отключает алгоритм Нагла( Nagle algorithm) (см. раздел 19.4 [111] и с. 858–859 [128]). По умолчанию этот алгоритм включен.

Назначение алгоритма Нагла – сократить число небольших пакетов в глобальной сети. Согласно этому алгоритму, если у данного соединения имеются неподтвержденные (outstanding) данные (то есть данные, которые отправил наш TCP и подтверждения которых он ждет), то небольшие пакеты не будут отправляться через соединение до тех пор, пока существующие данные не будут подтверждены. Под «небольшим» пакетом понимается любой пакет, меньший MSS. TCP будет по возможности всегда отправлять пакеты нормального размера. Таким образом, назначение алгоритма Нагла – не допустить, чтобы у соединения было множество небольших пакетов, ожидающих подтверждения.

Два типичных генератора небольших пакетов – клиенты Rlogin и Telnet, поскольку обычно они посылают каждое нажатие клавиши в отдельном пакете. В быстрой локальной сети мы обычно не замечаем действия алгоритма Нагла с этими клиентами, потому что время, требуемое для подтверждения небольшого пакета, составляет несколько миллисекунд – намного меньше, чем промежуток между вводом двух последовательных символов. Но в глобальной сети, где для подтверждения небольшого пакета может потребоваться секунда, мы можем заметить задержку в отражении символов, и эта задержка часто увеличивается при включении алгоритма Нагла.

Рассмотрим следующий пример. Мы вводим строку из шести символов hello!либо клиенту Rlogin, либо клиенту Telnet, промежуток между вводом символов составляет точно 250 мс. Время обращения к серверу (RTT) составляет 600 мс и сервер немедленно отправляет обратно отражение символа. Мы считаем, что сегмент ACK, подтверждающий получение клиентского символа, отправляется обратно клиенту с отражением символа, а сегменты ACK, которые клиент отправляет для подтверждения приема отраженного сервером символа, мы игнорируем. (Мы поговорим о задержанных сегментах ACK далее.) Считая, что алгоритм Нагла отключен, получаем 12 пакетов, изображенных на рис. 7.7.

Рис. 7.7. Шесть символов, отраженных сервером при отключенном алгоритме Нагла

Каждый символ отправляется в индивидуальном пакете: сегменты данных слева направо, а сегменты ACK справа налево.

Но если алгоритм Нагла включен (по умолчанию), у нас имеется 8 пакетов, показанных на рис. 7.8. Первый символ посылается как пакет, но следующие два символа не отправляются, поскольку у соединения есть небольшой пакет, ожидающий подтверждения. Эти пакеты отправляются, когда прошло 600 мс, то есть когда прибывает сегмент ACK, подтверждающий прием первого пакета, вместе с отражением первого символа. Пока второй пакет не будет подтвержден сегментом ACK в момент времени 1200, не будет отправлен ни один небольшой пакет.

Рис. 7.8. Пакеты, отправляемые при включенном алгоритме Нагла

Алгоритм Нагла часто взаимодействует с другим алгоритмом TCP: алгоритмом задержанного сегмента ACK( delayed ACK). Этот алгоритм заставляет TCP не отправлять сегмент ACK сразу же при получении данных – вместо этого TCP ждет в течение небольшого количества времени (типичное значение 50-200 мс) и только после этого отправляет сегмент ACK. Здесь делается расчет на то, что в течение этого непродолжительного времени появятся данные для отправки собеседнику, и сегмент ACK может быть вложен в пакет с этими данными. Таким образом можно будет сэкономить на одном сегменте TCP. Это обычный случай с клиентами Rlogin и Telnet, поэтому сегмент ACK клиентского символа вкладывается в отражение символа сервером.

Проблема возникает с другими клиентами, серверы которых не генерируют трафика в обратном направлении, в который может быть вложен сегмент ACK. Эти клиенты могут обнаруживать значительные задержки, поскольку TCP клиента не будет посылать никаких данных серверу, пока не истечет время таймера для задержанных сегментов ACK сервера. Таким клиентам нужен способ отключения алгоритма Нагла. Осуществить это позволяет параметр TCP_NODELAY.

Другой тип клиента, для которого нежелательно использование алгоритма Нагла и задержанных ACK TCP, – это клиент, отправляющий одиночный логический запрос своему серверу небольшими порциями. Например, будем считать, что клиент отправляет своему серверу 400-байтовый запрос, состоящий из 4 байт, задающих тип запроса, за которыми следуют 396 байт данных. Если клиент выполняет функцию write, отправляя 4 байт, и затем функцию write, отправляя остальные 396 байт, вторая часть не будет отправлена со стороны клиента, пока TCP сервера не подтвердит получение первых 4 байт. Кроме того, поскольку сервер не может работать с 4 байтами данных, пока не получит оставшиеся 396 байт, TCP сервера задержит сегмент ACK, подтверждающий получение 4 байт данных (то есть не будет данных от сервера клиенту, в которые можно вложить сегмент ACK). Есть три способа решить проблему с таким клиентом.

1. Использовать функцию writev(раздел 14.4) вместо двух вызовов функции write. Один вызов функции writevприводит к отправке только одного сегмента TCP в нашем примере. Это предпочтительное решение.

2. Скопировать 4 байт и 396 байт данных в один буфер и вызвать один раз функцию writeдля этого буфера.

3. Установить параметр сокета TCP_NODELAYи продолжать вызывать функцию writeдважды. Это наименее желательное решение.

Упражнения 7.8 и 7.9 продолжают этот пример.


    Ваша оценка произведения:

Популярные книги за неделю