Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

отсоединение сокета;

присоединение сокета;

вывод второй дейтаграммы;

отсоединение сокета.

ПРИМЕЧАНИЕ

Другой момент, который нужно учитывать, — количество поисков в таблице маршрутизации. Первое временное соединение производит поиск в таблице маршрутизации IP-адреса получателя и сохраняет (кэширует) эту информацию. Второе временное соединение отмечает, что адрес получателя совпадает с кэшированным адресом из таблицы маршрутизации (мы считаем, что обеим функциям sendto задан один и тот же получатель), и ему не нужно снова проводить поиск в таблице маршрутизации [128, с. 737–738].

Когда приложение знает, что оно будет отправлять множество дейтаграмм одному и тому же собеседнику, эффективнее будет присоединить сокет явно. Вызов функции

connect
, за которым следуют два вызова функции
write
, теперь будет включать следующие шаги, выполняемые ядром:

присоединение сокета;

вывод первой дейтаграммы;

вывод второй дейтаграммы.

В этом случае ядро копирует структуру адреса сокета, содержащую IP-адрес получателя и порт, только один раз, а при двойном вызове функции

sendto
копирование выполняется дважды. В [89] отмечается, что на временное присоединение отсоединенного сокета UDP приходится примерно треть стоимости каждой передачи UDP.

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 возвращают.

  • Читать дальше
  • 1
  • ...
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: