Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование в сетях Windows

.pdf
Скачиваний:
538
Добавлен:
11.03.2015
Размер:
3.02 Mб
Скачать

118

ЧАСТЬ II Интерфейс прикладного программирования Winsock

Затем укажите константу FROMPROTOCOLJNFO во всех трех параметрах (а/, type и protocol) — для них будут использоваться значения из переданной структуры WSAPROTOCOL_INFO Так указывается определенная запись протокола

Теперь рассмотрим два последних флага из WSASocket Параметр группы всегда равен 0, так как ни одна из версий Winsock не поддерживает группы сокетов В параметре dwFlags указывают один или несколько следующих флагов

WSA_FLAG_OVERLAPPED, ШWSA_FLAG_MULTIPOINT_C_ROOT, ЩWSA_FLAG_MULT1POINT_C_LEAF, ШWSA_FLAG_MULTIPOINT_D_ROOT, ШWSA_FLAG_MULTIPOINT_D_LEAF

Первый флаг — WSA_FLAG_OVER1APPED, указывает, что данный сокет допускает перекрытый ввод-вывод — это один из механизмов связи, предусмотренных в Winsock (см главу 8) Если вы создаете сокет функцией socket, флаг WSA_FLAG_OVERLAPPED задан по умолчанию В общем, рекомендуется всегда задавать этот флаг при использовании WSASocket Последние четыре флага относятся к сокетам многоадресного вещания

Простые сокеты

При создании сокета функцией WSASocket вы можете передать вызову структуру WSAPROTOCOLJNFO, чтобы определить тип сокета, который хотите создать Впрочем, вы можете создавать типы сокетов, для которых нет записи в каталоге поставщиков транспорта Лучшим пример тому — простые сокеты (raw socket) под протоколом IP Это одна из форм связи, позволяющая инкапсулировать другие протоколы, например Internet Control Message Protocol (ICMP) в пакеты UDP Протокол ICMP доставляет управляющие и информационные сообщения, а также уведомления об ошибках между узлами в Интернете Поскольку ICMP не предусматривает средств доставки данных, он работает не на том же уровне, что и протоколы UDP или TCP, а относится к уровню протокола IP Подробнее о простых сокетах — в главе 13

Информация о платформах

Windows 95 изначально поддерживает спецификацию Winsock 1 1 Корпорация Microsoft предоставила возможность бесплатно загружать обновления для Winsock 2 по адресу http //wwwmicrosoftcom/windows95/downloads/ Кроме того, доступен комплект разработчика — Winsock 2 SDK, содержащий заголовочные файлы и библиотеки, необходимые для компиляции приложений Winsock 2 Платформы Windows 98, Windows NT 4 и Windows 2000 изначально поддерживают Winsock 2 Windows СЕ поддерживает только Winsock 1 1

Поставщики транспорта поддерживаются с рядом ограничений Windows СЕ поддерживает только протоколы TCP/IP и Infrared Sockets (инфракрасные сокеты) В Windows 95 и Windows 98 поставщики транспорта NetBIOS (транс-

Г Л А ВА 5 Сетевые протоколы

i119

порты с семейством адресов AF NETBIOS) недоступны из Winsock При вызове WSAEnumProtocols ни один из поставщиков транспорта NetBIOS не будет перечислен, даже если установлен на компьютере Впрочем, обратиться к NetBIOS можно через «родной» интерфейс NetBIOS (см главу 1) Упомянутые поставщики RSVP (предоставляет функции QoS) и ATM изначально поддерживаются в Windows 98 и Windows 2000

Winsockимодель0SI

Теперь обсудим, как некоторые из понятий, описанных в этой главе, относятся к модели OSI (рис 1-1) Поставщики транспорта из каталога Winsock, перечисленные WSAEnumProtocols, работают на транспортном уровне модели OSI, то есть каждый из них обеспечивает обмен данными Впрочем, все они относятся к какому-то протоколу, а сетевой протокол работает на сетевом уровне, поскольку обусловливает способ адресации каждого узла в сети Например, UDP и TCP — это транспорты, хотя оба относятся к протоколу IP

Интерфейс Winsock расположен между сеансовым и транспортным уровнями Winsock позволяет открывать и закрывать сеанс связи и управлять им для любого данного транспорта Под управлением Windows три верхних уровня прикладной, представительский и сеансовый, — в основном относятся к вашему приложению Winsock Другими словами, приложение Winsock управляет всеми аспектами сеанса связи и при необходимости форматирует данные согласно целям программы

