Эта программа работает, однако имеется два ограничения. Во-первых, мы должны обрабатывать все различия, следя за
h_addrtype
и задавая соответствующим образом
sa
или
salen
. Более удачным решением было бы иметь библиотечную функцию, которая не только просматривает имя узла и имя службы, но и заполняет всю структуру адреса сокета (например,
getaddrinfo
, см. раздел 11.6). Во-вторых, эта программа компилируется только на узлах с поддержкой IPv6. Чтобы ее можно было откомпилировать на узле, поддерживающем только IPv4, следует добавить в код огромное количество директив
#ifdef
, что, несомненно, усложнит программу.
11.7. Разместите в памяти большой буфер (превышающий по размеру любую структуру адреса сокета) и вызовите функцию
getsockname
. Третий аргумент является аргументом типа «значение-результат», возвращающим фактический размер адресов протоколов. К сожалению, это допускают только структуры адреса сокета с фиксированной длиной (IPv4 и IPv6). Нет гарантии, что этот буфер будет работать с протоколами, которые могут вернуть структуру адреса сокета переменной длины (доменные сокеты Unix, см. главу 15).
11.8. Сначала размещаем в памяти массивы, содержащие имя узла и имя службы:
char host[NI_MAXHOST], serv[NI_MAXSERV];
После того как функция
accept
возвращает управление, вызываем вместо функции
sock_ntop
функцию
getnameinfo
:
if (getnameinfo(cliaddr, len, host, NI_MAXHOST, serv, NI_MAXSERV,
NI_NUMERICHOST | NI_NUMERICSERV) == 0)
printf("connection from %s.%s\n", host, serv);
Поскольку мы имеем дело с сервером, определяем флаги
NI_NUMERICHOST
и
NI_NUMERICSERV
, чтобы избежать поиска в DNS и
/etc/services
.
11.9. Первая проблема состоит в том, что второй сервер не может связаться (
bind
) с тем же портом, что и первый сервер, поскольку не установлен параметр сокета
SO_REUSEADDR
. Простейший способ справиться с такой ситуацией — создать копию функции
udp_server
, переименовать ее в
udp_server_reuseaddr
, сделать так, чтобы она установила параметр сокета, и вызывать ее в сервере.
11.10. Когда клиент выводит
Trying 206.62.226.35...
, функция
gethostname
возвращает IP-адрес. Пауза перед этим выводом означает, что распознаватель ищет имя узла. Вывод
Connected to bsdi.unpbook.com.
значит, что функция
connect
возвратила управление. Пауза между этими двумя выводами говорит о том, что функция connect пытается установить соединение.
Глава 12
12.1. Далее приведен сокращенный листинг. Обратите внимание, что клиент FTP в системе
freebsd
всегда пытается использовать команду
EPRT
(независимо от версии IP), но если это не срабатывает, то он пробует команду
PORT
.
freebsd %
ftp aix-4
Connected to aix-4.unpbook.com.
220 aix FTP server ...
...
230 Guest login ok. access restrictions apply.
ftp
debug
Debugging on (debug=1).
ftp
passive
Passive mode: off; fallback to active mode= off
ftp
dir
--- EPRT |1|192 168.42.1|50484|
500 'EPRT |1|192.168.42.1|50484|' command not understood.
disabling epsv4 for this connection
--- PORT 192.168.42.1.197.52
200 PORT command successful.
--- LIST
150 Opening ASCII mode data connection for /bin/ls
...
freebsd %
ftp ftp.kame.net
Trying 2001.200:0:4819:203:47ff:fea5:3085...
Connected to orange.kame.net.
220 orange.kame.net FTP server ...
...
230 Guest login ok. access restrictions apply.
ftp
debug
Debugging on (debug=1).
ftp
passive
Passive mode: off; fallback to active mode: off.
ftp
dir
--- EPRT |2|3ffe:b80:3:9ad1::2|50480|
200 EPRT command successful
--- LIST
150 Opening ASCII mode data connection for '/bin/ls'.
Глава 13
13.1. Все сообщения об ошибках, даже ошибка загрузки, такая как неправильный аргумент командной строки, должны сохраняться в файлах журнала с помощью функции
syslog
.