UNIX: разработка сетевых приложений - страница 8

Шрифт
Интервал

стр.

>11   err_sys("socket error");


>12  bzero(&servaddr, sizeof(servaddr));

>13  servaddr.sin6_family = AF_INET6;

>14  servaddr.sin6_port = htons(13); /* сервер времени и даты */

>15  if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0)

>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. Лучше сделать программу независимой от протокола (protocol independent). В листинге 11.3 представлена независимая от протокола версия этого клиента, основанная на вызове >getaddrinfo из >tcp_connect.

Другим недостатком наших программ является то, что пользователь должен вводить IP-адрес сервера в точечно-десятичной записи (например, 206.168.112.219 для версии IPv4). Людям проще работать с именами, чем с числами (например, >www.unpbook.com). В главе 11 мы обсудим функции, обеспечивающие преобразование имен узлов в IP-адреса и имен служб в порты. Мы специально откладываем описание этих функций, продолжая использовать IP-адреса и номера портов, чтобы иметь ясное представление о том, что именно входит в структуры адресов сокетов, которые мы должны заполнить и проверить. Это также упрощает наши объяснения сетевого программирования, снимая необходимость описывать в подробностях еще один набор функций.

1.4. Обработка ошибок: функции-обертки

В любой реальной программе существенным моментом является проверка каждого вызова функции на предмет возвращаемой ошибки. В листинге 1.1 мы проводим поиск ошибок в вызовах функций >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 }

Хотя вы можете решить, что использование этих функций-оберток не обеспечивает большой экономии, на самом деле это не так. Обсуждая потоки (threads) в главе 26, мы обнаружим, что, когда происходит какая-либо ошибка, функции потоков не устанавливают значение стандартной переменной Unix >errno равным определенной константе, специфической для произошедшей ошибки. Вместо этого значение переменной >errno просто возвращается функцией. Это значит, что каждый раз, когда мы вызываем одну из функций >pthread, мы должны разместить в памяти переменную, сохранить возвращаемое значение в этой переменной и установить >errno равной этому значению перед вызовом >err_sys. Чтобы избежать загромождения кода скобками, мы можем использовать оператор языка С запятая для объединения присваивания значения переменной >errno и вызова >err_sys в отдельное выражение следующим образом:

>int n;

>if ((n = pthread_mutex_lock(&ndone_mutex)) != 0)

> errno = n, err_sys("pthread_mutex_lock error");

ВНИМАНИЕ

В тексте книги вам будут встречаться функции, имена которые начинаются с заглавной буквы. Это наши собственные функции-обертки. Функция-обертка вызывает функцию, имеющую такое же имя, но начинающееся со строчной буквы.


стр.

Похожие книги