Протокол доставки пользовательских дейтаграмм UDP.

Задачей протокола транспортного уровня UDP (User Datagram Protocol) является передача данных меж прикладными процессами без гарантий доставки, потому его пакеты могут быть потеряны, продублированы либо придти не в том порядке, в каком они были высланы.

Формат сообщений UDP

Единица данных протокола UDP именуется UDP-пакетом либо пользовательской дейтаграммой (user datagram). UDP-пакет Протокол доставки пользовательских дейтаграмм UDP. состоит из заголовка и поля данных, в каком располагается пакет прикладного уровня. Заголовок имеет обычный формат и состоит из 4 двухбайтовых полей:

· UDP source port - номер порта процесса-отправителя,

· UDP destination port - номер порта процесса-получателя,

· UDP message length - длина UDP-пакета в б,

· UDP checksum - контрольная сумма UDP-пакета

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

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

Рис.2. Формат UDP дейтаграммы

3.3. Протокол надежной доставки сообщений TCP

В стеке протоколов TCP/IP протокол TCP (Transmission Control Protocol) работает так же, как и протокол UDP, на транспортном уровне. Он обеспечивает надежную транспортировку данных меж прикладными процессами методом установления логического соединения.

Формат сообщений Протокол доставки пользовательских дейтаграмм UDP. TCP

Сообщения протокола TCP именуются секторами и состоят из заголовка и блока данных. Заголовок сектора имеет последующие поля:

· Порт источника (SOURS PORT) занимает 2 б, идентифицирует процесс-отправитель;

· Порт предназначения (DESTINATION PORT) занимает 2 б, идентифицирует процесс-получатель;

· Поочередный номер (SEQUENCE NUMBER) занимает 4 б, показывает номер б, который определяет смещение сектора относительно потока Протокол доставки пользовательских дейтаграмм UDP. отправляемых данных;

· Подтвержденный номер (ACKNOWLEDGEMENT NUMBER) занимает 4 б, содержит наибольший номер б в приобретенном секторе, увеличенный на единицу; конкретно это значение употребляется в качестве квитанции;

· Длина заголовка (HLEN) занимает 4 бита, показывает длину заголовка сектора TCP, измеренную в 32-битовых словах. Длина заголовка не фиксирована и может изменяться зависимо от значений, устанавливаемых в Протокол доставки пользовательских дейтаграмм UDP. поле Функции;

· Резерв (RESERVED) занимает 6 битов, поле зарезервировано для следующего использования;

· Кодовые биты (CODE BITS) занимают 6 битов, содержат служебную информацию о типе данного сектора, задаваемую установкой в единицу соответственных бит этого поля:

· URG - срочное сообщение;

· ACK - квитанция на принятый сектор;

· PSH - запрос на отправку сообщения без ожидания наполнения Протокол доставки пользовательских дейтаграмм UDP. буфера;

· RST - запрос на восстановление соединения;

· SYN - сообщение применяемое для синхронизации счетчиков переданных данных при установлении соединения;

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

· Окно (WINDOW) занимает 2 б, содержит объявляемое значение размера окна в б;

· Контрольная сумма (CHECKSUM) занимает 2 б, рассчитывается по сектору;

· Указатель срочности (URGENT Протокол доставки пользовательских дейтаграмм UDP. POINTER) занимает 2 б, употребляется вместе с кодовым битом URG, показывает на конец данных, которые нужно срочно принять, невзирая на переполнение буфера;

· Функции (OPTIONS) - это поле имеет переменную длину и может вообщем отсутствовать, наибольшая величина поля 3 б; употребляется для решения вспомогательных задач, к примеру, при выборе наибольшего размера Протокол доставки пользовательских дейтаграмм UDP. сектора;

· Заполнитель (PADDING) может иметь переменную длину, представляет собой фиктивное поле, применяемое для доведения размера заголовка до целого числа 32-битовых слов.

4. Программирование по схеме “клиент-сервер” с внедрением интерфейса Windows Sockets

В локальных и глобальных сетях есть два принципно различных метода передачи данных. 1-ый из их подразумевает посылку данных от 1-го узла к Протокол доставки пользовательских дейтаграмм UDP. другому (либо сходу нескольким узлам) без получения доказательства о доставке и даже без гарантии того, что передаваемые пакеты будут получены в правильной последовательности. Примером такового протокола служит UDP, который употребляется в сетях TCP/IP, либо протокол IPX, который является базисным в сетях Novell NetWare. Главные достоинства дейтаграммных Протокол доставки пользовательских дейтаграмм UDP. протоколов заключаются в высочайшем быстродействии и способности широковещательной передачи данных, когда один узел посылает сообщения, а несколько других их получают, причём сразу.

