Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ




Методические указания для выполнения лабораторной работы № 7

По курсу «Операционные системы и системное программирование»

 

 

«Сетевое программирование в Windows»

 

Полоцк, 2017



ЦЕЛЬ РАБОТЫ

Создание распределенных сетевых приложений.

КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

Cокеты(sockets) представляют собой высокоуровневый унифицированный интерфейс взаимодействия с телекоммуникационными протоколами.

Свой первый цикл статей я посвящу только одной реализации сокетов - Winsock2. Библиотека Winsock поддерживает два вида сокетов синхронные и асинхронные. Синхронные сокеты задерживают управление на время выполнения операции, а Асинхронные - возвращают его немедленно, продолжая работать в фоновом режиме.

Сокеты, независимо от вида, деляться на три типа: потоковые, сырые(windows их не "держит") и дейтаграммные. Потоковые сокеты работают с установкой соединения, обеспечивая надежную идентификацию обеих сторон и гарантируют целостность и успешность доставки данных,опираються на протокол TCP. Дейтаграммные сокеты работают без установки соединения и не обеспечивают ни идентификации отправителя, ни контроля успешности доставки данных, зато они быстрее потоковых, опираються на протокол UDP. Сырые сокеты, они предоставляют возможность ручного формирования TCP\IP пакетов.

Програмирование сокетов идет поэтапно:
1.Создание сокета
2.Привязка сокета к локальным именам
3.Установка связи
4.Передача данных
5.Закрытие сокета

 

Таблица – Функции по работе с сокетами

Функция

Описание
accept

Принимает входящую попытку соединения на сокете.

AcceptEx

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

bind

Связывает локальный адрес с сокетом.

closesocket

Закрывает существующий сокет

connect

Устанавливает соединение с указанным сокетом

ConnectEx

Устанавливает соединение с указанным сокетом, и (необязательно) посылает данные, как только соединение установлено

DisconnectEx

Закрывает соединение на сокете, и позволяет снова использовать дескриптор этого сокета.

freeaddrinfo

Освобождает информацию об адресе, которая была получена динамически при помощи функции getaddrinfo.

gai_strerror

Помогает сформировать сообщения об ошибках из кодов ошибок типа EAI_*, возвращенных функцией getaddrinfo.

GetAcceptExSockaddrs

Анализирует данные, полученные функцией AcceptEx.

GetAddressByName

Запрашивает пространство имен или устанавливает пространства имен заданные по умолчанию для получения информации о сетевом адресе указанного сетевого сервиса. Этот процесс известен как Разрешение Имен Сервисов (Service Name Resolution).

getaddrinfo

Обеспечивает протоколо-независимую трансляцию имени хоста в его адрес.

gethostbyaddr

Получает информацию о хосте по сетевому адресу.

gethostbyname

Получает из базы данных хостов информацию, соответствующую имени хоста.

gethostname

Получает стандартное имя хоста для локального компьютера

getnameinfo

Обеспечивает разрешение имени из адреса в имя хоста

getpeername

Получает имя одноуровнего (peer) узла сети, с которым соединен сокет

getprotobyname

Получает информацию о протоколе по его имени.

getprotobynumber

Получает информацию о протоколе по его номеру

getservbyname

Получает информацию о сервисе по имени сервиса и протоколу

getservbyport

Получает информацию о сервисе по номеру порта и протоколу

getsockname

Получает локальное имя для сокета.

getsockopt

Получает опции сокета.

htonl

Преобразует порядок байтов u_long из формата хоста в сетевой формат TCP/IP (формат big-endian)

htons

Преобразует порядок байтов u_short из формата хоста в сетевой формат TCP/IP (формат big-endian).

inet_addrv

Преобразует строку, содержащую десятично-точечный адрес протокола Internet (IPv4) в надлежащий адрес для структуры in_addr.

inet_ntoa

Преобразует адрес Internet (IPv4) из сетевого формата в строку, содержащую стандартный десятично-точечный адрес

ioctlsocket

Управляет режимом ввода-вывода сокета

listen

Переводит сокет в состояние ожидания входящих соединений

ntohl

Преобразует порядок байтов u_long из сетевого формата TCP/IP в формат хоста (формат little-endian на процессорах Intel).

ntohs

Преобразует порядок байтов u_short из сетевого формата TCP/IP в формат хоста (формат little-endian на процессорах Intel).

recv

Получает данные от присоединенного или связанного сокета

recvfrom

Получает датаграмму и сохраняет адрес источника

select

Определяет статус одного или нескольких сокетов, ожидая в случае необходимости исполнения синхронного ввода-вывода.

send

Посылает данные на соединенный сокет

