ГлавнаяarrowСистемное программированиеarrow26. Программирование TCP/IP в Windows

26. Программирование TCP/IP в Windows

На предыдущей работе рассматривались механизмы обмена данными между процессами для случаев, когда оба процесса были запущены на одном компьютере. Но если требуется организовать взаимодействие процессов, работающих на разных компьютерах, объединённых в сеть, то рассмотренные механизмы использовать невозможно. В локальных и глобальных сетях существует два принципиально разных способа передачи данных.
Первый из них предполагает посылку пакетов данных от одного узла другому без получения подтверждения о доставке и даже без гарантии того, что передаваемые пакеты будут получены в правильной последовательности. Примером такого протокола может служить протокол UDP (User Datagram Protocol), который используется в сетях TCP/IP, или протокол IPX, который является базовым в сетях Novell NetWare. Основные преимущества датаграммных протоколов заключаются в высоком быст­родействии и возможности широковещательной передачи данных, когда один узел отправляет сообщения, а другие их получают, причем все одновременно.
Второй способ передачи данных предполагает создание канала передачи данных между двумя различными узлами сети. При этом канал создается средствами датаграммных протоколов, однако доставка пакетов в канале является гарантированной. Пакеты всегда доходят в целостности и сохранности, причем в правильном порядке, хотя быстродействие получается в среднем ниже за счет посылки подтверждений. Примерами протоколов, использующих каналы связи, могут служить протоколы TCP и SPX.
Для передачи данных с использованием любого из перечисленных выше способов каждое приложение должно создать объект, который называется сокетом. На сегодняшний день сокеты являются стандартным механизмом обмена данными через сеть. Техно­логия сокетов лежит в основе Интернета, и в наши дни эту технологию поддер­живает большинство компьютеров. По своему назначению сокет больше всего похож на идентификатор файла, который нужен для выполнения над файлом операций чтения или записи. Прежде чем приложение, запущенное на узле сети, сможет выполнять передачу или прием данных, оно должно создать сокет и проинициализировать его, указав некоторые параметры: IP-адрес, связанный с сокетом номер порта, для которого будут выполняться операции передачи данных, а также тип сокета. Что касается последнего параметра (тип сокета), то существуют сокеты двух типов. Первый тип предназначен для передачи данных в виде датаграмм, второй - с использованием каналов связи. Каждому сокету соответствует уникальный номер порта. Некоторые номера зарезервированы для так называемых «хорошо известных» служб.
Сервер создает сокет, которому соответствует «хорошо известный» номер пор­та. После этого он начинает ожидать поступления запросов клиентов через этот порт. Чтобы соединиться с сервером, клиент создает сокет, которому соот­ветствует случайно выбранный системой, никем не занятый номер порта. После этого устанавливается связь между этими двумя сокетами.
На самом деле «хорошо известный» номер порта сервера не используется для реального обмена данными. При поступлении от клиента запроса на соединение через «хорошо известный» порт система перехватывает запрос и автоматически создает на сервере новый сокет, которому соответствует случайно выбранный, никем не занятый номер порта, а затем соединяет этот новый сокет с сокетом клиен­та. После чего обмен данными осуществляется с использованием нового сокета. Такая подмена сокета сервера никак не влияет на работу клиента. Клиент полу­чает возможность взаимодействия с сервером, и вместе с тем сервер оставляет свой «хорошо известный» сокет свободным для поступления запросов на соеди­нение от других клиентов.
2 Функции для работы с сокетами
Перед тем как начать работу с сокетами в Windows нужно инициализировать библиотеку Windows Sockets (wsock32.dll) и добавить в модуль приложения директиву препроцессора: #include
Для инициализации необходимо вызвать функцию WSAStartup().
В случае успеха функция возвращает нулевое значение.
В операционных системах Microsoft Windows 95 и Microsoft Windows NT версии 3.51 встроена система Windows Sockets версии 1.1, поэтому именно это значение задано при вызове функции WSAStartup().
Перед тем как завершить свою работу, приложение должно освободить ресурсы, полученные у ОС для работы с Windows Sockets. Для выполнения этой задачи приложение должно вызвать функцию WSACleanup.
Эта функция может возвратить ноль при успехе или значение SOCKET_ERROR в случае ошибки.
После инициализации интерфейса Windows Sockets приложение должно создать один или несколько сокетов, которые будут использованы для передачи данных. Сокет создается с помощью функции socket()
Для освобождения ресурсов приложение дотжно закрывать сокеты, которые ему больше не нужны, вызывая функцию closesocket
Для выполнения преобразований из обычного формата в сетевой и обратно в ин­терфейсе Windows Sockets предусмотрен специальный набор функций. В частности, для заполнения поля sin_pon нужно использовать функцию htons(), выполняющую пре­образование данных в сетевой формат. Входной параметр функции - номер порта в обычном формате, а выходной - в сетевом.
Если вам известен адрес в виде четырех десятичных чисел, разделенных точкой “000.000.000.000” (именно так его вводит пользователь), то вы можете заполнить поле IP-адреса при помо­щи функции inet_addr(). Обратное преобразование IP-адреса в текстовую строку можно при необходимое легко выполнить с помощью функции inet_ntoa().
После того как вы подготовили структуру SOCKADDR_IN, записав в нее параметры сокета (в частности, адрес), следует выполнить привязку адреса к сокету при помощи функции bind():
В случае ошибки функция возвращает значение SOCKET_ERROR.
Если требуется передавать датаграммные сообщения при помощи протокола негарантированной доставки UDP, то канал связи не нужен. Сразу после создания сокетов и их инициализации можно приступать к передаче данных. Но для передачи дан­ных с использованием протокола TCP необходимо создать канал связи.
Процедура создания канала связи со стороны сервера.
Прежде всего, надо переключить сокет в режим приема для выполнения задания соединения с клиентом при помощи функции listen().
Далее необходимо выполнить ожидание соединения. Это можно выполнить различными способами. Первый способ заключается в циклическом вызове функции accept() до тех пор, пока не будет установлено соединение. Ожидание соединения в цикле приводит к тому, что приложение не будет реагировать на запросы пользователя до момента соединения. Поэтому есть более удобный способ, основанный на использовании расширении программного интерфейса Windows Socket, предназначенного для выполнения асинхрон­ных операций.
Приложение может вызвать один раз функцию WSAAsyncSelect(), указав ей, что при получении запроса на установку соединения функция окна вашего приложения должно получить сообщение:
#define WSA_ACCEPT (WM_USER +1);
В данном случае обработчик сообщения вначале вызывает функцию accept(), выполняющую создание канала передачи данных. После этого функция WSAAsyncSelect() вызывается еще один раз для того, чтобы установить асинхронную обработку приема данных от удаленного клиента, а также обработку ситуации разрыва канала связи.
Процедура создания канала связи со стороны клиента.
Вначале с помощью функции socket() необходимо создать сокет клиента. Затем выполняет­ся заполнение адресной информацией структуры SOCKADDR_IN. В этой структуре необходимо задать известный порт сервера, и его IP-адрес. Адрес задаётся при помощи функции inet_addr().
После заполнения структуры с адресной информацией функция можно устанавливать канал связи с сервером с помощью функции connect().
После того как канал создан, можно начинать передачу данных. Для передачи данных при помощи протокола гарантированной доставки TCP нужно воспользоваться функциями send() и recv(), которые входят в программный интерфейс Widows Sockets.
3 Запуск сервера и запуск клиента
Теперь следует полностью рассмотреть процедуры, которые должны выполнить приложения сервер и клиент, чтобы выполнять обмен данными по сети.
Запуск сервера.
1. При помощи функции socket() создать новый сокет. При этом необходимо ука­зать желаемый тип сокета. Большинство прикладных программ используют сокеты с адресацией в стиле Интернета и гарантией доставки пакетов (то есть сокеты TCP, а не UDP).
2. Присвоить значения полям структуры SOCKADDR_IN. Эта структура содержит информацию о типе адресации, допустимых адресах клиентов и номере пор­та.
3. При помощи функции bind() поставьте в соответствие сокету, созданному на шаге 1, структуру SOCKADDR_IN, заполненную на шаге 2.
4. Перейти в режим ожидания соединения.
5. Чтобы принять запрос на соединение, воспользоваться функцией WSAAsyncSelect().
6. Добавить определение сообщений WSA_ACCEPT, WSA_NETEVENT в заголовочном файле модуля, создать в объявлении класса карту сообщений и написать их обработчики.
7. Обработчик сообщения WSA_ACCEPT чтобы принять запрос на соединение, должен использовать функцию accept(). Эта функ­ция возвращает новый сокет, соответствующий соединению. Если при этом надо узнать адрес клиента, передайте вызову accept() в качестве аргументов структуру SOCKADDR_IN и ее длину. Если не интересует, каким адресом обладает клиент, передайте в качестве этих параметров значения NULL и ноль.
8. Обработчик сообщения WSA_NETEVENT чтобы принять данные, должен использовать функцию recv().
9. Для передачи данных клиенту следует использовать функцию send().
10. При завершении работы следует освободить ресурсы, полученные у ОС для работы с Windows Sockets и закрыть используемые сокеты.
Запуск клиента.
1. При помощи функции socket() создать новый сокет.
2. Присвоить значения полям структуры SOCKADDR_IN. В структуре указать информацию о типе адресации, адресе сервера и номере пор­та сервера.
3. При помощи функции connect() установить соединение с сервером и реализовать асинхронный приём данных.
4. Добавить определение сообщения WSA_NETEVENT в заголовочном файле модуля, создать в объявлении класса карту сообщений и написать его обработчик.
5. Написать обработчик сообщения WSA_NETEVENT чтобы принять данные от сервера.
6. Для передачи данных серверу следует использовать функцию send():
7. При завершении работы следует освободить ресурсы, полученные у ОС для работы с Windows Sockets и закрыть используемые сокеты.
 

Hosted by uCoz