Книга: UNIX: разработка сетевых приложений
8.12. Функция dg_cli (продолжение)
8.12. Функция dg_cli (продолжение)
Вернемся к функции dg_cli
, показанной в листинге 8.4, и перепишем ее, с тем чтобы она вызывала функцию connect
. В листинге 8.7 показана новая функция.
Листинг 8.7. Функция dg_cli, вызывающая функцию connect
//udpcliserv/dgcliconnect.c
1 #include "unp.h"
2 void
3 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
4 {
5 int n;
6 char sendline[MAXLINE], recvline[MAXLINE + 1];
7 Connect(sockfd, (SA*)pservaddr, servlen);
8 while (Fgets(sendline, MAXLINE, fp) != NULL) {
9 Write(sockfd, sendline, strlen(sendline));
10 n = Read(sockfd, recvline, MAXLINE);
11 recvline[n] = 0; /* завершающий нуль */
12 Fputs(recvline, stdout);
13 }
14 }
Изменения по сравнению с предыдущей версией — это добавление вызова функции connect
и замена вызовов функций sendto
и recvfrom вызовами функций write
и read
. Функция dg_cli
остается не зависящей от протокола, поскольку она не вникает в структуру адреса сокета, передаваемую функции connect
. Наша функция main
клиента, показанная в листинге 8.3, остается той же.
Если мы запустим программу на узле macosx
, задав IP-адрес узла freebsd4
(который не запускает наш сервер на порте 9877), мы получим следующий вывод:
macosx % udpcli04 172.24.37.94
hello, world
read error: Connection refused
Первое, что мы замечаем, — мы не получаем ошибку, когда запускаем процесс клиента. Ошибка происходит только после того, как мы отправляем серверу первую дейтаграмму. Именно отправка этой дейтаграммы вызывает ошибку ICMP от узла сервера. Но когда клиент TCP вызывает функцию connect
, задавая узел сервера, на котором не запущен процесс сервера, функция connect
возвращает ошибку, поскольку вызов функции connect
вызывает отправку первого пакета трехэтапного рукопожатия TCP, и именно этот пакет вызывает получение сегмента RST от собеседника (см. раздел 4.3).
В листинге 8.8 показан вывод программы tcpdump
.
Листинг 8.8. Вывод программы tcpdump при запуске функции dg_cli
macosx % tcpdump
01 0.0 macosx.51139 > freebsd4 9877:udp 13
02 0.006180 ( 0.0062) freebsd4 > macosx: icmp: freebsd4 udp port 9877 unreachable
В табл. A.5 мы также видим, что возникшую ошибку ICMP ядро сопоставляет ошибке ECONNREFUSED
, которая соответствует выводу строки сообщения Connection refused
(В соединении отказано) функцией err_sys
.
ПРИМЕЧАНИЕ
К сожалению, не все ядра возвращают сообщения ICMP присоединенному сокету UDP, как мы показали в этом разделе. Обычно ядра реализаций, происходящих от Беркли, возвращают эту ошибку, а ядра System V — не возвращают. Например, если мы запустим тот же клиент на узле Solaris 2.4 и с помощью функции connect соединимся с узлом, на котором не запущен наш сервер, то с помощью программы tcpdump мы сможем убедиться, что ошибка ICMP о недоступности порта возвращается узлом сервера, но вызванная клиентом функция read никогда не завершается. Эта ситуация была исправлена в Solaris 2.5. UnixWare не возвращает ошибку, в то время как AIX, Digital Unix, HP-UX и Linux возвращают.
- 8.1. Введение
- 8.2. Функции recvfrom и sendto
- 8.3. Эхо-сервер UDP: функция main
- 8.4. Эхо-сервер UDP: функция dg_echo
- 8.5. Эхо-клиент UDP: функция main
- 8.6. Эхо-клиент UDP: функция dg_cli
- 8.7. Потерянные дейтаграммы
- 8.8. Проверка полученного ответа
- 8.9. Запуск клиента без запуска сервера
- 8.10. Итоговый пример клиент-сервера UDP
- 8.11. Функция connect для UDP
- 8.12. Функция dg_cli (продолжение)
- 8.13. Отсутствие управления потоком в UDP
- 8.14. Определение исходящего интерфейса для UDP
- 8.15. Эхо-сервер TCP и UDP, использующий функцию select
- 8.16. Резюме
- Упражнения
- 16.2. Неблокируемые чтение и запись: функция str_cli (продолжение)
- * Продолжение следует??
- 6.4. Функция str_cli (продолжение)
- ББД продолжение
- Продолжение беседы
- 2.1.3. Функция getopt_long()
- Группировка по встроенным функциям и UDF
- Продолжение линии 1.0
- SERVER CLIENT MAPPING
- 19.1.1. Функция jQuery()
- Функция strcmp( )
- Управление функциями узла