sendto

Посылает данные определенному адресату

setsockopt

Устанавливает опции сокета.

shutdown

Запрещает прием или передачу на сокете

socket

Создает сокет и связывает его с определенным сервисом

TransmitFile

Передает данные файла через соединенный сокет.

TransmitPackets

Передает данные из памяти или данные файла через соединенный сокет

WSAAccept

Принимает соединение, основываясь на возвращаемом значении функции условия, обеспечивает качество обслуживания (QoS) спецификаций процесса и разрешает передачу данных соединения.

WSAAddressToString

Преобразует все компоненты структуры SOCKADDR в понятное для человека строковое представление адреса.

WSAAsyncGetHostByAddr

Асинхронно получает информацию о хосте по его адресу

WSAAsyncGetHostByName

Асинхронно получает информацию о хосте по его имени

WSAAsyncGetProtoByName

Асинхронно получает информацию о протоколе по его имени

WSAAsyncGetProtoByNumber

Асинхронно получает информацию о протоколе по его номеру

WSAAsyncGetServByName

Асинхронно получает информацию о сервисе по его имени и номеру порта.

WSAAsyncGetServByPort

Асинхронно получает информацию о сервисе по номеру порта и протоколу.

WSAAsyncSelect

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

WSACancelAsyncRequest

Отменяет незавершенную асинхронную операцию

WSACleanup

Завершает использование Ws2_32.dll.

WSACloseEvent

Закрывает открытый дескриптор объекта события

WSAConnect

Устанавливает соединение с сокетом другого приложения, обменивается данными соединения и определяет необходимое качество обслуживания (QoS), основываясь на указанной структуре FLOWSPEC

WSACreateEvent

Создает новый событийный объект

WSADuplicateSocket

Возвращает структуру, которая может использоваться для создания нового дескриптора общедоступного сокета (сокет может использоваться несколькими процессами).

WSAEnumNameSpaceProviders

Возвращает информацию о доступных пространствах имен

WSAEnumNetworkEvents

Обнаруживает сетевые события для обозначенного сокета, очищает внутренние записи сетевых событий и сбрасывает событийные объекты (необязательно).

WSAEnumProtocols

Получает информацию о доступных транспортных протоколах

WSAEventSelect

Определяет событийный объект, который будет связан с указанным набором FD_XXX сетевых событий.

WSAGetLastError

Возвращает статус ошибки для последней операции, которая завершилась неудачно.

WSAGetOverlappedResult

Получает результаты перекрытой (совместной) операции на указанном сокете.

WSAGetQOSByName

Инициализирует структуру QOS, основываясь на названном шаблоне, или предоставляет буфер для получения доступных имен шаблонов.

  WSAGetServiceClassInfo

 

Получает информацию о классе (схему), имеющую отношение к указанному классу сервиса, от заданного поставщика пространства имен (name space provider).

WSAGetServiceClassNameByClassId

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

WSAHtonl

Преобразует порядок байтов u_long из формата хоста в сетевой формат

WSAHtons

Преобразует порядок байтов u_short из формата хоста в сетевой формат

WSAInstallServiceClass

Регистрирует схему класса сервиса в пространстве имен.

WSAIoctl

Управляет режимом сокета.

WSAJoinLeaf

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

WSALookupServiceBegin

Инициализирует клиентский запрос, основываясь на критериях, содержащихся в структуре WSAQUERYSET.

WSALookupServiceEnd

Освобождает дескриптор, использовавшийся предыдущими вызовами WSALookupServiceBegin и WSALookupServiceNext.

WSALookupServiceNext

Получает информацию о требуемом сервисе.

WSANSPIoctl

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

WSANtohl

Преобразует порядок байтов u_long из сетевого формата в формата хоста.

WSANtohs

Преобразует порядок байтов u_short из сетевого формата в формата хоста.

WSAProviderConfigChange

Уведомляет приложение о смене конфигурации поставщика.

WSARecv

Получает данные от соединенного сокета.

WSARecvDisconnect

Завершает прием на сокете и получает данные разъединения, если сокет является ориентированным на соединение

WSARecvEx

Получает данные от соединенного сокета.

WSARecvFrom

Получает датаграмму и сохраняет адрес источника.

WSARecvMsg

Получает данные и дополнительную управляющую информацию от соединенных и несоединенных сокетов.

WSARemoveServiceClass

Удаляет схему класса сервиса из системного реестра.

WSAResetEvent

Сбрасывает состояние указанного событийного объекта в несигнальное.

WSASend

Посылает данные на соединенный сокет.

WSASendDisconnect

Инициализирует завершение соединения на сокете и посылает данные разъединения.

WSASendTo

Посылает данные определенному адресату, используя перекрываемый ввод-вывод где это возможно.

WSASetEvent

Устанавливает состояние указанного событийного объекта в сигнальное

WSASetLastError

Устанавливает код ошибки.

WSASetService

Регистрирует или удаляет из системного реестра экземпляр сервиса в пределах одного или нескольких пространств имен

WSASocket

Создает сокет, связанный с определенным поставщиком транспортных услуг (transport-service provider).

WSAStartup

Инициализирует использование Ws2_32.dll процессом.

WSAStringToAddress

Преобразует числовую строку в структуру SOCKADDR.

WSAWaitForMultipleEvents

Возвращает значение в том случае, когда один или все указанные событийные объекты находятся в сигнальном состоянии, или когда истекает интервал ожидания (тайм-аут).

     

 






Пример TCP

#include <stdio.h>

#include <string.h>

// Для работы с библиотекой Winsock2 в исходный текст нужно включить директиву #include <winsock2.h>,

//а в командной строке компоновщика указать ws2_32.lib. Библиотека Winsock2 должна быть указана раньше,

// чем библиотека Windows.

#include <winsock2.h>

#include <windows.h>

 

#define PORT 31337    // Порт, через который идет подключение к серверу....21,80,25,110 и т.п.

#define SERVERADDR "127.0.0.1" // Адрес сервера

 

int main ( int argc, char* argv [ ] )

{

    char buff [ 1024 ] ;

    printf ( "TCP Client \n" ); // ну, тут и так понятно

//Перед началом использования библиотеки ее необходимо подготовить к работе с помощью вызова функции

// WSAStartup(Ver, lpWSAData), передав ей в старшем байте номер требуемой версии, а в младшем подверсии.

// Аргумент lpWSAData должен указывать на структуру WSADATA, в которую при успешной инициализации

//будет занесена информация о производителе библиотеки. Если инициализация не удалась, то функция //возвращает не нулевое значение.

    if ( WSAStartup ( 0x202, ( WSADATA * ) &buff [ 0 ] ) )

    {

                       printf ( " WSAStart error %d \n ", WSAGetLastError ( ) );

                       return -1;

     }

// Создаем сокет socket ( int af, int type, int protocol ). Первый слева аргумент указывает на семейство использу-

//емых протоколов, AF_INET - используеться при создании интернет приложений. SOCK_STREAM - тип //создаваемого сокета, SOCK_STREAM (потоковый) или SOCK_DGRAM (дейтаграммный) или SOCK_RAW //(сырой).Последний аргумент задает тип создаваемого сокета, нулевое значение соответствует выбору по //умолчанию, ТСР - для потоковых, и UDP - дейтограммных.

//Если функция завершилась успешно то она возвращает дескриптор сокета.

     SOCKET my_sock ;

     my_sock=socket ( AF_INET, SOCK_STREAM, 0 );

     if ( my_sock < 0 )   //

     {

                       printf (" Socket ( ) error %d \n ", WSAGetLastError ( ) );

                       return -1;

     }

//Далее расмотрим установку соединения. Заполнение структуры sockaddr_in :

     sockaddr_in dest_addr ;

     dest_addr.sin_family=AF_INET; //инет коннектинг

     dest_addr.sin_port=htons ( PORT ); //порт

     HOSTENT *hst; // хост

// Преобразование ip-адреса из символьного в сетевой формат.

     if ( inet_addr ( SERVERADDR ) !=INADDR_NONE ) dest_addr.sin_addr=inet_addr ( SERVERADDR) ;

     else

//Осуществляем поптыку получения ip-адреса по доменному имени сервера.

               if ( hst=gethostbyname ( SERVERADDR ) ) ( ( unsigned long * ) &dest_addr.sin_addr ) [ 0 ] =

//hst->h_addr_list содержит массив указателей на адреса, НО не массив адресов

                                                                                        ( ( unsigned long ** ) hst->h_addr_list ) [ 0 ] [ 0 ] ;

//Если ip-адрес не получен, то работа программы завершаеться

               else

               {

                                 printf ( " invalid address %s \n ", SERVERADDR ) ;

                                 closesocket ( my_sock ) ;

                                 WSACleanup ( ) ;

                                 return -1;

               }

//После получения адреса сервера, попытаемся установит соединение.Для этого мы вызовем функцию connect

// (SOCKET s, sockaddr * name, len). Первый элемент -SOCKET- это дескриптор сокета, второй -

//указатель на структуру sockaddr, содержащую в себе адрес (ip) и порт, последний аргумент сообщает о размере

// sockaddr.

// Если по каким-то причинам установить соединение не удаеться, то функция возвращает не нулевое значение.

       if (connect ( my_sock, ( sockaddr * ) &dest_addr, sizeof ( dest_addr ) ) )

       {

                       printf (" Connect error %d \n ", WSAGetLastError ( ) );

                       return -1;

       }

 

       printf (" Соединение с %s успешно установлено \n\ Type quit for quit \n\n" , SERVERADDR );

 //Далее начинаеться чтение и передача сообщений.

       int nsize;

       while ( ( nsize = recv ( my_sock, &buff[0], sizeof ( buff ) -1,0 ) ) !=SOCKET_ERROR )

       {

  //Ставим завершающий ноль в конце строки

                         buff[ nsize ] =0;

  //Выводим на экран

                         printf ( " S=>C: %s ", buff ) ;

  //Читаем пользовательский ввод с клавиатуры

                         printf ( "S<=C: " ) ;

                         fgets ( &buff [ 0 ] , sizeof ( buff ) -1, stdin );

   //После того, как ввели слово quit, выходим.....

                         if ( !strcmp ( &buff [ 0 ], "quit \n " ) )

                         {

                                     printf ( " Exit " );

                                     closesocket ( my_sock ) ; //выход правильный

                                     WSACleanup ( ) ;

                                      return 0;

                         }

   //Передача строки клиента серверу

                         send ( my_sock, &buff [ 0 ], nsize, 0 ) ;

         }

 

         printf ( " Recv error %d \n", WSAGetLastError ( ) );

         closesocket ( my_sock ) ;

         WSACleanup ( ) ;

         return -1;

}

 

