- •3.2. Протокол доставки пользовательских дейтаграмм udp
- •5. Рабочее задание и указание к его выполнению
- •Цель работы
- •Подготовка к работе
- •Стек протоколов tcp/ip
- •3.1. Протокол межсетевого взаимодействия ip, формат ip пакета.
- •3.2. Протокол доставки пользовательских дейтаграмм udp.
- •3.3. Протокол надежной доставки сообщений tcp
- •Программирование по схеме “клиент-сервер” с использованием интерфейса Windows Sockets
- •Int wsaStartup(word wVersionRequested, lpwsadata lpWsaData);
- •Int wsaCleanup(void);
- •Int wsaGetLastError(void);
- •Socket socket(int af, int type, int protocol);
- •Int closesocket(socket sock);
- •Char far * inet_ntoa(struct in_addr in);
- •#Define h_addr h_addr_list[0]
- •Int bind(socket s, const struct sockaddr far *name, int namelen);
- •Int listen(socket sock, int backlog);
- •Socket accept(socket s, struct sockaddr far *addr, int far * addrlen);
- •Void ExitThread(uint fuExitCode);
- •Bool TerminateThread(handle hThread, dword dwExitCode);
- •Connect (socket s, const struct sockaddr *peer, int peer_len);
- •Передача и приём данных.
- •Int sendto(socket s,const void* buf, size_t len, int flags,
- •Int recvfrom(socket s,void* buf,size_t len, int flags,
- •Алгоритм построения клиента и сервера.
- •5. Рабочее задание и указание к его выполнению.
- •Содержание отчёта.
- •Вопросы для самопроверки.
- •8. Библиографический список
Int closesocket(socket sock);
Значение |
Описание |
WSANOTINITIALISED |
Интерфейс Windows Sockets не был проинициализирован функцией WSAStartup |
WSAENETDOWN |
Сбой сетевого программного обеспечения |
WSAENONSOCK |
Указанный в параметре дескриптор не является сокетом |
WSAEINPROGRESS |
Выполняется одна из блокирующих функций интерфейса Windows Sockets |
WSAEINTR |
Работа функции была отменена при помощи функции 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 на смену ей пришла структура 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; |
В общем - ничего не изменилось, замена беззнакового короткого целого на знаковое для представления семейства протоколов ничего не дает. Зато теперь адрес узла представлен в виде трех полей: sin_port (номера порта), sin_addr (IP-адреса узла) и "хвоста" из восьми нулевых байтов, который остался от четырнадцатисимвольного массива sa_data. Для чего он нужен? Дело в том, что структура sockaddr не привязана именно к TCP/IP, и может работать и с другими сетевыми протоколами. Адреса же некоторых сетей требуют для своего представления гораздо больше четырех байт.
Поле sin_family определяет тип адреса. Нужно записать в это поле значение AF_INET, которое соответствует типу адреса, принятому в Internet: srv_adress.sin_family = AF_INET;
Поле sin_port определяет номер порта, который будет использоваться для передачи данных. Порт – это просто идентификатор программы, выполняющей обмен в сети. На одном узле может одновременно работать несколько программ, использующих разные порты. Особенностью поля sin_port является использование так называемого сетевого формата данных. Этот формат отличается от того, что принят в процессорах с архитектурой Intel, а именно младшие байты данных хранятся по старшим
адресам памяти. Напомним, что архитектура процессоров Intel подразумевает хранение старших байтов данных по младшим адресам. Универсальный сетевой формат удобен при организации глобальных сетей, так как в узлах такой сети могут использоваться компьютеры с различной архитектурой.
Для выполнения преобразования из обычного формата в сетевой и обратно в интерфейсе Windows Sockets предусмотрен специальный набор функций. В частности, для заполнения поля sin_port нужно использовать функцию htons, выполняющую преобразование 16-ти разрядных данных или htonl, выполняющую преобразование 32-х разрядных данных из формата 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_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_un.S_un_w.s_w2 #define s_impno S_un.S_un_b.s_b3 |
При инициализации сокета в этой структуре нужно указать адрес IP, с которым будет работать данный сокет. Если сокет будет работать с любым адресом (например, вы создаёте сервер, который будет доступен из узлов с любым адресом), адрес для сокета можно указать следующим образом:
srv_adress.sin_addr.s_addr = INADDR_ANY;
В этом случае, если сокет будет работать с определённым адресом IP (например вы создаёте приложение-клиент, которое будет обращаться к серверу с конкретным адресом IP), в указанную структуру необходимо записать реальный адрес.
Дейтаграммный протокол UDP позволяет посылать пакеты данных одновременно всем рабочим станциям в широковещательном режиме. Для этого нужно указать адрес как INADDR_BROADCAST.
Если известен адрес в виде четырёх десятичных чисел, разделённых точкой (именно так его вводит пользователь), то можно заполнить поле адреса при помощи inet_addr:
dest_sin.sin_addr.s_addr = inet_addr(“192.168.1.1”);
При записи адресов нужно учитывать, что в некоторых реализациях TCP/IP принято стандартное для языка С соглашение о том, что числа начинающиеся с нуля, записываются в восьмеричной системе. В таком случае 17.52.86.120 – это не то же самое, 017.52.86.120. В первом примере адрес сети равен 17, а во втором – 15.
В случае ошибки функция возвращает значение INADDR_NONE, что можно использовать для проверки.
Обратное преобразование адреса IP в текстовую строку можно при необходимости легко выполнить с помощью функции inet_ntoa, имеющей следующий прототип:
