7 struct sockaddr_in6
8 if (argc != 2)
9 err_quit("usage: a.out
10 if ((sockfd = socket(AF_INET6
11 err_sys("socket error");
12 bzero(&servaddr, sizeof(servaddr));
13 servaddr.sin6_family
14 servaddr.sin6_port
15 if (inet_pton(AF_INET6
16 err_quit("inet_pton error for %s", argv[1]);
17 if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) < 0)
18 err_sys("connect error");
19 while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
20 recvline[n] = 0; /* символ конца строки */
21 if (fputs(recvline, stdout) == EOF)
22 err_sys("fputs error");
23 }
24 if (n < 0)
25 err_sys("read error");
26 exit(0);
27 }
Изменились только пять строк, но в результате мы все равно получили программу, зависимую от протокола, в данном случае — от протокола IPv6. Лучше сделать программу
getaddrinfo
из tcp_connect
.Другим недостатком наших программ является то, что пользователь должен вводить IP-адрес сервера в точечно-десятичной записи (например, 206.168.112.219 для версии IPv4). Людям проще работать с именами, чем с числами (например, www.unpbook.com
1.4. Обработка ошибок: функции-обертки
В любой реальной программе существенным моментом является проверка
socket
, inet_pton
, connect
, read
и fputs
, и когда ошибка случается, мы вызываем свои собственные функции err_quit
и err_sys
для печати сообщения об ошибке и для прерывания выполнения программы. В отдельных случаях, когда функция возвращает ошибку, бывает нужно сделать еще что-либо помимо прерывания программы, как показано в листинге 5.9, когда мы должны проверить прерванный системный вызов.Поскольку прерывание программы из-за ошибки — типичное явление, мы сократим наши программы, определив
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
Наша функция-обертка для функции socket показана в листинге 1.3.
Листинг 1.3
. Наша функция-обертка для функции socket//lib/wrapsock.c
172 int
173 Socket(int family, int type, int protocol)
174 {
175 int n;
176 if ((n = socket(family, type, protocol)) < 0)
177 err_sys("socket error");
178 return (n);
179 }