Пример UDP

//Пример простого UDP-клиента

#include<stdio.h>

#include<string.h>

#include<winsock2.h>

#include<windows.h>

 

 

#define PORT 31337

#define SERVERADDR "127.0.0.1"

 

int main ( int argc, char* argv [ ] )

{

           char buff [ 10*1024 ];

         printf (" UDP Client \n");

   //Подключение библиотеки

         if (WSAStartup ( 0x202, ( WSADATA *) &buff [ 0 ] ))

         {

                                 printf (" WSAStartup error: %d\n ", WSAGetLastError ( ) );

                                 return -1;

          }

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

          SOCKET name_sock=socket ( AF_INET, SOCK_DGRAM, 0 );

          if ( name_sock==INVALID_SOCKET )

          {

                                 printf (" socket ( ) error: %d \n ", WSAGetLastError ( ) );

                                 WSACleanup ( );

                                 return -1;

          }

          //Обмен сообщений с сервером

         HOSTENT *hst;

         sockaddr_in dest_addr;

 

         dest_addr.sin_family=AF_INET;

         dest_addr.sin_port=htons ( PORT );

          //Определение IP-адреса узла

          if (inet_addr ( SERVERADDR )) dest_addr.sin_addr.s_addr=inet_addr ( SERVERADDR );

         else

                    if ( hst=gethostbyname ( SERVERADDR )) dest_addr.sin_addr.s_addr=((unsigned long **)

                              //функция gethostbyname ожидает на входе ТОЛЬКО доменные имена

                                                                                                                            hst->h_addr_list)[0][0];

         else

                    {

                                  printf ("Unknown host: %d \n", WSAGetLastError ( ));

                                  closesocket ( name_sock );

                                  WSACleanup ( );

                                  return -1;

                     }

          while (1)

           {

                      //Чтение сообщения с клавиатуры

                      printf ("S<=C: "); fgets (&buff [0], sizeof (buff) -1, stdin);

                      if (!strcmp(&buff [0], "quit \n")) break;

                      //передача сообщений на сервер

                      sendto(name_sock, &buff [0], strlen ( &buff [0] ), 0,(sockaddr *) &dest_addr, sizeof(dest_addr));

                      //Прием сообщений с сервера

                      sockaddr_in server_addr;

                      int server_addr_size=sizeof (server_addr);

 

                      int n=recvfrom (name_sock, &buff [0], sizeof(buff)-1,0,(sockaddr *) &server_addr, &server_addr_size);

                      if ( n==SOCKET_ERROR)

                       {

                                   printf ("recvfrom ( ) error: %d\n", WSAGetLastError ( ) );

                                   closesocket(name_sock);

                                   WSACleanup ( );

                                   return -1;

                      }

                      buff [n]=0;

                      //Вывод принятого сообщения с сервера на экран

                      printf("S=>C: %s", &buff [0]);

            }

            //Выход

           closesocket (name_sock);

           WSACleanup ( );

            return 0;

}










Последнее изменение этой страницы: 2018-06-01; просмотров: 167.

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