Выбор соответствующего протокола

При разработке сетевого приложения вы можете выбрать базовый протокол из числа имеющихся Если приложению необходимо осуществлять связь по определенному протоколу, выбор не богат Однако разрабатывая приложение «с нуля», лучше выбрать TCP/IP, поскольку этот протокол распространен

ишироко применяется в продуктах Microsoft AppleTalk, NetBIOS и IPX/SPX Microsoft поставляет для совместимости с другими операционными системами

исуществующими приложениями Например, вместе с Windows 95 по умолчанию устанавливаются протоколы NetBEUI и IPX/SPX

По мере роста популярности Интернета большинство организаций все шире используют TCP/IP Это также основной протокол Windows 2000 В связи с этим NetBIOS будет применяться все реже Учтите и активную поддержку Microsoft-реализации TCP/IP ошибки в нем исправляются значительно чаще и быстрее, чем в других протоколах

Таким образом, TCP/IP — это стратегический протокол для сетевых приложений Помимо этого Microsoft активно поддерживает сети ATM Если вы можете позволить себе разрабатывать приложение, функционирующее исключительно в сетях ATM, возьмите за основу ATM-функции из Wmsock. Пользователям TCP/IP следует иметь в виду, что сети ATM можно сконфигурировать для эмуляции TCP/IP, и этот механизм работает довольно хорошо,

стественно, 3 Де сь мы привели далеко не все факторы, учитываемые при Разработке сетевого приложения

120

ЧАСТЬ II Интерфейс прикладного программирования Winsock

\

Резюме

В этой главе мы обсудили основные характеристики, которые обязательно нужно учитывать при выборе базово1 о сетевого транспорта для проектируемого приложения Мы рассмотрели, как программным путем получить список установленных в системе поставщиков транспорта и информацию об определенном свойстве протокола И наконец, дали рекомедации как создать сокет для любого сетевого транспорта с помощью параметров функции WSASocket или socket, а также опрашивать запись каталога транспортов функцией WSAEnumProtocols и передавать структуру WSAPROTOCOLJNFO функции WSASocket

В следующей главе мы расскажем о способах адресации для всех широко распространенных протоколов

Г Л А В А

Семейства адресов и разрешение имен

Для связи средствами Winsock важны механизмы адресации рабочих станций в конкретных протоколах В этой главе рассматриваются протоколы, поддерживаемые Winsock, а также порядок разрешения адресов разных семейств каждым протоколом В Winsock 2 реализовано несколько новых независимых от протокола функций, которые можно использовать с сокетами любых семейств адресов Впрочем, в большинстве случаев у каждого семейства свой механизм разрешения адресов с помощью функции либо через параметр, переданный функции getsockopt

Материал этой главы содержит лишь основные понятия, рассказывает о формировании структуры адресов для каждого семейства протоколов В главе 10 рассматриваются функции регистрации и разрешения имен, оповещающие о службе данного семейства протоколов (это не совсем то же, что разрешение имени) Там же вы найдете дополнительную информацию о различиях между прямым и обычным разрешением имен и оповещением о службе

Для каждого семейства имен мы рассмотрим основы адресации компьютера в сети Затем покажем, как создать сокет для каждого семейства Кроме этого, будет описана специфика каждого протокола в методике разрешения имен

ПротрколIP

Internet Protocol (IP) широко используется в Интернете, поддерживается большинством ОС и применяется как в локальных (local area networks, LAN), так и в глобальных сетях (wide area networks, WAN) IP не требует установления соединения и не гарантирует доставку данных Поэтому для передачи данных поверх IP используются два протокола более высокого уровня TCPиUDP

Протокол TCP

ransrmssion Control Protocol (TCP) реализует связь с установлением соеди- ения, обеспечивает надежную безошибочную передачу данных между двумя компьютерами Когда приложения связываются по TCP, осуществляется Ртуальное соединение исходного компьютера с целевым, после чего меж-

У ними возможен двунаправленный обмен данными

122

ЧАСТЬ II Интерфейс прикладного программирования Winsock

ПротоколUDP

Связь без установления соединения выполняется при помощи User Datagram Protocol (UDP). He гарантируя надежности, UDP может осуществлять передачу данных множеству адресатов и принимать данные от множества источников. Например, данные, отправляемые клиентом на сервер, передаются немедленно, независимо от того, готов ли сервер к приему. При получении данных от клиента, сервер не подтверждает их прием. Данные передаются в виде дейтаграмм.

