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

Значение

0x01000000
интерпретируется как 16 777 216. Аналогично, целое число 2, отправленное клиентом, интерпретируется сервером как
0x02000000
, или 33 554 432. Сумма этих двух целых чисел равна 50 331 648, или
0x03000000
. Когда это значение, записанное в обратном порядке байтов, отправляется клиенту, оно интерпретируется клиентом как целое число 3.

Но 32-разрядное целое число -22 представляется в системе с прямым порядком байтов так, как показано на рис. Д.3 (мы предполагаем, что используется поразрядное дополнение до двух для отрицательных чисел).

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

Рис. Д.3. Представление 32-разрядного целого числа -22 в формате прямого порядка байтов

В системе с обратным порядком байтов это значение интерпретируется как

0xeaffffff
, или -352 521 537. Аналогично, представление числа -77 в прямом порядке байтов выглядит как
0xffffffb3
, но в системах с обратным порядком оно представляется как
0xb3ffffff
, или -1 275 068 417. Сложение, выполняемое сервером, приводит к результату
0x9efffffe
, или -1 627 389 954. Полученное значение в обратном порядке байтов посылается через сокет клиенту, где в прямом порядке байтов оно интерпретируется как
0xfeffff9e
, или -16 777 314 — это то значение, которое выводится в нашем примере.

5.9. Метод правильный (преобразование двоичных значений в сетевой порядок байтов), но нельзя использовать функции

htonl
и
ntohl
. Хотя символ
l
в названиях данных функций обозначает «long», эти функции работают с 32-разрядными целыми (раздел 3.4). В 64-разрядных системах
long
занимает 64 бита, и эти две функции работают некорректно. Для решения этой проблемы следует определить две новые функции
hton64
и
ntoh64
, но они не будут работать в системах, представляющих значения типа
long
32 битами.

5.10. В первом сценарии сервер будет навсегда блокирован при вызове функции

readn
в листинге 5.14, поскольку клиент посылает два 32-разрядных значения, а сервер ждет два 64-разрядных значения. В случае, если клиент и сервер поменяются узлами, клиент будет посылать два 64-разрядных значения, а сервер считает только первые 64 бита, интерпретируя их как два 32-разрядных значения. Второе 64-разрядное значение останется в приемном буфере сокета сервера. Сервер отправит обратно 32-разрядное значение, и клиент навсегда заблокируется в вызове функции
readn
в листинге 5.13, поскольку будет ждать для считывания 64-разрядное значение.

5.11. Функция IP-маршрутизации просматривает IP-адрес получателя (IP-адрес сервера) и пытается по таблице маршрутизации определить исходящий интерфейс и следующий маршрутизатор (см. главу 9 [111]). В качестве адреса отправителя используется первичный IP-адрес исходящего интерфейса, если сокет еще не связан с локальным IP-адресом.

Глава 6

6.1. Массив целых чисел содержится внутри структуры, а язык С позволяет использовать со структурами оператор присваивания.

6.2. Если функция

select
сообщает, что сокет готов к записи, причем буфер отправки сокета вмещает 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. Вывод строки данных, возвращаемых сервером, был удален, поскольку это значение нам не нужно.

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