2-ой метод передачи подразумевает создание канала передачи данных меж 2-мя разными узлами сети. При всем этом канал создаётся средствами дейтаграммных протоколов, но доставка пакетов в канале является гарантированной. Пакеты Протокол доставки пользовательских дейтаграмм UDP. всегда доходят в целостности и сохранности (по последней мере до прикладного уровня протокола), причём в правильном порядке. Быстродействие выходит в среднем ниже, чем у дейтаграммных протоколов, за счёт посылки подтверждений. Примерами протоколов, использующих канал связи, могут служить протоколы TCP и SPX (протокол NETBIOS допускает передачу данных с внедрением как Протокол доставки пользовательских дейтаграмм UDP. дейтаграмм, так и каналов связи). В данном приложении для передачи тестовых данных употребляется протокол пользовательских дейтаграмм UDP, потому что он не гарантирует доставки пакетов, и как следует годится для тестирования сетей.

Для передачи данных при помощи хоть какого из перечисленных выше 2-ух методов каждое приложение должно сделать объект, именуемый Протокол доставки пользовательских дейтаграмм UDP. сокетом. По собственному предназначению сокет больше всего похож на идентификатор файла (file handle), который нужен для выполнения над файлом операций чтения либо записи. До того как приложение, запущенное на узле сети, сумеет делать передачу либо приём данных, оно должно сделать сокет и проинициализировать его, указав некие характеристики. Для сокета Протокол доставки пользовательских дейтаграмм UDP. нужно указать три параметра. Это IP адресок, связанный с сокетом, номер порта, для которого будут производиться операции передачи данных, а так же тип сокета. Что касается последнего параметра (тип сокета), то есть сокеты 2-ух типов. 1-ый тип предназначен для передачи данных в виде дейтаграмм, 2-ой – с внедрением каналов Протокол доставки пользовательских дейтаграмм UDP. связи.

Инициализация приложения и окончание его работы.

В процессе инициализации приложение должно зарегистрировать себя в библиотеке winsock32.dll, которая предоставляет приложениям интерфейс Windows Sockets в среде операционных систем MS Windows9x и MS Windows NT.

Для инициализации нужно вызвать функцию WSAStartup, определённую последующим образом:

int WSAStartup(WORD wVersionRequested Протокол доставки пользовательских дейтаграмм UDP., LPWSADATA lpWSAData);

В параметре wVersionRequested указывается версия интерфейса WS, нужная для работы данного приложения. Старший б показывает младший номер версии (minor version), младший б – старший номер версии (major version).

Перед вызовом функции WSAStartup параметр lpWSAData должен содержать указатель на структуру типа WSADATA, в которую будут записаны сведения о определенной реализации Протокол доставки пользовательских дейтаграмм UDP. интерфейса Windows Sockets. В случае фуррора функция WSAStartup возвращает нулевое значение.

Если происходит ошибка, ворачивается одно из последующих значений:

Значение Описание
WSASYSNOTREADY Сетевое программное обеспечение не готово для работы
WSAVERNOTSUPPORTED Функция не поддерживается данной реализацией интерфейса Windows Sockets
WSAEINVAL Библиотека dll, обеспечивающая интерфейс Windows Sockets, не соответствует версии Протокол доставки пользовательских дейтаграмм UDP., обозначенной приложением в параметре wVersionRequested

Кусок текста программки, выполняющий инициализацию интерфейса Windows Sockets:

#include ………………………….. Rc=WSAStartup(MAKEWORD(2,0), &WSAData); if(rc != 0) { mMessageBox(NULL, “WSAStartup Error”, “Error”, MB_OK); return FALSE; } //Отображаем описание и версию системы Windows Sockets в //окне органа управления StatusBar wsprintf(szTemp,“Server use %s %s”,WSAData.szDescription,WSAData.szSystemStatus Протокол доставки пользовательских дейтаграмм UDP.); hwndSb = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_BORDER | SBARS_SIZEGRIP, szTemp, hWnd, IDS_STATUSBAR);

Определение структуры WSADATA и указателя на неё смотрится последующим образом:

typedef struct WSAData { WORD wVersion; WORD wHighVersion; charszDescription[WSADESCRIPTION_LEN+1]; char szSystemstatus[WSASYS_STATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; } WSADTA Протокол доставки пользовательских дейтаграмм UDP.; typedef WSADATA FAR *LPWSADATA;

Использованные выше поля szDescription и szSystemStatus после вызова функции WSAStartup содержат соответственно описание определенной реализации интерфейса Windows Sockets и текущее состояние этого интерфейса в виде текстовых строк. В полях wVersion и wHighVersion записаны соответственно версия спецификации Windows Sockets, которую будет использовать приложение, и версия спецификации Протокол доставки пользовательских дейтаграмм UDP., которой соответствует определенная реализация интерфейса Windows Sockets. Приложение может создавать сразу несколько сокетов, к примеру для использования в разных подзадачах 1-го процесса. В поле iMaxSockets хранится наибольшее количество сокетов, которое можно получить для 1-го процесса. В поле iMaxUdpDg записан наибольший размер пакета данных, который можно делать Протокол доставки пользовательских дейтаграмм UDP. с внедрением дейтаграмного протокола UDP. Поле lpVendorInfo содержит указатель на дополнительную информацию, формат которой находится в зависимости от конторы – изготовителя определенной реализации системы Windows Sockets.

Перед тем, как окончить свою работу, приложение должно высвободить ресурсы, приобретенные у операционной системы для работы с Windows Sockets. Для выполнения этой задачки приложение должно вызвать Протокол доставки пользовательских дейтаграмм UDP. функцию WSACleanup, определённую так, как это показано ниже:

int WSACleanup(void);

Эта функция может вернуть нулевое значение при успехе либо значение SOCKET_ERROR в случае ошибки. Для получения кода последней ошибки, возвращённой Windows Sockets, употребляется функция:

int WSAGetLastError(void);

Эта функция позволяет найти код ошибки при неудачном Протокол доставки пользовательских дейтаграмм UDP. окончании фактически всех функций интерфейса Windows Sockets. Её необходимо вызывать сходу прямо за функцией, завершившейся безуспешно. Если ошибка появилась при выполнении функции WSACleanup, функция WSAGetLastError может возвратить одно из последующих значений:


Значение Описание
WSANOTINITIALISED Интерфейс Windows Sockets не был проинициализирован функцией WSAStartup
WSAENETDOWN Сбой сетевого программного обеспечения
WSAEINPROGRESS Во время вызова Протокол доставки пользовательских дейтаграмм UDP. функции WSACleanup производилась одна из блокирующих функций интерфейса Windows Sockets

Создадим маленькие пояснения относительно последней ошибки, приведённой в этом перечне, имеющей код WSAEINPROGRESS. Некие функции интерфейса Windows Sockets способны перекрыть работу приложения, потому что они не возвращают управление до собственного окончания. В операционных системах, использующих вытесняющую мультизадачность Протокол доставки пользовательских дейтаграмм UDP., к которым относятся Microsoft Windows 9x/Me, Windows NT4/5, это не приводит к блокировке всей системы. Реально избежать использования блокирующих функций, потому что для их в интерфейсе Windows Sockets существует подмена.

Создание и инициализация сокета.

После инициализации интерфейса Windows Sockets приложение должно сделать один либо несколько сокетов, которые будут применены для Протокол доставки пользовательских дейтаграмм UDP. передачи данных.

Сокет создаётся при помощи функции:

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

API сокетов не находится в зависимости от протокола и может поддерживать различные адресные домены. Параметр af – это константа, указывающая какой домен нужен сокету (определяет формат адреса). Этому параметру соответствуют домены AF_INET Протокол доставки пользовательских дейтаграмм UDP., что соответствует формату адреса, принятому в Internet, AF_LOCAL (либо AF_UNIX) и AF_UNSPEC. Домен AF_LOCAL применяется для межпроцессного взаимодействия (IPC) на одной и той же машине. В устаревших вариантах вызова socket константы доменов обозначали как PF_* заместо современных AF_*. Но так как оба набора констант определены идиентично – в реальности Протокол доставки пользовательских дейтаграмм UDP. одни константы просто выражаются через другие, - на практике можно употреблять оба варианта.

Домен AF_UNSPEC применяется в тех случаях, когда спецификация сокета определяется 2-мя другими параметрами.

Характеристики type и protocol определяют соответственно тип сокета и протокол, который будет применен для данного сокета.

Тип сокета Описание
SOCK Протокол доставки пользовательских дейтаграмм UDP._STREAM Сокет будет применен для передачи данных через канал связи с внедрением протокола TCP
SOCK_DGRAM Сокет будет применен для передачи данных без сотворения канала связи через дейтаграммный протокол UDP
SOCK_RAW Сокет будет применен для доступа к неким дейтаграммам на уровне протокола IP. Они употребляются в особенных случаях, к примеру Протокол доставки пользовательских дейтаграмм UDP. для просмотра всех ICMP сообщений.

Параметр протокол должен быть определен константами связанными с протоколом, такими как IPPROTO_TCP и IPPROTO_UDP для протоколов TCP и UDP соответственно. Но при использовании домена AF_INET довольно указать только тип сокета, а для параметра protocol можно указать нулевое значение.

В случае фуррора функция Протокол доставки пользовательских дейтаграмм UDP. socket возвращает дескриптор, который можно использовать для выполнения всех операций над данным сокетом. Если же произошла ошибка, эта функция возвращает значение INVALID_SOCKET. Для анализа предпосылки ошибки необходимо вызвать функцию WSAGetLastError, которая в этом случае может возвратить один из последующих кодов ошибки:

Значение Описание
WSANOTINITIALISED Интерфейс Windows Sockets не Протокол доставки пользовательских дейтаграмм UDP. был проинициализирован функцией WSAStartup
WSAENETDOWN Сбой сетевого программного обеспечения
WSAEAFNOSUPPORT Указан неверный тип адреса
WSAEINPROGRESS Производится блокирующая функция интерфейса Windows Sockets
WSAEMFILE Израсходован весь припас свободных дескрипторов
WSAENOBUFS Нет памяти для сотворения буфера
WSAEPROTONOSUPPORT Указан неверный протокол
WSAEPROTOTYPE Обозначенный протокол несовместим с данным типом сокета
WSAESOCKTNOSUPPORT Обозначенный тип Протокол доставки пользовательских дейтаграмм UDP. сокета несовместим с данным типом адреса

Кусок кода, в каком создаётся сокет для передачи данных с внедрением протокола TCP:

srv_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (srv_socket == INVALID_SOCKET) { MessageBox(NULL, “socket error”, “error”, MB_OK); return 0; }

Удаление сокета

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

int closesocket(SOCKET sock);

Значение Описание
WSANOTINITIALISED Интерфейс Windows Sockets не был проинициализирован функцией WSAStartup
WSAENETDOWN Сбой сетевого программного обеспечения
WSAENONSOCK Обозначенный в параметре дескриптор не является сокетом
WSAEINPROGRESS Производится одна из блокирующих функций интерфейса Windows Sockets
WSAEINTR Работа функции была Протокол доставки пользовательских дейтаграмм UDP. отменена с помощью функции WSACancelBlockingCall

Характеристики сокета.

Для задания характеристик сокета нужно приготовить структуру типа sockaddr, определение которой:

struct sockaddr { u_short sa_family; char sa_data[14]; } typedef struct sockaddr SOCKADDR; typedef struct sockaddr *PSOCKADDR; typedef struct sockaddr FAR *LPSOCKADDR;

Но, сейчас она считается устаревшей, и в Winsock 2.x на замену Протокол доставки пользовательских дейтаграмм UDP. ей пришла структура sockaddr_in, определенная так:


struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; } typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr_in *PSOCKADDR_IN; typedef struct sockaddr_in FAR *LPSOCKADDR_IN;

В общем - ничего не поменялось, подмена Протокол доставки пользовательских дейтаграмм UDP. беззнакового недлинного целого на знаковое для представления семейства протоколов ничего не дает. Зато сейчас адресок узла представлен в виде 3-х полей: sin_port (номера порта), sin_addr (Айпишника узла) и "хвоста" из восьми нулевых байтов, который остался от четырнадцатисимвольного массива sa_data. Для каких целей он Протокол доставки пользовательских дейтаграмм UDP. нужен? Дело в том, что структура sockaddr не привязана конкретно к TCP/IP, и может работать и с другими сетевыми протоколами. Адреса же неких сетей требуют для собственного представления еще больше 4 б.

Поле sin_family определяет тип адреса. Необходимо записать в это поле значение AF_INET, которое соответствует типу Протокол доставки пользовательских дейтаграмм UDP. адреса, принятому в Internet: srv_adress.sin_family = AF_INET;

Поле sin_port определяет номер порта, который будет употребляться для передачи данных. Порт – это просто идентификатор программки, выполняющей обмен в сети. На одном узле может сразу работать несколько программ, использующих различные порты. Особенностью поля sin_port является внедрение так Протокол доставки пользовательских дейтаграмм UDP. именуемого сетевого формата данных. Этот формат отличается от того, что принят в микропроцессорах с архитектурой Intel, а конкретно младшие байты данных хранятся по старшим


