Пиши Дома Нужные Работы

Обратная связь

Коммуникационная модель клиент-сервер

Лабораторная работа № 9 Изучение принципов работы с RAW-сокетами

Цель работы: Изучить:

- возможности реализации архитектуры клиент-сервер на основе интерфейса сокетов Windows Sockets API;

- типы сокетов TCP/IP;

- основные методики и API-функции для разработки сетевых приложений с использованием Winsock.

Постановка задачи

1.Изучить методические указания к лабораторной работе, материалы лекций и рекомендуемую литературу.

2.Разработать консольное приложение для работы с адресами сокетов.

3.Разработать консольное клиент-серверное приложение, демонстрирующее взаимодействие на основе потоковых сокетов.

4.Разработать консольное клиент-серверное приложение, демонстрирующее взаимодействие на основе дейтаграммных сокетов.

Методические указания

 

Понятие сокета

Сокет (Socket - гнездо, разъем) - абстрактное программное понятие, используемое для обозначения в прикладной программе конечной точки канала связи с коммуникационной средой, образованной вычислительной сетью.

Соединяя вместе два сокета, можно передавать данные между разными процессами (локальными и удаленными). Реализация сокетов обеспечивает инкапсуляцию протоколов сетевого и транспортного уровней.

Интерфейс, используемый приложением при взаимодействии с программным обеспечением транспортного протокола, называется интерфейсом прикладного программирования (Application Programming Interface - API). API интерфейс определяет набор операций, которые могут быть выполнены приложением при взаимодействии с программным обеспечением протокола.

Функции прикладного программного интерфейса сокетов (Sockets API) обеспечивают идентификацию конечных точек соединения, установку соединения, отправку сообщений, ожидание входящих сообщений, разрыв соединения и обработку ошибок.



Протоколы и семейства адресов

Важнейшим преимуществом сокетов Windows является предоставление единого независимого интерфейса сетевого программирования (Sockets API) для различных сетевых протоколов.

Платформы Win32 поддерживают разнообразные сетевые стеки протоколов : TCP/IP, IPX/SPX, NetBIOS/SMB, AppleTalk, ATM, Infrared Sockets. Каждому из них соответствует свое семейство адресов сокетов. Напрмер, TCP/IP соответствует семейство адресов AF_INET, IPX/SPX – AF_NS, ATM –AF_ATM и т.д.

Семейство адресов – важнейший параметр сокета. Он указывает используемый в настоящее время протокол и ограничивает применение других параметров сокета.

Мы рассмотрим адресацию сокетов только для стека протоколов TCP/IP, как самого распространенного на сегодняшний день.

Адрес сокета при использовании протоколов TCP/IP задает следующий набор значений:

- номер сети;

- номер конечного узла;

- номер порта прикладной службы.

Инициализация Winsock

Перед вызовом любой функции Winsock необходимо загрузить соответствующую версию библиотеки Winsock. Для использования в приложении Winsock 2 необходимо подключить библиотеку Ws2_32.lib и заголовочный файл Winsock2.h.

Имена новых или обновленных API-функций, добавленные в Winsock 2, начинаются с префикса WSA.

Инициализацию Winsock выполняет функция WSAStartup:

int WSAStartup(

WORD wVersionRequested,

LPWSADATA IpWSAData);

Параметр wVersionRequested задает версию загружаемой библиотеки Winsock. На современных платформах Win32 используется версия 2.2. Для получения значения параметра wVersionRequested можно использовать макрос MAKEWORD(2, 2) либо значение 0х0202.

Параметр IpWSAData — указатель на структуру LPWSADATA, которая при вызове функции WSAStartup заполняется сведениями о версии загружаемой библиотеки.

 

По завершении работы с библиотекой Winsock необходимо вызвать функцию WSACleanup для выгрузки библиотеки и освобождения ресурсов:

int WSACleanup (void);

Адресация сокетов для протокола IP

