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
15 sockfd = Socket(AF_INET, SOCK_STREAM, 0);
16 bzero(&servaddr, sizeof(servaddr));
17 servaddr.sin_family = AF_INET;
18 servaddr.sin_port = htons(13); /* сервер времени и даты */
19 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
20 Signal(SIGPIPE, sig_pipe);
21 Connect(sockfd, (SA*)&servaddr, sizeof(servaddr));
22 sleep(2);
23 Write(sockfd, "hello", 5);
24 sleep(2);
25 Write(sockfd, "world", 5);
26 exit(0);
27 }
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии