Это требует описания переменной
len
как
socklen_t
, a
cliaddr
как структуры
struct sockaddr_in
. Обратите внимание, что аргумент типа «значение-результат» для функции
getsockname(len)
должен быть до вызова функции инициализирован размером переменной, на которую указывает второй аргумент. Наиболее частая ошибка программирования при использовании аргументов типа «значение-результат» заключается в том, что про эту инициализацию забывают.
4.3. Когда дочерний процесс вызывает функцию
close
, счетчик ссылок уменьшается с 2 до 1, так что клиенту не посылается сегмент FIN. Позже, когда родительский процесс вызывает функцию
close
, счетчик ссылок уменьшается до нуля, и тогда сегмент FIN посылается.
4.4. Функция
accept
возвращает значение
EINVAL
, так как первый аргумент не является прослушиваемым сокетом.
4.5. Вызов функции
listen
без вызова функции
bind
присваивает прослушиваемому сокету динамически назначаемый порт.
Глава 5
5.1. Длительность состояния TIME_WAIT должна находиться в интервале между 1 и 4 минутами, что дает величину MSL от 30 с до 2 мин.
5.2. Наши клиент-серверные программы не работают с двоичными файлами. Допустим, что первые 3 байта в файле являются двоичной единицей (1), двоичным нулем (0) и символом новой строки. При вызове функции
fgets
в листинге 5.4 либо считывается
MAXLINE
- 1 символов, либо считываются символы до символа новой строки или до конца файла. В данном примере функция считает три символа, а затем прервет строку нулевым байтом. Но вызов функции
strlen
в листинге 5.4 возвращает значение 1, так как она остановится на первом нулевом байте. Один байт посылается серверу, но сервер блокируется в своем вызове функции
readline
, ожидая символа новой строки. Клиент блокируется, ожидая ответа от сервера. Такое состояние называется
fgets
обозначает нулевым байтом конец возвращаемых ею данных, поэтому данные, которые она считывает, не должны содержать нулевой байт.
5.3. Программа
Telnet
преобразует входные строки в NVT ASCII (см. раздел 26.4 книги [111]), что означает прерывание каждой строки 2-символьной последовательностью CR (carriage return — возврат каретки) и LF (linefeed — новая строка). Наш клиент добавляет только разделитель строк (newline), который в действительности является символом новой строки (linefeed, LF). Тем не менее можно использовать клиент Telnet для связи с нашим сервером, поскольку наш сервер отражает каждый символ, включая CR, предшествующий каждому разделителю строк.
5.4. Нет, последние два сегмента из последовательности завершения соединения не посылаются. Когда клиент посылает серверу данные после уничтожения дочернего процесса сервера (ввод строки
another line
, см. раздел 5.12), сервер TCP отвечает сегментом RST. Сегмент RST прекращает соединение, а также предотвращает переход в состояние TIME_WAIT на стороне сервера (конец соединения, осуществивший активное закрытие).
5.5. Ничего не меняется, потому что процесс, запущенный на узле сервера, создает прослушиваемый сокет и ждет прибытия запросов на соединение. На третьем шаге мы посылаем сегмент данных, предназначенный для установленного соединения TCP (состояние ESTABLISHED). Наш сервер с прослушиваемым сокетом не увидит этот сегмент данных, и TCP сервера по-прежнему будет посылать клиенту сегмент RST.
5.6. В листинге Д.1 [1]приведена программа. Запуск этой программы в Soalris генерирует следующий вывод:
solaris %
tsigpipe 192.168.1.10
SIGPIPE received
write error: Broken pipe
Начальный вызов функции
sleep
и переход в режим ожидания на 2 с нужен, чтобы сервер времени и даты отправил ответ и закрыл свой конец соединения. Первая функция
write
отправляет сегмент данных серверу, который отвечает сегментом RST (поскольку сервер времени и даты полностью закрыл свой сокет). Обратите внимание, что наш TCP позволяет писать в сокет, получивший сегмент FIN. Второй вызов функции
sleep
позволяет получить от сервера сегмент RST, а во втором вызове функции
write
генерируется сигнал
SIGPIPE
. Поскольку наш обработчик сигналов возвращает управление, функция write возвращает ошибку
EPIPE
.
Листинг Д.1. Генерация SIGPIPE
//tcpcliserv/tsigpipe.c
1 #include "unp.h"
2 void
3 sig_pipe(int signo)
4 {
5 printf("SIGPIPE received\n");
6 return;
7 }
8 int
9 main(int argc, char **argv)
10 {
11 int sockfd;
12 struct sockaddr_in servaddr;
13 if (argc != 2)
14 err_quit("usage: tcpcli Ipaddress");