Почему мы устанавливаем размер буфера приема сокета равным 240x1024 байт в листинге 8.12? Максимальный размер приемного буфера сокета в BSD/OS 2.1 по умолчанию равен 262 144 байта (256x1024), но из-за способа размещения буфера в памяти (описанного в главе 2 [128]) он в действительности ограничен до 246 723 байт. Многие более ранние системы, основанные на 4.3BSD, ограничивали размер буфера приема сокета примерно до 52 000 байт.
8.14. Определение исходящего интерфейса для UDP
С помощью присоединенного сокета UDP можно также задавать исходящий интерфейс, который будет использован для отправки дейтаграмм к определенному получателю. Это объясняется побочным эффектом функции
connect
, примененной к сокету UDP: ядро выбирает локальный IP-адрес (предполагается, что процесс еще не вызвал функцию
bind
для явного его задания). Локальный адрес выбирается в процессе поиска адреса получателя в таблице маршрутизации, причем берется основной IP-адрес интерфейса, с которого, согласно таблице, будут отправляться дейтаграммы.В листинге 8.13 показана простая программа UDP, которая с помощью функции connect соединяется с заданным IP-адресом и затем вызывает функцию
getsockname
, выводя локальный IP-адрес и порт.Листинг 8.13
. Программа UDP, использующая функцию connect для определения исходящего интерфейса//udpcliserv/udpcli09.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int sockfd;
6 socklen_t len;
7 struct sockaddr_in cliaddr, servaddr;
8 if (argc != 2)
9 err_quit("usage: udpcli
10 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
11 bzero(&servaddr, sizeof(servaddr));
12 servaddr.sin_family = AF_INET;
13 servaddr.sin_port = htons(SERV_PORT);
14 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
15 Connect(sockfd, (SA*)&servaddr, sizeof(servaddr));
16 len = sizeof(cliaddr);
17 Getsockname(sockfd, (SA*)&cliaddr, &len);
18 printf("local address %s\n", Sock_ntop((SA*)&cliaddr, len));
19 exit(0);
20 }
Если мы запустим программу на узле
freebsd
с несколькими сетевыми интерфейсами, то получим следующий вывод:freebsd %
local address 12.106.32.254:52329
freebsd %
local address 192.168.42.1:52330
freebsd %
local address 127.0.0.1:52331
По рис. 1.7 видно, что когда мы запускаем программу первые два раза, аргументом командной строки является IP-адрес в разных сетях Ethernet. Ядро присваивает локальный IP-адрес первичному адресу интерфейса в соответствующей сети Ethernet. При вызове функции
connect
на сокете UDP ничего не отправляется на этот узел — это полностью локальная операция, которая сохраняет IP-адрес и порт собеседника. Мы также видим, что вызов функции connect на неприсоединенном сокете UDP также присваивает сокету динамически назначаемый порт.К сожалению, эта технология действует не во всех реализациях, что особенно касается ядер, происходящих от SVR4. Например, это не работает в Solaris 2.5, но работает в AIX, Digital Unix, Linux, MacOS X и Solaris 2.6.
8.15. Эхо-сервер TCP и UDP, использующий функцию select
Теперь мы объединим наш параллельный эхо-сервер TCP из главы 5 и наш последовательный эхо-сервер UDP из данной главы в один сервер, использующий функцию
select
для мультиплексирования сокетов TCP и UDP. В листинге 8.14 представлена первая часть этого сервера.Листинг 8.14
. Первая часть эхо-сервера, обрабатывающего сокеты TCP и UDP при помощи функции select