адресам памяти. Напомним, что архитектура микропроцессоров Intel предполагает хранение старших байтов данных по младшим адресам. Универсальный сетевой формат комфортен при организации глобальных сетей, потому что в Протокол доставки пользовательских дейтаграмм UDP. узлах таковой сети могут употребляться компы с различной архитектурой.

Для выполнения преобразования из обыденного формата в сетевой и назад в интерфейсе Windows Sockets предусмотрен особый набор функций. А именно, для наполнения поля sin_port необходимо использовать функцию htons, выполняющую преобразование 16-ти разрядных данных либо htonl, выполняющую преобразование 32-х разрядных Протокол доставки пользовательских дейтаграмм UDP. данных из формата Intel в сетевой формат.

Инициализация поля sin_port:

srv_address.sin_port = htons(5000);

где 5000 – номер порта.

Вернёмся опять к структуре sockaddr_in. Поле sin_addr этой структуры представляет собой структуру in_addr:

struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un Протокол доставки пользовательских дейтаграмм UDP._b; struct { u_short s_w1,s_w2;} S_un_w; u_long S_addr; } S_un; }; #define s_addr S_un.S_addr #define s_host S_un.S_un_b.s_b2 #define s_net S_un.S_un_b.s_b1 #define s_ipm S Протокол доставки пользовательских дейтаграмм UDP._un.S_un_w.s_w2 #define s_impno S_un.S_un_b.s_b3

При инициализации сокета в этой структуре необходимо указать адресок IP, с которым будет работать данный сокет. Если сокет будет работать с хоть каким адресом (к примеру, вы создаёте сервер, который будет доступен из узлов с Протокол доставки пользовательских дейтаграмм UDP. хоть каким адресом), адресок для сокета можно указать последующим образом:

srv_adress.sin_addr.s_addr = INADDR_ANY;

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

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

Если известен адресок в виде четырёх десятичных чисел, разделённых точкой (конкретно так его вводит юзер), то можно заполнить поле адреса с помощью inet_addr Протокол доставки пользовательских дейтаграмм UDP.:

dest_sin.sin_addr.s_addr = inet_addr(“192.168.1.1”);

При записи адресов необходимо учесть, что в неких реализациях TCP/IP принято стандартное для языка С соглашение о том, что числа начинающиеся с нуля, записываются в восьмеричной системе. В таком случае 17.52.86.120 – это не то же самое, 017.52.86.120. В первом примере адресок сети равен 17, а Протокол доставки пользовательских дейтаграмм UDP. во 2-м – 15.

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

Оборотное преобразование адреса IP в текстовую строчку можно по мере надобности просто выполнить при помощи функции inet_ntoa, имеющей последующий макет:

char FAR * inet_ntoa(struct in_addr in);

При ошибке Протокол доставки пользовательских дейтаграмм UDP. эта функция возвращает NULL.

Но в большинстве случаев юзер работает с доменными именами, применяя сервер DNS либо файл HOSTS(пример файла приведен ниже).

# (C) Компания Майкрософт (Microsoft Corp.), 1993-1999 # # Это эталон файла HOSTS, применяемый Microsoft TCP/IP для #Windows. # Этот файл содержит сравнения Айпишников именам узлов. # Каждый элемент должен размещаться Протокол доставки пользовательских дейтаграмм UDP. в отдельной строке. IP-#адресок должен # находиться в первом столбце, за ним должно следовать #соответственное имя. # Айпишник и имя узла должны делиться хотя бы одним пробелом. # Не считая того, в неких строчках могут быть вставлены #комменты # (такие, как эта строчка), они должны следовать за именованием узла и #отделяться # от него эмблемой Протокол доставки пользовательских дейтаграмм UDP. '#'. # К примеру: # # 102.54.94.97 rhino.acme.com # начальный сервер # 38.25.63.10 x.acme.com # узел клиента x 127.0.0.1 localhost 172.16.1.3 node

В данном случае сначала необходимо пользоваться функцией gethostbyname, возвращающей IP адресок, а потом записать приобретенный IP адресок в структуру sin_addr:


SOCKADDR_IN dest_sin; PHOSTENT phe; phe = gethostbyname(“ftp.microsoft.com Протокол доставки пользовательских дейтаграмм UDP.”); if (phe == NULL) { closesocket(srv_socket); MessageBox(NULL,“gethostbyname Error”,“Error”,MB_OK); return; } memcpy((char FAR *)&(dest_sin.sin_addr), phe->h_addr, phe->h_lenght);

В случае ошибки функция gethostbyname возвращает NULL. При всем этом причину ошибки можно узнать, проверив код возврата функции WSAGetLastError.

Если же обозначенный Протокол доставки пользовательских дейтаграмм UDP. узел найден в базе DNS либо в файле HOSTS, функция gethostbyname возвращает указатель на структуру hostent, описанную ниже:

struct hostent { char FAR * h_name; //имя узла char FAR * FAR * h_aliases; //перечень //других имён short h_addrtype; //тип адреса узла short h_length; //длина адреса char FAR * FAR * h Протокол доставки пользовательских дейтаграмм UDP._addr_list //перечень указателей // на Айпишника }; typedef struct hostent *PHOSTENT; typedef struct hostent FAR *LPHOSTENT;

Как и в случае с in_addr, во огромном количестве программ и прилагаемых к Winsock SDK примерах интенсивно употребляется недокументированное поле структуры h_addr. К примеру, вот строчка из файла "simplec.c":

memcpy(&(server.sin_addr),hp Протокол доставки пользовательских дейтаграмм UDP.->h_addr,hp->h_length);


В "winsock2.h", можно отыскать, что обозначает h_addr:

#define h_addr h_addr_list[0]

Т.е. разыскиваемый адресок находиться в h_addr_list[0]. А зачем необходимы другие адреса в перечне? Дело в том, что с некими доменными именами связано сходу несколько Айпишников. В Протокол доставки пользовательских дейтаграмм UDP. случае неработоспособности 1-го узла, клиент может испытать подключиться к другому, либо просто избрать узел с большей скоростью обмена. Но в приведенном примере клиент употребляет только 1-ый Айпишник в перечне и игнорирует все другие! Естественно, это не принципиально в данной лабораторной работе, но внедрение таковой способности может Протокол доставки пользовательских дейтаграмм UDP. приметно повысить производительность приложения.

Привязка адреса к сокету.

После инициализации сокета следует произвести привязку адреса интерфейса и номера порта к сокету с помощью функции bind:

int bind(SOCKET s, const struct sockaddr FAR *name, int namelen);

При отсутствии ошибки возращаемое значение 0 по другому SOCKET_ERROR (для Windows) либо -1 (для UNIX Протокол доставки пользовательских дейтаграмм UDP.).

Параметр s – это дескриптор сокета. При помощи характеристик name и namelen передаются порт и сетевой интерфейс. Обычно в качестве адреса задаётся константа INADDR_ANY. Это значит, что будет принято соединение, запрашиваемое по хоть какому интерфейсу. Если хосту с несколькими сетевыми адресами необходимо принимать соединения только по одному интерфейсу, то следует Протокол доставки пользовательских дейтаграмм UDP. указать Айпишник этого интерфейса. Как обычно namelen – длина структуры SOCKADDR_IN. Если ваше приложение использовало bind для привязки порта к сокету, то ни одно другое приложение не сумеет прослушивать этот порт.

Пример вызова функции bind:

if (bind(srv_socket,(LPSOCKADDR)&srv_address, sizeof(srv_adress))==SOCKET_ERROR) { closesocket(srv Протокол доставки пользовательских дейтаграмм UDP._socket); MessageBox(NULL, “bind Error”, “Error”, MB_OK); return; }

Создание канала связи.

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

Сторона сервера:

Сначала необходимо переключить сокет в режим приёма для выполнения соединения с клиентом с помощью функции LISTEN:

int listen(SOCKET sock, int backlog);

Через параметр sock функции нужно задать дескриптор сокета, который будет применен для сотворения канала. Параметр backlog задаёт наибольший размер очереди для ожидания соединения (можно Протокол доставки пользовательских дейтаграмм UDP. указывать значения от 1 до 5). Очередь содержит запросы на установку соединений для каждой пары значений (адресок IP, порт). Если указать значение backlog , больше очень допустимого, то система уменьшит его, не сообщив об ошибке.

Пример вызова функции listen:

if (listen(srv_socket, 1) == SOCKET_ERROR) { closesocket(srv_socket); MessageBox(NULL Протокол доставки пользовательских дейтаграмм UDP., “listen Error”, “Error”, MB_OK); return; }

Дальше нужно выполнить ожидание соединения. Это можно выполнить 2-мя разными методами:

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

Функция accept имеет последующий макет:

SOCKET accept(SOCKET s Протокол доставки пользовательских дейтаграмм UDP., struct sockaddr FAR *addr, int FAR * addrlen);

Параметр s – это дескриптор прослушиваемого сокета. Функция возвращает адресок приложения на другом конце соединения в структуре SOCKADDR_IN, на которую показывает параметр addr. Целому числу, на которое показывает параметр addrlen, ядро присваивает значение, равное длине этой структуры. Нередко нет необходимости знать адресок клиентского приложения, потому Протокол доставки пользовательских дейтаграмм UDP. в качестве addr и addrlen будет передаваться NULL.

Возвращаемое значение в случае ошибки: INVALID_SOCKET (для Windows) либо -1 (для UNIX). Если ошибки нет, то функция accept делает сокет с теми же параметрами, что и SOCKET s и возвращает дескриптор сделанного сокета. Сокет возвращенный функцией accept связан и Протокол доставки пользовательских дейтаграмм UDP. может немедля употребляться для приема и передачи данных.

Потому что при вызове accept выполнение программки прекращается до установления соединения целенаправлено производить вызов функции из параллельного треда (потока). Для Windows функция сотворения потока смотрится так:

HANDLE CreateThread( LPSECURITY_ATTRIBUTES LPSA; DWORD cbStack; LPTHREAD_START_ROUTINE lpStartAddr; LPVOID lpvThreadParm; DWORD fdwCreate; LPDWORD lpIDThread Протокол доставки пользовательских дейтаграмм UDP.; );

Тщательно о параметрах функции можно выяснить в MSDN Library. Для выполнения данной лабораторной работы необходимыми параметрами являются lpStartAddr , lpvThreadParm и lpIDThread.Параметр lpStartAddrопределяет адресок функции потока, с которой должен будет начать работу создаваемый поток. Полностью допустимо и даже полезно создавать несколько потоков, у каких в качестве входной точки Протокол доставки пользовательских дейтаграмм UDP. употребляется адресок одной и той же стартовой функции. Параметр lpvThreadParmпозволяет передавать функции потока какое-либо инициализирующее значение. Оно может представлять собой либо просто 32-битное значение, либо 32-битный указатель на структуру данных с дополнительной информацией. Последний параметр функцииlpIDThread– это адресок переменной типа DWORD, в какой функция возвратит идентификатор, приписанный системой Протокол доставки пользовательских дейтаграмм UDP. новенькому сгустку. В Windows 95 передача NULL заместо этого параметра даст ошибку. В Windows NT версии 4.0 и выше разрешено передавать NULL в параметре lpIDThread.Потому для корректной работы вашего приложения на разных платформах нужно указать функции адресок, для помещения в него идентификатор потока. Для окончания потока нужно пользоваться одной из функций Протокол доставки пользовательских дейтаграмм UDP.:

VOID ExitThread(UINT fuExitCode);

У этой функции нет возвращаемого значения, ведь после ее вызова поток перестает существовать. В параметр fuExitCode она помещает код окончания потока. Функция вызывается из завершаемого потока.

BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);