Для задания IP-адреса и номера порта службы используется структура SOCKADDR_IN. Она определена в include-файле in.h следующим образом:

struct sockaddr_in {

short sin_family;

u_short sin_port;

struct in_addr sin_addr;

char sin_zero[8];

};

Поле sin_family при использовании семейства адресов IP должно быть равно AF_INET.

Поле sin_port задает, какой коммуникационный порт будет использован для идентификации службы.

Поле sin_addr структуры SOCKADDR_IN хранит IP-адрес в 4-байтном виде с типом unsigned long int. В зависимости от того, как это поле использовано, оно может представлять и локальный, и удаленный IP-адрес.

Поле sin_zero играет роль заполнителя, чтобы структура SOCKADDR_IN по размеру равнялась структуре SOCKADDR.

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

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

Второй специальный адрес – INADDR_BROADCAST, позволяет широковещательно рассылать UDP – дейтаграммы по IP – сети. Для его использования необходимо в приложении задать параметр сокета SO_BROADCAST.

Порядок байт

В памяти компьютера IP-адрес и номер порта представляются в системном порядке (host-byte-order). Для процессоров Intel Pentium это порядок от менее значимого к более значимому байту (обратный). Стандарты Internet требуют, чтобы многобайтные значения передавались от старшего байта к младшему, что называется сетевым порядком (network-byte order) или прямым порядком следования байтов. Поэтому существует необходимость преобразования чисел из одной формы в другую. Для этого предназначен целый ряд функций. Например, функции htonl, WSAHtonl, htons, WSAHtons преобразуют числа из системного порядка в сетевой. Функции ntohl, WSANtohl, ntohs, WSANtohs решают обратную задачу.

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

unsigned long inet_addr( const char FAR *cp);

Поле ср - строка, заканчивающаяся нулевым символом, в которой задается IP-адрес в точечно-десятичной нотации.

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

В Winsock предусмотрено две функции для разрешения имени в IP-адрес.

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

struct hostent

{

char FAR * h_name;

char FAR * FAR * h_aliases;

short h_addrtype;

short h_length;

char FAR * FAR * h_addr_list;

};

Поле h_name является официальным именем узла. Если в сети используется доменная система имен (Domain Name System, DNS), в качестве имени сервера будет возвращено полное имя домена (Fully Qualified Domain Name, FQDN). Если в сети для разрешения имен применяется локальный файл (hosts, lmhosts) - это первая запись после IP- адреса.

Поле h_aliases – массив дополнительных имен узла, завершающийся нулем.

Поле h_addrtype – возвращаемое семейство адресов.

Поле h_length определяет длину в байтах каждого адреса из поля h_addr_list.

Поле h_addr_list – массив, завершающийся 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);

Параметры hWind – дескриптор окна, которое получит сообщение по завершении выполнения асинхронного запроса. Параметр wMsg –Windows-сообщение, которое будет возвращено по завершении выполнения асинхронного запроса. Параметр name - дружественное имя искомого узла. Параметр buf – указатель на область данных, куда помещается HOSTENT. Этот буфер должен быть больше структуры HOSTENT и иметь размер, определенный в MAXGETHOSTSTRUCT.

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

struct HOSTENT FAR * gethostbyaddr(

const char FAR * addr,

int len,

int type);

Параметр addr – указатель на IP–адрес в сетевом порядке.

Параметр len задает длину параметра addr в байтах.

Параметр type должен иметь значение AF_INET (IP-адрес).

Функция WSAAsyncGetHostByAddr – асинхронная версия функции gethostbyaddr.

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

Приложения должны быть внимательны при выборе номера порта, поскольку некоторые доступные порты зарезервированы для использования популярными службами, такими как FTP, HTTP и т.д. Эти порты обслуживаются и распределяются центром Internet Assigned Numbers Authority (IANA), их описание содержится в RFC 1700.

Номера портов разделяются на 3 категории (стандартные, зарегистрированные и динамические и/или частные):

- Номера от 0 до 1023 зарезервированы для стандартных служб.