И TCP, и UDP передают данные по IP, поэтому обычно говорят об использовании TCP/IP или UDP/IP. В Winsock для IP-соединений предусмотрено семейство адресов AFJNET, определенное в файлах Winsock.h и Winsock2.h.

Адресация

При использовании IP компьютерам назначается IP-адрес, состоящий из 32 бит, официально называемый IP-адресом версии 4 (IPv4). Для взаимодействия с сервером по TCP или UDP клиент должен указать IP-адрес сервера и номер порта службы. Чтобы прослушивать входящие запросы клиента, сервер также должен указать IP-адрес и номер порта. В Winsock IP-адрес и порт службы задают в структуре SOCKADDRJN-.

struct sockaddr_in

 

{

 

short

sin_family;

u_short

sin_port;

struct in_addr

sin_addr;

char

sin_zero[8];

Поле sinjamily должно быть равно AFJNET: этим Winsock сообщают об использовании семейства адресов IP.

IP версии 6

IP версии б — обновленная спецификация, позволяющая использовать большее адресное пространство. Оно понадобится в недалеком будущем, когда возможности IP4 будут исчерпаны. Множество заголовков файлов Winsock содержит условное описание структур IPv6, однако ни одна из 32-битных платформ, включая Windows 2000, не обеспечивает работу сетевого стека IPv6. Исследователи из Microsoft Research представили экспериментальный стек IPv6 по адресу http://research.microsoft.com/ msripv6/. Впрочем, он не поддерживается, а потому здесь мы не будем обсуждать особенности версии 6.

Поле sin_port задает, какой коммуникационный порт TCP или UDP будет использован для идентификации службы сервера. Приложения должны быть очень внимательны при выборе порта, поскольку некоторые доступные порты зарезервированы для использования популярными службами: такими, как File Transfer Protocol (FTP) и Hypertext Transfer Protocol (HTTP). Эти порты

Г Л А ВА 6 Семейства адресов и разрешение имен

il23

обслуживаются и распределяются центром Internet Assigned Numbers Authority (IANA), ИХ описание см. в RFC 1700. По сути, номера портов делят на три категории: стандартные, зарегистрированные и динамические и (или) частные порты. Диапазоны портов:

щ0-Ю23 — управляются IANA и зарезервированы для стандартных служб;

щ1024-49151 — зарегистрированы IANA и могут использоваться процессами и программами;

являются динамическими и (или) частными.

Во избежание накладок с портами, уже занятыми системой или другим приложением, ваша программа должна выбирать зарегистрированные порты в диапазоне 1024-49151- Порты 49152-65535 также можно задействовать свободно — с ними не связаны никакие стандартные службы. Если при использовании API-функции bind ваше приложение попытается выбрать порт, уже занятый другим приложением на узле, то система вернет ошибку WSAEADDRINUSE. Подробнее о процедуре привязки к порту в Winsock — в главе 7.

Поле sin_addr структуры SOCKADDRJN хранит IP-адрес в 4-байтном виде с типом unsigned long int. В зависимости от того, как это поле использовано, оно может представлять и локальный, и удаленный IP-адрес. IP-адреса обычно задают в точечной нотации: a.b.c.d. Здесь каждая буква представляет число для каждого байта и задается слева направо (все четыре байта с типом unsigned long int). И наконец, поле sinjzero играет роль простого заполнителя, чтобы структура SOCKADDRJN по размеру равнялась структуре

SOCKADDR.

Полезная вспомогательная функция inet_addr преобразует IP-адрес из точечной нотации в 32-битное длинное целое без знака:

unsigned long inet_addr( const char FAR *cp

);

Поле ср является строкой, заканчивающейся нулевым символом, здесь задается IP-адрес в точечной нотации. Заметьте, что эта функция в качестве результата возвращает IP-адрес, представленный 32-битным числом с сетевым порядком следования байт (network-byte order). Краткое описание этого порядка см. в разделе «Порядок байт».

Специальные адреса

В некоторых ситуациях на поведение сокета влияют два специальных 1Р-ад- Реса. Специальный адрес INADDR_ANY позволяет серверному приложению слушать клиента через любой сетевой интерфейс на несущем компьютере.

бычно приложения сервера используют этот адрес, чтобы привязать сокет

клокальному интерфейсу для прослушивания соединений. Если на компьтере несколько сетевых адаптеров, то этот адрес позволит отдельному при-

°жению получать отклики от нескольких интерфейсов.

Второй специальный адрес — INADDR BROADCAST, позволяет широковеЩательно рассылать UDP-дейтаграммы по IP-сети. Для его использования

1 24

ЧАСТЬ II Интерфейс прикладного программирования Winsock

необходимо в приложении задать параметр сокета SO BROADCAST (см также главу 9)

Порядок байт

Разные процессоры в зависимости от конструкции представляют числа в одном из двух порядков байт big-endian или little-endian Например, процессоры Intel х8б представляют многобайтные числа, следуя от менее значимого к более значимому байту (little-endian) Если номер порта и IP-адрес хранятся в памяти компьютера как многобайтные числа, они представляются в системном порядке (host-byte-order) Впрочем, когда IP-адрес или номер порта задаются по сети, стандарты Интернета требуют, чтобы многобайтные значения представлялись от старшего байта к младшему (в порядке bigendian), что обычно называется сетевым порядком (network-byte order)

Есть целый ряд функций для преобразования многобайтных чисел из системного порядка в сетевой и обратно Например, четыре следующих APIфункции преобразуют числа из системного порядка в сетевой

u_long htonl(u_long hostlong),

int WSAHtonK SOCKET s, u_long hostlong,

u_long FAR * lpnetlong

u_short htons(u_short hostshort);

int WSAHtons( SOCKET s,

u_short hostshort, u_short FAR * lpnetshort

);

Параметры hostlong функций htonl и WSAHtonl — четырехбайтные числа с системным порядком следования байт Функция htonl возвращает число с сетевым порядком, a WSAHtonl — число с сетевым порядком через параметр lpnetlong Параметр hostshort функций htons и WSAHtons является двухбайтным числом с системным порядком Функция htons возвращает число, как двухбайтное значение с сетевым порядком, тогда как функция WSAHtons возвращает такое число через параметр lpnetshort

Следующие четыре функции решают обратную задачу переставляют байты из сетевого порядка в системный

u_long ntohl(u_long netlong);

int WSANtohl( SOCKET s, u_long netlong,

u_long FAR • lphostlong

Г Л А ВА 6 Семейства адресов и разрешение имен

i 125

u_short ntohs(u_short netshort);

mt WSANtohs( SOCKET s, u_short netshort,

u_short FAR • lphostshort

);

А сейчас продемонстрируем, как создать структуру SOCKADDRJN при помощи уже описанных функций inet_addr и htons.

SOCKADDR_IN InternetAddr,

INT nPortld = 5150;

InternetAddr.sin_family = AF_INET,

//Преобразование адреса 136.149.3.29 из десятично-точечной нотации в

//4-байтное целое число и присвоение результата sm_addr

InternetAddr.sin_addr s_addr = inet_addr("136.149.3 29'),

//Переменная nPortld хранится в системном порядке. Преобразование

//nPortld к сетевому порядку и присвоение результата sm_port.

InternetAddr.sin_port = htons(nPortld);

Теперь подготовим сокет для соединения по TCP или UDP.

Создание сокета

Создание IP-сокета позволит приложениям осуществлять подключение через TCP, UDP и протоколы IP Для открытия IP-сокета при помощи протокола TCP, вызовите функцию socket или WSASocket с семейством адресов AFJNET и типом сокета SOCK_STREAM, а также присвойте значение 0 полю протокола

s = socket(AF_INET, SOCK_STREAM, 0),

s = WSASocket(AF_INET, SOCK.STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED),

Чтобы открыть IP-сокет при помощи протокола UDP, вместо SOCKSTREAM укажите тип сокета SOCKDGRAM в функции socket или WSASocket Также можно открывать сокет для связи непосредственно по IP — для этого задайте тип сокета SOCK_RAW Подробнее об этом параметре — в главе 13

Разрешение имен

Для подключения к узлу по IP Winsock-приложение должно знать IP-адрес этого узла, сложный для запоминания пользователем Большинство людей более охотно обращаются к компьютерам при помощи легко запоминаемых имен узлов, а не IP-адресов В Winsock предусмотрено две функции для разРешения имени в IP-адрес

126

ЧАСТЬ II Интерфейс прикладного программирования Winsock

Функции gethostbyname и WSAAsyncGetHostByName отыскивают в базе данных узла сведения об узле, соответствующие его имени Обе функции возвращают структуру HOSTENT

struct hostent

char

FAR *

 

h_name,

char FAR • FAR • h.aliases,

short

 

 

h.addrtype,

short

 

 

h_length,

char

FAR *

FAR *

h_addrj.ist,

Поле hname является официальным именем узла Если в сети используется доменная система имен (Domain Name System, DNS), в качестве имени сервера будет возвращено полное имя домена (Fully Qualified Domain Name, FQDN) Если в сети применяется локальный файл узлов (hosts, lmhosts) — это первая запись после IP-адреса Поле h_ahases — массив, завершающийся нулем (null-terminated array) дополнительных имен узла Поле b_add? type представляет возвращаемое семейство адресов Поле hjength охире-црпяег длину в байтах каждого адреса из поля h_addrjist Поле h_addrjist — массив, завершающийся 0 и содержащий IP-адреса узла (Узел может иметь несколько IP-адресов) Каждый адрес в этом массиве представлен в сетевом порядке Обычно приложение использует первый адрес из массива Впрочем, при получении нескольких адресов, приложение должно выбирать адрес случайным образом из числа доступных, а не упорно использовать первый

API-функция gethostbyname определена так

struct hostent FAR * gethostbyname ( const char FAR * name

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

WSAAsyncGetHostByName — асинхронная версия функции gethostbyname,

оповещающая приложение о завершении своего выполнения с помощью сообщений Windows

HANDLE WSAAsyncGetHostByName( HWND hWnd,

unsigned int wMsg, const char FAR * name, char FAR * buf,

Int buflen

Параметр hWnd дескриптор окна, которое получит сообщение по завершении выполнения асинхронного запроса. Параметр wMsg Windows-

•ГЛАВА 6 Семейства адресов и разрешение имен

'127

сообщение, которое будет возвращено по завершении выполнения асинхронного запроса Параметр пате— дружественное имя искомого узла Параметр buf— указатель на область данных, куда помещается HOSTENT Этот буфер должен быть больше структуры HOSTENT и иметь размер, определен-

ный BMAXGETHOSTSTRUCT

Стоит упомянуть еще две функции поиска сведений об узле gethostbyaddr и WSAAsyncGetHostByAddr Они полезны, когда вы знаете IP-адрес узла и хотите найти его понятное пользователю имя Функция gethostbyaddr определена так

struct HOSTENT FAR • gethostbyaddr( const char FAR • addr,

int len, mt type

),

Параметр addr — указатель на IP-адрес в сетевом порядке Параметр len задает длину параметра addr в байтах Параметр type должен иметь значение AFJNET (IP-адрес) WSAAsyncGetHostByAddr — асинхронная версия функции gethostbyaddr

Номера портов

Помимо IP-адреса удаленного компьютера для подключения к службе на локальном или удаленном компьютере приложение должно знать номер порта службы При использовании TCP и UDP приложение решает, через какой порт связаться Существуют стандартные номера портов, зарезервированные для служб сервера, поддерживающих протоколы более высокого уровня, чем TCP Например, порт 21 зарезервирован для FTP, 80 — для HTTP Как уже упоминалось, стандартные службы обычно используют порты 1-1023 Поэтому если вы разрабатываете TCP-приложение, которое не использует ни одну из известных служб, старайтесь задействовать порты с номером больше 1023 Вы можете узнать номера портов, используемых стандартными службами, вызвав функцию getservbyname или WSAAsyncGetServByName Эти функции просто извлекают статическую информацию из файла с именем services В Windows 95 и Windows 98 файл служб расположен в папке %WINDOWS%, а в Windows NT и Windows 2000 - в %WINDOWS%\System32\Dnvers\Etc Функция getservbyname определена так

struct servant FAR * getservbyname( const char FAR * name,

const char FAR * proto

Параметр name представляет имя искомой службы Например, если вы пытаетесь найти порт, используемый FTP, присвойте параметру пате указатель на строку «ftp» Параметр proto иногда ссылается на строку, указывающую протокол, под которым зарегистрирована служба из параметра пате Функция WSA- •AsyncGetServByName — асинхронная версия getsen b)>name

В Windows 2000 применен новый динамический метод регистрации и запроса информации о службах для TCP и UDP Серверные приложения могут за-