сообщает, что сокет готов к записи, причем буфер отправки сокета вмещает 8192 байта, а мы вызываем для этого блокируемого сокета функцию
write
с буфером размером 8193 байта, то функция
write
может заблокироваться, ожидая места для последнего байта. Операции считывания на блокируемом сокете будут возвращать сообщение о неполном считывании, если доступны какие-либо данные, но операции записи на блокируемом сокете заблокированы до принятия всех данных ядром. Поэтому, чтобы избежать блокирования при использовании функции
select
для проверки на возможность записи, следует переводить
сокет в неблокируемый режим.
6.3. Если оба дескриптора готовы для чтения, выполняется только первый тест — тест сокета. Но это не нарушает работоспособность клиента, а только лишь уменьшает его эффективность. Поэтому если при завершении функции
select
оба дескриптора готовы для чтения, первое условие
if
оказывается истинным, в результате чего сначала вызывается функция
readline
для считывания из сокета, а затем функция
fputs
для записи в стандартный поток вывода. Следующее условие
if
пропускается (поскольку мы добавили
else
), но функция
select
вызывается снова, сразу находит стандартное устройство ввода, готовое к чтению, и завершается. Суть в том, что условие готовности стандартного потока ввода для чтения сбрасывается считыванием из сокета, а не возвратом функции
select
.
6.4. Воспользуйтесь функцией
getrlimit
для получения значений константы
RLIMIT_NOFILE
, а затем вызовите функцию
setrlimit
для установки текущего гибкого предела (
rlim_cur
) равным жесткому пределу (
rlim_max
). Например, в Solaris 2.5 гибкий предел равен 64, но любой процесс может увеличить это значение до используемого по умолчанию значения жесткого предела (1024).
6.5. Серверное приложение непрерывно посылает данные клиенту, клиент TCP подтверждает их прием и сбрасывает.
6.6. Функция
shutdown
с аргументами
SHUT_WR
и
SHUT_RDWR
всегда посылает сегмент FIN, в то время как функция
close
посылает сегмент FIN только если в момент вызова функции
close
счетчик ссылок дескриптора равен 1.
6.7. Функция
readline
возвращает ошибку, и наша функция-обертка
Readline
завершает работу сервера. Но серверы должны справляться с такими ситуациями. Обратите внимание на то, как мы обрабатываем эти условия в листинге 6.6, хотя даже этот код не является удовлетворительным. Рассмотрим, что произойдет, если соединение между клиентом и сервером прервется и время ожидания одного из ответов сервера будет превышено. Возвращаемой ошибкой может быть ошибка
ETIMEDOUT
.
Обычно сервер не должен прекращать свою работу из-за подобных ошибок. Он должен записать ее в файл журнала, закрыть сокет и продолжать обслуживание других клиентов. Следует понимать, что обработка таких ошибок путем прекращения работы сервера недопустима для серверов, у которых один процесс выполняет обработку всех клиентов. Но если сервер был дочерним процессом, обрабатывающим только один клиент, то прекращение работы одного дочернего процесса не отразится ни на родительском процессе (который, по нашему предположению, обрабатывает все новые соединения и порождает новые дочерние процессы), ни на одном из других дочерних процессов, обрабатывающих другие клиенты.
Глава 7
7.2. Решение упражнения приведено в листинге Д.2. Вывод строки данных, возвращаемых сервером, был удален, поскольку это значение нам не нужно.
Листинг Д.2. Вывод размера приемного буфера сокета и MSS до и после установления соединения
He существует какого-то одного «правильного» вывода для данной программы. Результаты зависят от системы. Некоторые системы (в особенности Solaris 2.5.1 и более ранние версии) всегда возвращают нулевой размер буфера сокета, не давая нам возможности увидеть, что происходит с этим значением в процессе соединения.
До вызова функции
connect
выводится значение MSS по умолчанию (часто 536 или 512), а значение, выводимое после вызова функции connect, зависит от возможных параметров MSS, полученных от собеседника. Например, в локальной сети Ethernet после выполнения функции connect MSS может иметь значение 1460. Однако после соединения (
connect
) с сервером в удаленной сети значение MSS может быть равно значению по умолчанию, если только ваша система не поддерживает обнаружение транспортной MTU. Если это возможно, запустите во время работы вашей программы программу
tcpdump
или подобную ей (см. раздел В.5), чтобы увидеть фактическое значение параметра MSS в сегменте SYN, полученном от собеседника.