Функция завершает поток, идентифицируемый параметром hThread, и помещает код окончания в Протокол доставки пользовательских дейтаграмм UDP. dwExitCode. Ее употребляют только в последнем случае, когда управление потоком потеряно. Вызов осуществляется из другого потока.

Пример использования accept:

#define MAXCONNECT 100 SOCKADDR_IN s_addr_out[MAXCONNECT]; DWORD WINAPI ServerAccept(LPVOID); SOCKET sock, socket[MAXCONNECT]; ………………………… int main() { ………………………… DWORD DwThCtrlACC; HANDLE ThreadACC = CreateThread(NULL,0,ServerAccept,0,0,&DwThCtrlACC); return 0; } DWORD WINAPI ServerAccept Протокол доставки пользовательских дейтаграмм UDP.(LPVOID) { int numconnect = 0; while(numconnect

2-ой метод основан на использовании расширения интерфейса Windows Sockets, созданного для выполнения асинхронных операций. Заместо того, чтоб ждать соединение, приложение может вызвать один раз функцию WSAAsyncSelect, указав ей, что Протокол доставки пользовательских дейтаграмм UDP. при получении запроса на установку соединения функция окна приложения должна получить сообщение:

#define WM_SOCKET (WM_USER + 1) //При попытке установки соединения главное окно приложения получит //сообщение WSA_ACCEPT rc = WSAAsyncSelect(srv_socket, hWnd, WM_SOCKET, FD_ACCEPT); if (rc > 0) { clossesocket(srv_socket); MessageBox(NULL, “WSAAsyncSelect Error”, “Error”,MB Протокол доставки пользовательских дейтаграмм UDP._OK); return; }