- Порты с номерами от 1024 до 49151 являются регистрируемыми. Они используются для различных целей.

- Порты с номерами от 49152 до 65535 представляют собой динамические и частные порты.

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

Узнать номера портов, используемых стандартными службами, можно вызвав функцию getservbyname или WSAAsyncGetServByName. Эти функции извлекают статическую информацию из файла services, расположенного в папке %WINDOWS%\System32\Drivers\Etc

Функция getservbyname определена так:

struct servent FAR *getservbyname(

const char FAR *name,

const char FAR *proto);

Параметр name представляет имя искомой службы.

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

Функция WSAAsyncGetServByName – асинхронная версия getservbyname.

Типы сокетов

Существуют три основных типа сокетов: потоковые, дейтаграммые и сырые.

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

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

Сырые сокеты (необрабатываемые, простые) – это сокеты, которые принимают пакеты сетевого уровня в обход протоколов транспортного уровня и отправляют их непосредственно приложению.

Коммуникационная модель клиент-сервер

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

 

 

 

Рис. 1 Блок-схема взаимодействия потоковых сокетов

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

Сокет идентифицирует пару, состоящую из IP-адреса и номера порта. Пара сокетов идентифицирует четыре компонента: адреса и номера портов отправителя и получателя.

Обращение к сокетам осуществляется при помощи соответствующих дескрипторов сокетов. В Win32 сокет отличается от описателя файла и представлен отдельным типом – SOCKET.

Сокет создается одной из двух функций:

SOCKET WSASocket (

int af,

int type,

int protocol,

LPWSAPROTOCOL_INFO IpProtocolInfo,

GROUP g,

DWORD dwFlags);

или SOCKET socket ( int af, int type, int protocol);

Первый параметр – af, определяет семейство адресов протокола и ограничивает применение второго и третьего параметров. Он может принимать значения AF_UNIX, AF_INET, AF_OSI, AF_NS, AF_NETBIOS, AF_APPLETALK, AF_ATM и т.д.. Значение AF_INET позволяет взаимодействовать через объединенную сеть по IP-адресам.

Параметр type - это тип сокета для данного протокола. Для протокола TCP/IP он может принимать одно из следующих значений: SOCK_STREAM (транспортный протокол TCP, ориентированная на соединение надежная связь), SOCK_DGRAM (транспортный протокол UDP, ненадежная дейтаграммная связь), SOCK_RAW (простые сокеты).

Третий параметр — protocol, указывает конкретный протокол. Если этот параметр равен 0, это означает, что задействуется протокол по умолчанию для выбранных значений семейства адресов и типа. Для протокола TCP задается значение IPPROTO_IP, для протокола UDP – IPPROTO_UDP, для простых сокетов – IPPROTO_RAW или IPPROTO_ICMP.

Если в функции WSASocket указать константу FROM_PROTOCOL_INFO во всех трех параметрах (af, type и protocol) — для них будут использоваться значения из переданной структуры WSAPROTOCOL_INFO.

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

WSA_FLAG_OVERLAPPED;

WSA_FLAG_MULTIPOINT_C_ROOT;

WSA_FLAG_MULTIPOINT_C_LEAF;

WSA_FLAG_MULTIPOINT_D_ROOT;

WSA_FLAG_MULTIPOINT_D_LEAF.

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

В случае успеха функция socket() возвращает дескриптор сокета, представляющий собой целое число, в случае неудачи возвращается –1.

Проверка и обработка ошибок

Большинство функций Winsock при успешном завершении возвращают 0, а в случае ошибки - значение SOCKET_ERROR, которое равно –1.

Для получения кода ошибки можно использовать функцию

int WSAGetLastError (void);

Функция возвращает код последней ошибки. Коды ошибок описаны в Winsock.h или Winsock2.h (в зависимости от версии)

Серверные API-функции

