Фатальная ошибка, не относящаяся к системному вызову.
52 Выводим сообщение и заканчиваем работу. */
53 void
54 err_quit(const char *fmt, ...)
55 {
56 va_list ap;
57 va_start(ap, fmt);
58 err_doit(0, LOG_ERR, fmt, ap);
59 va_end(ap);
60 exit(1);
61 }
62 /* Выводим сообщение и возвращаем управление.
63 Вызывающий процесс задает "errnoflag" и "level" */
64 static void
65 err_doit(int errnoflag, int level, const char *fmt, va_list ap)
66 {
67 int errno_save, n;
68 char buf[MAXLINE + 1];
69 errno_save = errno; /* значение может понадобиться вызвавшему
процессу */
70 #ifdef HAVE_VSNPRINTF
71 vsnprintf(buf, MAXLINE, fmt, ap); /* защищенный вариант */
72 #else
73 vsprintf(buf, fmt, ap); /* незащищенный вариант */
74 #endif
75 n = strlen(buf);
76 if (errnoflag)
77 snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
78 strcat(buf, "\n");
79 if (daemon_proc) {
80 syslog(level, buf);
81 } else {
82 fflush(stdout); /* если stdout и stderr совпадают */
83 fputs(buf, stderr);
84 fflush(stderr);
85 }
86 return;
87 }
Приложение Д
Решения некоторых упражнений
Глава 1
1.3. В операционной системе Solaris получаем:
solaris % daytimetcpcli 127.0.0.1
socket error: Protocol not supported
Для получения дополнительной информации об этой ошибке сначала используем программу
grep
, чтобы найти строку
Protocol not supported
в заголовочном файле
<sys/errno.h>
.
solaris % grep 'Protocol not supported' /usr/include/sys/errno.h
#define EPROTONOSUPPORT 120 /* Protocol not supported */
Это значение
errno
возвращается функцией
socket
. Далее смотрим в руководство пользователя:
solaris % man socket
В большинстве руководств пользователя в конце под заголовком «Errors» приводится дополнительная, хотя и лаконичная информация об ошибках.
1.4. Заменяем первое описание на следующее:
int sockfd, n, counter = 0;
Добавляем оператор
counter++;
в качестве первого оператора цикла
while
. Наконец, прежде чем прервать программу, выполняем
printf("counter = %d\n", counter);
На экран всегда выводится значение 1.
1.5. Объявим переменную i типа int и заменим вызов функции
write
на следующий:
for (i = 0; i < strlen(buff); i++)
Write(connfd, &buff[i], 1);
Результат зависит от расположения клиентского узла и узла сервера. Если клиент и сервер находятся на одном узле, счетчик обычно равен 1. Это значит, что даже если сервер выполнит функцию
write
26 раз, данные будут возвращены за одну операцию считывания (
read
). Но если клиент запущен в Solaris 2.5.1, а сервер в BSD/OS 3.0, счетчик обычно равен 2. Просмотрев пакеты Ethernet, мы увидим, что первый символ отправляется в первом пакете сам по себе, а следующий пакет содержит остальные 25 символов. (Обсуждение алгоритма Нагла в разделе 7.9 объясняет причину такого поведения.)
Цель этого примера — продемонстрировать, что разные реализации TCP по-разному поступают с данными, поэтому наше приложение должно быть готово считывать данные как поток байтов, пока не будет достигнут конец потока.
Глава 2
2.1 Зайдите на веб-страницу
http://www.iana.org/numbers.htm
и найдите журнал под названием «IP Version Number». Номер версии 0 зарезервирован, версии 1-3 не использовались, а версия 5 представляет собой потоковый протокол Интернета (Internet Stream Protocol).
2.2. Все RFC бесплатно доступны по электронной почте, через FTP или Web. Стартовая страница для поиска находится по адресу
http://www.ietf.org
. Одним из мест расположения RFC является каталог
ftp://ftp.isi.edu/in-notes
. Для начала следует получить файл с текущим каталогом RFC, обычно это файл
rfc-index.txt
. HTML-версия хранится в файле
http://www.rfc-editor.org/rfc-index.html
. Если с помощью какого-либо редактора осуществить поиск термина «stream» (поток) в указателе RFC, мы выясним, что RFC 1819 определяет версию 2 потокового протокола Интернета. Какую бы информацию, которая может содержаться в RFC, мы ни искали, для поиска следует использовать указатель (каталог) RFC.