Последовательные серверы без установления логического соединения (UDP)

Опубликовано в Технологии > Серверные технологии

9.1. Введение

В предыдущей главе было рассмотрено много возможных проектов серверов и описаны преимущества и недостатки каждого из них. В настоящей главе приведен пример реализации последовательного сервера, в которой используется транспортный протокол без установления логического соединения. Этот пример сервера создан в соответствии с алгоритмом 8.2. В следующих главах описание этой темы продолжено на примерах реализации других алгоритмов серверов.

9.2. Создание пассивного сокета

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

В целях упрощения кода сервера программисты используют процедуры, которые скрывают сложности процесса распределения сокета. Как и в примерах клиентов, в этих примерах реализации серверов применяются две процедуры высокого уровня, passiveUDP и passiveTCP, которые распределяют пассивный сокет и привязывают его к общепринятому порту сервера. Каждый сервер вызывает одну из этих процедур, причем выбор конкретной процедуры зависит от того, используется ли в сервере транспортный протокол с установлением или без установления логического соединения. В настоящей главе рассматривается процедура passiveUDP, а в следующей главе приведен код процедуры passiveTCP. Поскольку эти две процедуры имеют много общего, в них предусмотрен вызов процедуры низкого уровня passivesock для выполнения одинаковых действий.

В сервере без установления логического соединения для создания сокета, который используется в предоставляемой им службе, вызывается функция passiveUDP. Если для сервера требуется один из портов, зарезервированных для общепринятых служб (т.е. порт с низким номером), серверный процесс должен иметь особые привилегии. Для создания сокета непривилегированной службы вызов процедуры passiveUDP может быть выполнен в любой прикладной программе. Процедура passiveUDP вызывает процедуру passivesock для создания сокета протокола без установления логического соединения, а затем возвращает дескриптор сокета в вызывающий оператор.

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

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

Основное преимущество использования переменной portbase связано с ее безопасностью и общностью. Во-первых, поскольку программисту не нужно корректировать все ссылки на номера портов во всем коде, применение переменной portbase способствует снижению вероятности ошибок (например, связанных с непреднамеренным пропуском одного из исправлений при вставке кода перед отладкой или при удалении кода после отладки). Во-вторых, применение переменной portbase служит общим решением проблемы. Она не только позволяет проверять новую версию во время работы производственного сервера, но и дает возможность одновременно проверять сразу несколько новых версий сервера. Для этого программист просто присваивает каждой версии уникальное, ненулевое значение portbase. Следовательно, номер порта, передаваемый конкретной версии сервера API-интерфейсу сокетов, не будет конфликтовать с номерами портов, которые используются для других отладочных версий или для производственной версии.

Применение глобальной переменной для смещения номеров портов обеспечивает безопасную отладку программы, поскольку позволяет программисту одновременно проверять несколько версий сервера, не внося изменений во всем коде.

I* passiveUDP.с - процедура passiveUDP */
int    passivesock(const char *service, const char transport, int qlen);
/*	
*	Процедура passiveUDP - создает пассивный сокет для использования
*	в сервере UDP
*	
*/ int
passiveUDP(const char *service)
 

В системе Linux, как и в большинстве систем UNIX, приложение должно выполняться с правами root (т.е. от имени суперпользователя), чтобы иметь достаточные привилегии для привязки порта с номером менее 1024.

*	Параметры:
*	service - служба, связанная с требуемым портом */
{
return passivesock(service, "udp", 0);
}
 

Все тонкости процесса распределения сокета, включая использование переменной portbase, учтены в процедуре passivesock. Она принимает три параметра. Первый параметр указывает службу, второй — имя протокола, а третий (используется только для сокетов TCP) задает требуемую длину очереди запросов на установление соединения. Первый параметр, символьная строка, может содержать либо имя службы, либо номер порта протокола для этой службы; если используется номер порта, он должен быть представлен в виде символьной строки. Процедура passivesock распределяет либо дейтаграммный, либо потоковый сокет, привязывает сокет к общепринятому порту данной службы и возвращает дескриптор сокета в вызывающий оператор.

Напомним, что при привязке сокета к общепринятому порту в серверной программе необходимо указать адрес с использованием структуры sockaddr_in, которая включает IP-адрес и номер порта протокола. Вместо задания конкретного локального IP-адреса в процедуре passivesock используется константа INADDR_ANY, как описано в главе 8. Применение константы INADDR_ANY обеспечивает работу сервера не только на хостах, имеющих один IP-адрес, но и на маршрутизаторах и многоадресных хостах, которые имеют несколько IP-адресов. Следует отметить, что процедура passivesock требует указания конкретного номера порта протокола; применение в качестве параметра порта константы INADDR_ANY означает, что сервер будет принимать запросы, направленные в данный порт через любой из IP-адресов компьютера.