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

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

стр.

При описании исходного кода, представленного в тексте книги, мы всегда ссылаемся на вызываемую функцию низшего уровня (например, socket), но не на функцию-обертку (например, Socket).

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

>Pthread_mutex_lock(&ndone_mutex);

Листинг 1.4. Наша собственная функция-обертка для функции pthread_mutex_lock

>//lib/wrappthread.c

>72 void

>73 Pthread_mutex_lock(pthread_mutex_t *mptr)

>74 {

>75  int n;


>76  if ((n = pthread_mutex_lock(mptr)) == 0)

>77   return;

>78  errno = n;

>79  err_sys("pthread_mutex_lock error");

>80 }

ПРИМЕЧАНИЕ

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

Наш выбор — первая заглавная буква в названии функции — является компромиссом. Было предложено множество других стилей: подстановка префикса e перед названием функции (как сделано в [67, с. 182]), добавление _е к имени функции и т.д. Наш вариант кажется наименее отвлекающим внимание и одновременно дающим визуальное указание на то, что вызывается какая-то другая функция.

Эта технология имеет, кроме того, полезный побочный эффект: она позволяет проверять возникновение ошибок при выполнении таких функций, ошибки в которых часто остаются незамеченными, например close и listen.

На протяжении всей книги мы будем использовать эти функции-обертки, кроме тех случаев, когда нам нужно проверить ошибку явно и обрабатывать ее другим, отличным от прерывания программы, способом. Мы не приводим исходный код для всех наших собственных функций-оберток, но он свободно доступен в Интернете (см. предисловие).

Значение системной переменной Unix errno

Когда при выполнении функции Unix (например, одной из функций сокетов) происходит ошибка, глобальной переменной >errno присваивается положительное значение, указывающее на тип ошибки, а возвращаемое значение функции обычно равно -1. Наша функция >err_sys проверяет значение переменной >errno и печатает строку с соответствующим сообщением об ошибке (например, «Время соединения истекло», если значение переменной errno равно >ETIMEDOUT).

Переменная errno устанавливается равной определенному значению, только если при выполнении функции произошла какая-либо ошибка. Ее значение не определено, если функция не возвращает ошибки. Все положительные значения ошибок являются константами с именами в верхнем регистре, начинающимися на «E», и обычно определяются в заголовке >. Ни одна ошибка не имеет кода 0.

Переменную errno нельзя хранить как глобальную переменную в случае множества потоков, у которых все глобальные переменные являются общими. О решении этой проблемы мы расскажем в главе 23.

На протяжении всего текста книги мы использовали фразы типа «функция connect возвращает >ECONNREFUSED» для сокращенного обозначения того, что при выполнении функции произошла ошибка (обычно при этом возвращаемое значение функции равно -1), и значение переменной >errno стало равным указанной константе.

1.5. Простой сервер времени и даты

Мы можем написать простую версию сервера TCP для определения времени и даты, который будет работать с клиентом, описанным в разделе 1.2. Мы используем функции-обертки, описанные в предыдущем разделе. Код сервера приведен в листинге 1.5.

Листинг 1.5. TCP-сервер времени и даты

>//intro/daytimetcpsrv.c

> 1 #include "unp.h"

> 2 #include


> 3 int

> 4 main(int argc, char **argv)

> 5 {

> 6  int listenfd, connfd;

> 7  struct sockaddr_in servaddr;

> 8  char buff[MAXLINE];

> 9  time_t ticks;


>10  listenfd = Socket(AF_INET, SOCK_STREAM, 0);

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

>12  servaddr.sin_family = AF_INET;

>13  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

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


>15  Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));


стр.

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