UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

Рис. 7.4. Использование функции shutdown для проверки того, что собеседник получил наши данные
Сравнивая этот рисунок с рис. 7.1 и 7.2, мы видим, что когда мы закрываем наш конец соединения, то в зависимости от вызванной функции (
closeshutdownSO_LINGER1. Функция
close2. Функция
close3. Функция
shutdownreadДругой способ узнать, что приложение-собеседник прочитало наши данные, — использовать подтверждение на уровне приложения, или ACK приложения. Например, клиент отправляет данные серверу и затем вызывает функцию
readchar ack;Write(sockfd, data, nbytes); /* данные от клиента к серверу */n = Read(sockfd, &ack, 1); /* ожидание подтверждения на уровне приложения */Сервер читает данные от клиента и затем отправляет ему 1-байтовый сегмент — подтверждение на уровне приложения:
nbytes = Read(sockfd, buff, sizeof(buff)); /* данные от клиента *//* сервер проверяет, верное ли количество данных он получил от клиента */Write(sockfd, 1); /* сегмент ACK сервера возвращается клиенту */Таким образом, мы получаем гарантию, что на момент завершения функции read на стороне клиента процесс сервера прочитал данные, которые мы отправили. (При этом предполагается, что либо сервер знает, сколько данных отправляет клиент, либо существует некоторый заданный приложением маркер конца записи, который мы здесь не показываем.) В данном случае сегмент ACK на уровне приложения представляет собой нулевой байт, но вообще содержимое этого сегмента можно использовать для передачи от сервера к клиенту сообщений о других условиях. На рис. 7.5 показан возможный обмен пакетами.

Рис. 7.5. ACK приложения
В табл. 7.4 описаны два возможных вызова функции
shutdowncloseТаблица 7.4. Итоговая таблица сценариев функции shutdown и параметров сокета SO_LINGER
| Функция | Описание |
|---|---|
| shutdown, SHUT_RD | Через сокет больше нельзя принимать данные; процесс может по-прежнему отправлять данные через этот сокет; приемный буфер сокета сбрасывается; все данные, получаемые в дальнейшем, игнорируются протоколом TCP (см. упражнение 6.5); не влияет на буфер отправки сокета |
| shutdown, SHUT_WR | Через сокет больше нельзя отправлять данные; процесс может по-прежнему получать данные через этот сокет; содержимое буфера отправки сокета отсылается на другой конец соединения, затем выполняется обычная последовательность действий по завершению соединения TCP (FIN); не влияет на приемный буфер сокета |
| close, l_onoff = 0 (по умолчанию) | Через сокет больше нельзя отправлять и получать данные; содержимое буфера отправки сокета отсылается на другой конец соединения. Если счетчик ссылок дескриптора становится нулевым, то следом за отправкой данных из буфера отправки сокета выполняется нормальная последовательность завершения соединения TCP (FIN), данные из приемного буфера сокета сбрасываются |
| close, l_onoff = 1 l_linger = 0 | Через сокет больше нельзя отправлять и получать данные. Если счетчик ссылок дескриптора становится нулевым, то на другой конец соединения посылается сегмент RST, соединение переходит в состояние в CLOSED (минуя состояние TIME_WAIT), данные из буфера отправки и приемного буфера сокета сбрасываются |
| close, l_onoff = 1 l_linger = 0 | Через сокет больше нельзя отправлять и получать данные; содержимое буфера отправки сокета отсылается на другой конец соединения. Если счетчик ссылок дескриптора становится нулевым, то следом за отправкой данных из буфера отправки сокета выполняется нормальная последовательность завершения соединения TCP (FIN), данные из приемного буфера сокета сбрасываются, и если время задержки истекает, прежде чем оставшиеся в буфере данные будут посланы и будет подтвержден их прием, функция close возвратит ошибку EWOULDBLOCK |
Параметр сокета SO_OOBINLINE
Когда установлен этот параметр, внеполосные данные помещаются в очередь нормального ввода (то есть вместе с обычными данными (inline)). Когда это происходит, флаг
MSG_OOBПараметры сокета SO_RCVBUF и SO_SNDBUF
У каждого сокета имеется буфер отправки и приемный буфер (буфер приема). Мы изобразили действие буферов отправки TCP, UDP и SCTP на рис. 2.15, 2.16 и 2.17.
Приемные буферы используются в TCP, UDP и SCTP для хранения полученных данных, пока они не будут считаны приложением. В случае TCP доступное пространство в приемном буфере сокета — это окно, размер которого TCP сообщает другому концу соединения. Приемный буфер сокета TCP не может переполниться, поскольку собеседнику не разрешается отправлять данные, размер которых превышает размер окна. Так действует управление передачей TCP, и если собеседник игнорирует объявленное окно и отправляет данные, превышающие его размер, принимающий TCP игнорирует эти данные. Однако в случае UDP дейтаграмма, не подходящая для приемного буфера сокета, игнорируется. Вспомните, что в UDP отсутствует управление потоком: более быстрый отправитель легко переполнит буфер медленного получателя, заставляя UDP получателя игнорировать дейтаграммы, как мы покажем в разделе 8.13. Более того, быстрый отправитель может переполнить даже собственный сетевой интерфейс, так что дейтаграммы будут сбрасываться еще до отправки их с исходного узла.
Указанные в заголовке раздела параметры позволяют нам изменять размеры буферов, заданные по умолчанию. Значения по умолчанию сильно отличаются в зависимости от реализации. Более ранние реализации, происходящие от Беркли, по умолчанию имели размеры буферов отправки и приема 4096 байт, а более новые системы используют буферы больших размеров, от 8192 до 61 440 байт. Размер буфера отправки UDP по умолчанию часто составляет около 9000 байт, а если узел поддерживает NFS, то размер приемного буфера UDP увеличивается до 40 000 байт.
При установке размера приемного буфера сокета TCP важен порядок вызова функций, поскольку в данном случае учитывается параметр масштабирования окна TCP (см. раздел 2.5). При установлении соединения обе стороны обмениваются сегментами SYN, в которых может содержаться этот параметр. Для клиента это означает, что параметр сокета
SO_RCVBUFconnectlistenaccept