Первый шаг после создания сокета — привязка сокета данного протокола к его стандартному адресу функцией bind. Второй — перевод сокета в режим прослушивания функцией listen. И наконец, сервер должен принять соединение клиента функцией accept или WSAAccept.

Фукция bind.

int bind (

SOCKET s,

const struct sockaddr FAR* name,

int namelen);

Параметр s задает дескриптор локального сокета, создаваемый функцией socket(), на котором ожидаются соединения клиентов.

Второй параметр – указатель на структуру, в которой хранится адрес сокета, соответствующий стандартам используемого протокола. Его нужно привести к типу struct sockaddr. В заголовочном файле Winsock определен тип SOCKADDR, соответствующий структуре struct sockaddr.

Третий параметр задает размер переданной адресной структуры, зависящий от протокола.

В случае успеха функция bind() возвращает 0. В случае ошибки - значение SOCKET_ERROR (т.е. -1). Самая распространенная ошибка при вызове bind — WSAEADDRINUSE. В случае использования TCP/IP это означает, что с локальным IP-интерфейсом и номером порта уже связан другой процесс, или они находятся в состоянии TIME_WAIT. При повторном вызове bind дляуже связанного сокета возвращается ошибка WSAEFAULT.

Функция listen.

Для перевода сокета в состояние ожидания входящих соединений используется API-функция listen().

int listen( SOCKET s, int backlog);

Первый параметр s — дескриптор сокета.

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

Функции accept.

Прототип функции accept:

SOCKET accept(

SOCKET s,

struct sockaddr FAR* addr,

int FAR* addrlen );

Параметр s — связанный сокет в состоянии прослушивания.

Второй параметр — адрес действительной структуры SOCKADDR_IN.

Параметр addrlen — ссылка на длину структуры SOCKADDR_IN.

Вызов accept обслуживает первый находящийся в очереди запрос на соединение. По его завершении структура addr будет содержать сведения об IP-адресе клиента, отправившего запрос, а параметр addrlen — размер структуры.

Кроме того, accept возвращает новый дескриптор сокета, соответствующий принятому клиентскому соединению. Для всех последующих операций с этим клиентом должен применяться новый сокет. Исходный прослушивающий сокет используется для приема других клиентских соединений и продолжает находиться в режиме прослушивания.

В Winsock 2 есть функция WSAAccept, способная устанавливать соединения в зависимости от результата вычисления условия.

Клиентские API-функции

Установление соединения осуществляется вызовом connect или WSAConnect. Прототип функции connect:

int connect (

SOCKET s,

const struct sockaddr FAR* name,

int namelen);

Параметр s — действительный ТСР-сокет для установления соединения, пате — структура адреса сокета (SOCKADDR_IN) для TCP, описывающая сервер к которому подключаются, namelen — длина переменной пате.

Если на компьютере, к которому вы подключаетесь, не запущен процесс, прослушивающий данный порт, функция connect вернет ошибку WSAECONNREFUSED. Другая ошибка — WSAETIMEDOUT, происходит, когда вызываемый адресат недоступен, например, из-за отказа коммуникационного оборудования на пути к узлу или отсутствия узла в сети.






ТОП 5 статей:
Экономическая сущность инвестиций - Экономическая сущность инвестиций – долгосрочные вложения экономических ресурсов сроком более 1 года для получения прибыли путем...
Тема: Федеральный закон от 26.07.2006 N 135-ФЗ - На основании изучения ФЗ № 135, дайте максимально короткое определение следующих понятий с указанием статей и пунктов закона...
Сущность, функции и виды управления в телекоммуникациях - Цели достигаются с помощью различных принципов, функций и методов социально-экономического менеджмента...
Схема построения базисных индексов - Индекс (лат. INDEX – указатель, показатель) - относительная величина, показывающая, во сколько раз уровень изучаемого явления...
Тема 11. Международное космическое право - Правовой режим космического пространства и небесных тел. Принципы деятельности государств по исследованию...



©2015- 2024 pdnr.ru Все права принадлежат авторам размещенных материалов.