Разрабатывайте и применяйте каркасы приложений
| | |
Большинство приложений TCP/IP попадают в одну из четырех категорий:
В приложениях одной категории обычно встречается почти одинаковый «стартовый» код, который инициализирует все, что связано с сетью. Например,TCP- сервер должен поместить в поля структуры sockaddr_in адрес и порт получателя, получить от системы сокет типа SOCK_STREAM, привязать к нему выбранный адрес и номер порта, установить опцию сокета SO_REUSEADDR (совет 23), вызвать listen, а затем быть готовым к приему соединения (или нескольких соединений) с помощью системного вызова accept.
На каждом из этих этапов следует проверять код возврата. А часть программы, занимающаяся преобразованием адресов, должна иметь дело как с числом так и с символическими адресами и номерами портов. Таким образом, в любом TCP-сервере есть порядка 100 почти одинаковых строк кода для выявления всех перечисленных выше задач. Один из способов решения этой проблемы - поместить стартовый код в одну или несколько библиотечных функций которые приложение может вызвать. Эта стратегия использована в книге. Но иногда приложению нужна слегка видоизмененная последовательность инициализации. В таком случае придется либо написать ее с нуля, либо извлечь нужный фрагмент кода из библиотеки и подправить его.
Чтобы справиться и с такими ситуациями, можно построить каркас приложения, в котором уже есть весь необходимый код. Затем скопировать этот каркас, внести необходимые изменения, после чего заняться логикой самого приложения. Не имея каркаса, легко поддаться искушению и срезать некоторые углы, например, жестко «зашить» в приложение адреса (совет 29) или сделать еще что-то сомнительное. Разработав каркас, вы сможете убрать все типичные функции в библиотеку, а каркас оставить только для необычных задач.
Чтобы сделать программы переносимыми, следует определить несколько макросов, в которых скрыть различия между API систем UNIX и Windows. Например, в UNIX системный вызов для закрытия сокета называется close, а в Windows - closesocket. Версии этих макросов для UNIX показаны в листинге 2.1. Версии для Windows аналогичны, приведены в приложении 2. Доступ к этим макросам из каркасов осуществляется путем включения файла skel.h.
Листинг 2.1. Заголовочный файл skel.h
1 #ifndef __SKEL_H__
2 #define __SKEL_H__
3 /*версия для UNIX */
4 #define INIT() ( program_name = \
5 strrchr ( argv[ 0 ], '/' ) ) ? \
6 program_name++ : \
7 ( program_name = argv[ 0 ] )
8 #define EXIT(s) exit( s )
9 #define CLOSE(s) if ( close( s ) ) error( 1, errno, \
10 "ошибка close " )
11 #define set_errno(e) errno = ( e )
12 #define isvalidsock(s) ( ( s ) >= 0 )
13 typedef int SOCKET;
14 #endif /* __SKEL_H__ */