В этом случае ожидание соединения производится для сокета srv_socket. Последний параметр функции имеет значение FD_ACCEPT. Это значит, что при попытке сотворения канала связи функция окна с идентификатором hWnd получит сообщение WSA_ACCEPT, определённое приложении.

Обработчик этого сообщения может смотреться, к примеру, последующим образом:

Void WndProc_OnWSAAccept Протокол доставки пользовательских дейтаграмм UDP.(HWND hWnd, UNIT msg, WPARAM wParam, LPARAM lParam) { int rc; //При ошибке отменяем поступление уведомлений в главное //окно приложения if (WSAGETSELECTEDERROR(lParam) != 0) { MessageBox(NULL, “accept Error”, “Error”, MB_OK); WSAAsyncSelect(srv_socket, hwnd, 0, 0); return; } //определяем размер адреса сокета acc_sin_len = sizeof(acc_sin); //разрешаем установку Протокол доставки пользовательских дейтаграмм UDP. соединения srv_socket = accept(srv_socket, (LPSOCKADDR)&acc_sin, (int FAR *)&acc_sin_len); if (srv_socket == INVALID_SOCKET) { MessageBox(NULL,“Invalid socket”,“Error”,MB_OK); return; } //если на данном сокете начинается передача данных от //клиента, в главное окно приложения поступит сообщение //WSA_NETEVENT. Это сообшение поступит при //разрыве соединения. rc Протокол доставки пользовательских дейтаграмм UDP. = WSAAsyncSelect(srv_socket, hWnd, WM_SOCKET, FD_READ | FD_CLOSE); if (rc > 0) { closesocket(srv_socket); MessageBox(NULL,“WSAAsyncSelect Error”,“Error”, MB_OK); return; } }

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

Сторона клиента:

Для установки соединения со стороны клиента употребляется функция connect.

connect (SOCKET s, const struct sockaddr *peer, int peer_len);

Возвращаемое значение: 0 – нормально, -1 (UNIX) либо не 0 (Windows) – ошибка. Параметр s – дескриптор сокета, который возвратил системный вызов функции socket Протокол доставки пользовательских дейтаграмм UDP.. Параметр peer показывает на структуру, в какой хранится адресок удаленного хоста и некая дополнительная информация (см. выше). Для домена AF_INET – это структура SOCKADDR_IN. Параметр peer_len содержит размер структуры в б, на которую показывает peer. При успешном окончании функции connect можно немедля приступать к обмену данными Протокол доставки пользовательских дейтаграмм UDP. с сервером.

Пример использования функции connect для установления соединения с сервером.

void SetConnection(…) { SOCKADDR_IN dest_sin; SOCKET clnt_socket; // создаем сокет clnt_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // устанавливаем адресок и порт запрашиваемого сервера dest_sin.sin_family = AF_INET; dest_sin.sin_addr.s Протокол доставки пользовательских дейтаграмм UDP._addr = inet_addr(“127.0.0.1”); dest_sin.sin_port = htons(1024); // посылаем запрос на соединение с сервером if(connect(clnt_sock,(PSOCKADDR)&dest_sin,sizeof(dest_sin)) == SOCKET_ERROR) MessageDlg("Failed",mtError,TMsgDlgButtons()<

Внедрение Айпишника 127.0.0.1 делает вероятным запускать и клиент, и сервер на одном компьютере (что очень комфортно для тестирования приложения). Для действенной и Протокол доставки пользовательских дейтаграмм UDP. надежной работы соединения типа клиент-сервер, нужно говорить одну из сторон при разрыве соединения, также в определенном порядке запускать приложения(первым запускается приложение-сервер).


protocol-tcp-or-udp-protokol-tcp-ili-udp-16-glava.html
protocol-tcp-or-udp-protokol-tcp-ili-udp-20-glava.html
protocol-tcp-or-udp-protokol-tcp-ili-udp-7-glava.html