- Purely functional
- Страницы
- воскресенье, 1 января 2012 г.
- Введение в Windows Sockets API: Клиентские сокеты C++
- Инициализация WSA
- Создание сокета
- Присоединение к серверу
- Передача данных серверу
- Прием данных от сервера
- Разрыв соединения
- Заключение
- Практическое руководство. Создание сокета How to: Create a Socket
- Пример Example
- Пример работы с сокетами (socket) для Windows
- socket.cpp
- сокеты Sockets
- Глобальные сети компьютеров. Практическое введение в Internet, E-Mail, FTP, WWW и HTML, программирование для Windows Sockets
- 5 ИНТЕРФЕЙС WINDOWS SOCKETS
- 5.1. Сокеты, датаграммы и каналы связи
- 5.2. Инициализация приложения и завершение его работы
- 5.3. Создание и инициализация сокета
- Создание сокета
- Удаление сокета
- Параметры сокета
- Привязка адреса к сокету
- 5.4. Создание канала связи
- Сторона сервера
- Сторона клиента
- 5.5. Передача и прием данных
- 5.6. Приложение SERVER
- 5.7. Приложение CLIENT
- 5.8. Приложение SERVERD
- 5.9. Приложение CLIENTD
Purely functional
Страницы
воскресенье, 1 января 2012 г.
Введение в Windows Sockets API: Клиентские сокеты C++
Клиентские сокеты используют приложения, которым необходимо передавать и принимать данные с другим приложением. Примером такого приложения является браузер: по определенному ip-адресу он передает серверу сформированный HTTP-заголовок, в качестве ответа сервер передает данные, которые затребовал в HTTP-заголовке клиент (web-страницу, изображение и т.п.).
В этой статье я расскажу о средствах WSA, необходимых для реализации передачи данных между процессами через клиентские сокеты.
Инициализация WSA
Перед началом работы с сокетами Windows необходимо инициализировать Windows sockets API (WSA)
Для этого надо вызывать функцию WSAStartup и передать в аргументах версию WSA и указатель на структуру WSAData. Функция возвращает 0, если инициализация прошла успешно, в противном случае возвращает код ошибки.
Создание сокета
Функция socket возвращает дескриптор сокета. Если при создании сокета произошла ошибка, она возвращает 0 (INVALID_SOCKET).
Присоединение к серверу
После того как сокет создан, можно начинать подключаться через него к серверам.
Для соединения нужен сам сокет, ip-адрес и порт процесса (сервера). Эти данные передаются функции connect, которая возвращает 0 в случае успешного соединения.
Ip-адрес и порт следует передать структуре sockaddr.
Передача данных серверу
Для передачи данных серверу необходимо вызвать функцию send. Вторым аргументом является указатель на данные, третьим количество данных.
Функция возвращает отрицательное число, если произошла ошибка, иначе возвращается число, соответствующие количеству переданных данных.
Прием данных от сервера
Что бы принять данные надо вызывать функцию recv и передать ей в качестве аргументов указатель на буфер данных и на размер этого буфера.
Из кода видно, что за один раз можно принять не более bufsize байт информации.
Разрыв соединения
Заключение
Дополнительную информацию о функциях, структурах WSA можно найти в MSDN: Winsock reference.
Практическое руководство. Создание сокета How to: Create a Socket
Перед использованием сокета для связи с удаленными устройствами необходимо инициализировать сокет, указав протокол и сведения о сетевом адресе. Before you can use a socket to communicate with remote devices, the socket must be initialized with protocol and network address information. Конструктор класса Socket имеет параметры, которые определяют семейство адресов, тип сокета и тип протокола, которые сокет использует для подключения. The constructor for the Socket class has parameters that specify the address family, socket type, and protocol type that the socket uses to make connections.
Пример Example
В следующем примере создается объект Socket, который может использоваться для обмена данными в сетях на основе TCP/IP (например, в Интернете). The following example creates a Socket that can be used to communicate on a TCP/IP-based network, such as the Internet.
Чтобы использовать UDP вместо TCP, измените тип протокола, как показано в следующем примере: To use UDP instead of TCP, change the protocol type, as in the following example:
В перечислении AddressFamily указаны стандартные семейства адресов, которые используются классом Socket для разрешения сетевых адресов (например, элемент AddressFamily.InterNetwork задает семейство адресов протокола IP версии 4). The AddressFamily enumeration specifies the standard address families used by the Socket class to resolve network addresses (for example, the AddressFamily.InterNetwork member specifies the IP version 4 address family).
В перечислении SocketType указан тип сокета (например, элемент SocketType.Stream указывает стандартный сокет для отправки и получения данных с помощью управления потоком). The SocketType enumeration specifies the type of socket (for example, the SocketType.Stream member indicates a standard socket for sending and receiving data with flow control).
В перечислении ProtocolType указан сетевой протокол, который используется для связи с объектом Socket (например, ProtocolType.Tcp означает, что сокет использует TCP; ProtocolType.Udp означает, что сокет использует UDP). The ProtocolType enumeration specifies the network protocol to use when communicating on the Socket (for example, ProtocolType.Tcp indicates that the socket uses TCP; ProtocolType.Udp indicates that the socket uses UDP).
После создания объекта Socket он может создать подключение к удаленной конечной точке или принимать подключения от удаленных устройств. After a Socket is created, it can either initiate a connection to a remote endpoint or receive connections from remote devices.
Пример работы с сокетами (socket) для Windows
Писал, когда сам разбирался с этим делом. На базе этого простого примера написано (точнее не совсем на его базе, а скорее при его участии) пара серьезных программок.
Все просто, как в танке. По исходникам разберетесь.
socket.cpp
char * OpenURL ( char * url ) <
WSADATA lpWSAData ;
SOCKET s ;
// Проверим на правильность введенный адрес.
// Он должен начинаться с «http://»
if ( memcmp ( url, «HTTP://» , 7 ) ! = 0 && memcmp ( url, «http://» , 7 ) ! = 0 ) return ( NULL ) ;
url + = 7 ;
// Инициализация библиотеки Ws2_32.dll.
if ( WSAStartup ( MAKEWORD ( 1 , 1 ) , & lpWSAData ) ! = 0 ) return ( NULL ) ;
char * http_host = strdup ( url ) ; // Имя хоста (HTTP_HOST)
int port_num = 80 ; // Номер порта по умолчанию (HTTP_PORT)
char * http_path = NULL ; // Путь (REQUEST_URI)
char * pch = strchr ( http_host, ‘:’ ) ;
if ( ! pch ) <
pch = strchr ( http_host, ‘/’ ) ;
if ( pch ) <
* pch = 0 ;
http_path = strdup ( pch + 1 ) ;
>
else http_path = strdup ( «» ) ;
>
else <
* pch = 0 ; pch ++ ;
char * pch1 = strchr ( pch, ‘/’ ) ;
if ( pch1 ) <
* pch1 = 0 ;
http_path = strdup ( pch1 + 1 ) ;
>
else http_path = strdup ( «» ) ;
port_num = atoi ( pch ) ;
if ( port_num == 0 ) port_num = 80 ;
>
// Поучаем IP адрес по имени хоста
struct hostent * hp ;
if ( ! ( hp = gethostbyname ( http_host ) ) ) <
free ( http_host ) ;
free ( http_path ) ;
return ( NULL ) ;
>
// Открываем сокет
s = socket ( AF_INET, SOCK_STREAM, 0 ) ;
if ( s == INVALID_SOCKET ) <
free ( http_host ) ;
free ( http_path ) ;
return ( NULL ) ;
>
// Заполняем структуру sockaddr_in
struct sockaddr_in ssin ;
memset ( ( char * ) & ssin, 0 , sizeof ( ssin ) ) ;
ssin. sin_family = AF_INET ;
ssin. sin_addr . S_un . S_un_b . s_b1 = hp — > h_addr [ 0 ] ;
ssin. sin_addr . S_un . S_un_b . s_b2 = hp — > h_addr [ 1 ] ;
ssin. sin_addr . S_un . S_un_b . s_b3 = hp — > h_addr [ 2 ] ;
ssin. sin_addr . S_un . S_un_b . s_b4 = hp — > h_addr [ 3 ] ;
ssin. sin_port = htons ( port_num ) ;
// Выводим IP адрес хоста, с которым будем соединятся
printf ( «Conecting to %d.%d.%d.%d. » , ( unsigned char ) hp — > h_addr [ 0 ] ,
( unsigned char ) hp — > h_addr [ 1 ] ,
( unsigned char ) hp — > h_addr [ 2 ] ,
( unsigned char ) hp — > h_addr [ 3 ] ) ;
// Соединяемся с хостом
if ( connect ( s, ( sockaddr * ) & ssin, sizeof ( ssin ) ) == — 1 ) <
free ( http_host ) ;
free ( http_path ) ;
printf ( «Error \n » ) ;
return ( NULL ) ;
>
printf ( «Ok \n » ) ;
// Формируем HTTP запрос
char * query = ( char * ) malloc ( 2048 ) ;
strcpy ( query, «GET /» ) ;
strcat ( query,http_path ) ;
strcat ( query, » HTTP/1.0 \n Host: » ) ;
strcat ( query,http_host ) ;
strcat ( query, » \n User-agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)» ) ;
strcat ( query, » \n Accept: */* \n \n » ) ;
// Выводим HTTP запрос
printf ( «%s» ,query ) ;
// Отправляем запрос серверу
int cnt = send ( s,query, strlen ( query ) , 0 ) ;
// Освобождаем память
free ( http_host ) ;
free ( http_path ) ;
free ( query ) ;
// Проверяем, не произошло ли ошибки при отправке запроса на сервер
if ( cnt == SOCKET_ERROR ) return ( NULL ) ;
int size = 1024 * 1024 ; // 1Mb
char * result = ( char * ) malloc ( size ) ;
strcpy ( result, «» ) ;
char * result_ptr = result ;
// Деинициализация библиотеки Ws2_32.dll
WSACleanup ( ) ;
сокеты Sockets
Пространство имен System.Net.Sockets содержит управляемую реализацию интерфейса Windows Sockets. The System.Net.Sockets namespace contains a managed implementation of the Windows Sockets interface. Все остальные классы для доступа к сети в пространстве имен System.Net основываются на этой реализации сокетов. All other network-access classes in the System.Net namespace are built on top of this implementation of sockets.
Класс Socket платформы .NET Framework — это версия служб сокетов на основе управляемого кода, предоставляемая API Winsock32. The .NET Framework Socket class is a managed-code version of the socket services provided by the Winsock32 API. В большинстве случаев методы класса Socket просто маршалируют данные в аналогичные собственные методы Win32 и осуществляют все необходимые проверки безопасности. In most cases, the Socket class methods simply marshal data into their native Win32 counterparts and handle any necessary security checks.
Класс Socket поддерживает два основных режима: синхронный и асинхронный. The Socket class supports two basic modes, synchronous and asynchronous. В синхронном режиме при вызове функций, выполняющих сетевые операции (например, Send и Receive), ожидается завершение операций, прежде чем управление возвращается вызывающей программе. In synchronous mode, calls to functions that perform network operations (such as Send and Receive) wait until the operation completes before returning control to the calling program. В асинхронном режиме вызовы возвращаются немедленно. In asynchronous mode, these calls return immediately.
Глобальные сети компьютеров. Практическое введение в Internet, E-Mail, FTP, WWW и HTML, программирование для Windows Sockets
5 ИНТЕРФЕЙС WINDOWS SOCKETS
Во второй главе нашей книги мы рассказали вам о том, как установить соединение с использованием протокола TCP/IP . Вы также научились работать в Internet в среде операционных систем Microsoft Windows 95, Microsoft Windows NT , а также OS/2 Warp Connect .
Нашей следующей задачей будет освоение основ программирования для сетей TCP/IP . Теперь мы расскажем вам о том, как составлять сетевые приложения, выполняющие обмен данными по глобальным и локальным сетям с использованием данного протокола. При этом из-за недостатка места в книге мы ограничимся описанием программного интерфейса Windows Sockets , который имеется в операционных системах Microsoft Windows 95 и Microsoft Windows NT .
Интерфейс Windows Sockets предоставляет в ваше распоряжение удобные средства организации передачи данных с использованием датаграмм и каналов связи между узлами сети.
В восьмом томе «Библиотеки системного программиста», который называется «Локальные сети персональных компьютеров. Использование протоколов IPX , SPX , NETBIOS » мы приводили соновные сведения об использовании протоколов IPX, SPX и NETBIOS в программах, передающих данные по сети Novell NetWare. Интерфейс Windows Sockets позволяет передавать данные не только с использованием протокола TCP/IP, но и других протоколов, например, IPX/SPX . Вы можете узнать об этом подробнее из документации, которая поставляется в составе SDK для программного интерфейса WIN32 .
5.1. Сокеты, датаграммы и каналы связи
В локальных и глобальных сетях существует два принципиально разных способа передачи данных.
Первый из них предполагает посылку пакетов данных от одного узла другому (или сразу нескольким узлам) без получения подтверждения о доставке и даже без гарантии того, что передаваемые пакеты будут получены в правильной последовательности. Примером такого протокола может служить протокол UDP (User Datagram Protocol ) , который используется в сетях TCP/IP, или протокол IPX , который является базовым в сетях Novell NetWare .
Основные преимущества датаграмных протоколов заключаются в высоком быстродействии и возможности широковещательной передачи данных, когда один узел отправляет сообщения, а другие их получают, причем все одновременно.
Второй способ передачи данных предполагает создание канала передачи данных между двумя различными узлами сети. При этом канал создается средствами датаграммных протоколов, однако доставка пакетов в канале является гарантированной. Пакеты всегда доходят в целостности и сохранности, причем в правильном порядке, хотя быстродействие получается в среднем ниже за счет посылки подтверждений. Примерами протоколов, использующих каналы связи, могут служить протоколы TCP и SPX (протокол NETBIOS допускает передачу данных с использованием как датаграмм, так и каналов связи) .
Для передачи данных с использованием любого из перечисленных выше способов каждое приложение должно создать объект, который называется сокетом.
По своему назначению сокет больше всего похож на идентификатор файла (file handle), который нужен для выполнения над файлом операций чтения или записи. Прежде чем приложение, запущенное на узле сети сможет выполнять передачу или прием данных, оно должно создать сокет и проинициализировать его, указав некоторые параметры.
Для сокета необходимо указать три параметра. Это IP адрес, связанный с сокетом, номер порта, для которого будут выполняться операции передачи данных, а также тип сокета.
Что касается последнего параметра (тип сокета), то существуют сокеты двух типов. Первый тип предназначен для передачи данных в виде датаграмм, второй — с использованием каналов связи.
5.2. Инициализация приложения и завершение его работы
В процессе инициализации приложение должно зарегистрировать себя в библиотеке WSOCK32.DLL , которая предоставляет приложениям интерфейс Windows Sockets в среде операционных систем Microsoft Windows 95 и Microsoft Windows NT.
Для инициализации необходимо вызвать функцию WSAStartup , определенную следующим образом:
В параметре wVersionRequested вы должны указать версию интерфейса Windows Sockets , необходимую для работы вашего приложения. Старший байт параметра указывает младший номер версии ( minor version ), младший байт — старший номер версии ( major version ).
Перед вызовом функции WSAStartup параметр lpWSAData должен содержать указатель на структуру типа WSADATA , в которую будут записаны сведения о конкретной реализации интерфейса Windows Sockets.
В случае успеха функция WSAStartup возвращает нулевое значение. Если происходит ошибка, возвращается одно из следующих значений:
Значение | Описание |
WSASYSNOTREADY | Сетевое программное обеспечение не готово для работы |
WSAVERNOTSUPPORTED | Функция не поддерживается данной реализацией интерфейса Windows Sockets |
WSAEINVAL | Библиотека DLL , обеспечивающая интерфейсe Windows Sockets, не соответствуетверсии, указанной приложением указанной в параметре wVersionRequested |
Ниже мы представили фрагмент исходного текста приложения SERVER, которое будет описано ниже, выполняющий инициализацию интерфейса Windows Sockets:
В операционных системах Microsoft Windows 95 и Microsoft Windows NT версии 3.51 встроена система Windows Sockets версии 1.1, поэтому именно это значение мы указали при вызове функции WSAStartup .
В следующих нескольких строках только что приведенного фрагмента кода содержимое двух полей структуры типа WSADATA отображается в окне органа управления Statusbar .
Определение структуры WSADATA и указателя на нее выглядят следующим образом:
Использованные выше поля szDescription и szSystemStatus после вызова функции WSAStartup содержат, соответственно, описание конкретной реализации интерфейса Windows Socket и текущее состояние этого интерфейса в виде текстовых строк.
В полях wVersion и wHighVersion записаны, соответственно, версия спецификации Windows Socket , которую будет использовать приложение, и версия спецификации, которой соответствует конкретная реализация интерфейса Windows Socket .
Приложение может одновременно создавать несколько сокетов, например, для использования в разных подзадачах одного процесса. В поле iMaxSockets хранится максимальное количество сокетов, которое можно получить для одного процесса.
В поле iMaxUdpDg записан максимальный размер пакета данных, который можно переслать с использованием датаграммного протокола UDP .
И, наконец, поле lpVendorInfo содержит указатель на дополнительную информацию, формат которой зависит от фирмы-изготовителя конкретной реализации системы Windows Sockets.
Перед тем, как завершить свою работу, приложение должно освободить ресурсы, полученные у операционной системы для работы с Windows Sockets. Для выполнения этой задачи приложение должно вызвать функцию WSACleanup , определенную так, как это показано ниже:
Эта функция может возвратить нулевое значение при успехе или значение SOCKET_ERROR в случае ошибки.
Для получения кода ошибки вы должны воспользоваться функцией с именем WSAGetLastError :
Функция WSAGetLastError позволяет определить код ошибки при неудачном завершении практически всех функций интерфейса Windows Sockets. Вы должны вызывать ее сразу вслед за функцией, завершившейся неудачно.
Если ошибка возникла при выполнении функции WSACleanup , функция WSAGetLastError может вернуть одно из следующих значений:
Значение | Описание |
WSANOTINITIALISED | Интерфейс Windows Sockets не был проинициализирован функцией WSAStartup |
WSAENETDOWN | Сбой сетевого программного обеспечения |
WSAEINPROGRESS | Во время вызыва функции WSACleanup выполнялась одна из блокирующих функций интерфейса Windows Sockets |
Сделаем небольшие пояснения относительно последней ошибки, приведенной в этом списке, и имеющей код WSAEINPROGRESS .
Некоторые функции интерфейса Windows Sockets способны блокировать работу приложения, так как они не возвращают управление до своего завершения. В операционных системах, использующих вытесняющую мультизадачность, к которым относятся Microsoft Windows 95 и Microsoft Windows NT, это не приводит к блокировке всей системы. Как вы увидите дальше, можно избежать использования блокирующих функций, так как для них в интерфейсе Windows Sockets существует замена.
5.3. Создание и инициализация сокета
После инициализации интерфейса Windows Sockets ваше приложение должно создать один или несколько сокетов, которые будут использованы для передачи данных.
Создание сокета
Сокет создается с помощью функции socket , имеющей следующий прототип:
Параметр af определяет формат адреса. Для этого параметра вы должны указывать значение AF_INET , что соответствует формату адреса, принятому в Internet.
Параметры type и protocol определяют, сооветственно, тип сокета и протокол, который будет использован для данного сокета.
Можно указывать сокеты следующих двух типов:
Тип сокета | Описание |
SOCK_STREAM | Сокет будет использован для передачи данных через канал связи с использованием протокола TCP |
SOCK_DGRAM | Передача данных будет выполняться без создания каналов связи через датаграммный протокол UDP |
Что же касается параметра protocol, то вы можете указать для него нулевое значение.
В случае успеха функция socket возвращает дескриптор, который нужно использовать для выполнения всех операций над данным сокетом. Если же произошла ошибка, эта функция возвращает значение INVALID_SOCKET . Для анализа причины ошибки вы должны вызвать функцию WSAGetLastError , которая в данном случае может вернуть один из следующих кодов ошибки:
Код ошибки | Описание |
WSANOTINITIALISED | Интерфейс Windows Sockets не был проинициализирован функцией WSAStartup |
WSAENETDOWN | Сбой сетевого программного обеспечения |
WSAEAFNOSUPPORT | Указан неправильный тип адреса |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEMFILE | Израсходован весь запас свободных дескрипторов |
WSAENOBUFS | Нет памяти для создания буфера |
WSAEPROTONOSUPPORT | Указан неправильный протокол |
WSAEPROTOTYPE | Указанный протокол несовместим с данным типом сокета |
WSAESOCKTNOSUPPORT | Указанный тип сокета несовместим с данным типом адреса |
Ниже мы привели фрагмент кода, в котором создается сокет для передачи данных с использованием протокола TCP:
Удаление сокета
Для освобождения ресурсов приложение должно закрывать сокеты, которые ему больше не нужны, вызывая функцию closesocket :
Ниже мы перечислили коды ошибок для этой функции :
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции closesocket необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAENOTSOCK | Указанный в параметре дескриптор не является сокетом |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEINTR | Работа функции была отменена при помощи функции WSACancelBlockingCall |
Параметры сокета
Перед использованием вы должны задать параметры сокета.
Для этого вы должны подготовить структуру типа sockaddr , определение которой показано ниже:
Для работы с адресами в формате Internet используется другой вариант этой структуры, в котором детализируется формат поля sa_data:
Поле sin_family определяет тип адреса. Вы должны записать в это поле значение AF_INET , которое соответствует типу адреса, принятому в Internet:
Поле sin_port определяет номер порта, который будет использоваться для передачи данных.
Порт — это просто идентификатор программы, выполняющей обмен на сети. На одном узле может одновременно работать несколько программ, использующих разные порты.
Особенностью поля sin_port является использование так называемого сетевого формата данных. Этот формат отличается от того, что принят в процессорах с архитектурой Intel , а именно, младшие байты данных хранятся по старшим адресам памяти . Напомним, что архитектура процессоров Intel подразумевает хранение старщих байтов данных по младшим адресам.
Универсальный сетевой формат данных удобен при организации глобальных сетей, так как в узлах такой сети могут использоваться компьютеры с различной архитектурой.
Для выполнения преобразований из обычного формат в сетевой и обратно в интерфейсе Windows Sockets предусмотрен специальный набор функций. В частности, для заполнения поля sin_port нужно использовать функцию htons, выполняющую преобразование 16-разрядных данных из формата Intel в сетевой формат.
Ниже мы показали, как инициализируется поле sin_port в приложении SERVER, описанном далее:
Вернемся снова к структуре sockaddr_in .
Поле sin_addr этой структуры представляет собой структуру in_addr:
При инициализации сокета в этой структуре вы должны указать адрес IP, с которым будет работать данный сокет.
Если сокет будет работать с любым адресом (например, вы создаете сервер, который будет доступен из узлов с любым адресом), адрес для сокета можно указать следующим образом:
В том случае, если сокет будет работать с определенным адресом IP ( например, вы создаете приложение-клиент , которое будет обращаться к серверу с конкретным адресом IP), в указанную структуру необходимо записать реальный адрес.
Датаграммный протокол UDP позволяет посылать пакеты данных одновременно всем рабочим станциям в широковещательном режиме. Для этого вы должны указать адрес как INADDR_BROADCAST.
Если вам известен адрес в виде четырех десятичных чисел, разделенных точкой (именно так его вводит пользователь), то вы можете заполнить поле адреса при помощи функции inet_addr :
В случае ошибки функция возвращает значение INADDR_NONE , что можно использовать для проверки.
Обратное преобразование адреса IP в текстовую строку можно при необходимости легко выполнить с помощью функции inet_ntoa , имеющей следующий прототип:
При ошибке эта функция возвращает значение NULL.
Однако чаще всего пользователь работает с доменными именами, используя сервер DNS или файл HOSTS . В этом случае вначале вы должны воспользоваться функцией gethostbyname , возвращающей адрес IP, а затем записать полученный адрес в структуру sin_addr :
В случае ошибки функция gethostbyname возвращает NULL. При этом причину ошибки можно выяснить, проверив код возврата функции WSAGetLastError .
Если же указанный узел найден в базе DNS или в файле HOSTS , функция gethostbyname возвращает указатель на структуру hostent , описанную ниже:
Искомый адрес находится в первом элемента списка h_addr _list[0], на который можно также ссылаться при помощи h_addr. Длина поля адреса находится в поле h_length.
Привязка адреса к сокету
После того как вы подготовили структуру SOCKADDR , записав в нее параметры сокета (в частности, адрес), следует выполнить привязку адреса к сокету при помощи функции bind :
Параметр sock должен содержать дескриптор сокета, созданного функцией socket .
В поле addr следует записать указатель на подготовленную структуру SOCKADDR , а в поле namelen — размер этой структуры.
В случае ошибки функция bind возвращает значение SOCKET_ERROR . Дальнейший анализ причин ошибки следует выполнять при помощи функции WSAGetLastError . Возможные коды ошибок перечислены ниже:
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEADDRINUSE | Указанный адрес уже используется |
WSAEFAULT | Значение параметра namelen меньше размера структуры sockaddr |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEAFNOSUPPORT | Этот протокол не может работать с указанным семейством адресов |
WSAEINVAL | Сокет уже привязан к адресу |
WSAENOBUFS | Установлено слишком много соединений |
WSAENOTSOCK | Указанный в параметре дескриптор не является сокетом |
Пример вызова функции bind показан ниже:
5.4. Создание канала связи
Если вы собираетесь передавать датаграммные сообщения при помощи протокола негарантированной доставки UDP , канал связи не нужен. Сразу после создания сокетов и их инициализации можно приступать к передаче данных. Но для передачи данных с использованием протокола TCP необходимо создать канал связи.
Сторона сервера
Рассмотрим процедуру создания канала связи со стороны сервера.
Прежде всего вы должны переключить сокет в режим приема для выполнения ожидания соединения с клиентом при помощи функции listen:
Через параметр sock функции необходимо передать дескриптор сокета, который будет использован для создания канала. Параметр backlog задает максимальный размер очереди для ожидания соединения (можно указывать значения от 1 до 5). Очередь содержит запросы на установку соединений для каждой пары значений (адрес IP, порт).
Ниже мы привели список возможных кодов ошибок для функции listen.
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEADDRINUSE | Указанный адрес уже используется |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEINVAL | Сокет еще не был привязан к адресу или уже находится в подключенном состоянии |
WSAEISCONN | Сокет уже находится в подключенном состоянии |
WSAEMFILE | Недостаточно дескрипторов файлов |
WSAENOBUFS | Нет места для размещения буфера |
WSAENOTSOCK | Указанный в параметре дескриптор не является сокетом |
WSAEOPNOTSUPP | Функция listen не работает с сокетом указанного типа |
Ниже мы привели пример вызов функции listen:
Далее необходимо выполнить ожидание соединения. Это можно выполнить двумя различными способами.
Первый способ заключается в циклическом вызове функции accept до тех пор, пока не будет установлено соединение. Затем можно будет приступать к обмену данными.
Функция accept имеет следующий прототип:
Через параметр sock необходимо указать дескриптор сокета, который находится в режиме приема для выполнения ожидания.
Параметр addr должен содержать адрес буфера, в который будет записан адрес узла, подключившегося к серверу. Размер этого буфера необходимо указать в переменной типа int , адрес которой передается через параметр addrlen.
Если ожидание соединения в цикле не вызывает у вас особого энтузиазма, можно предложить более удобный способ, основанный на использовании расширения программного интерфейса Windows Socket , предназначенного для выполнения асинхронных операций.
Приведем список возможных кодов ошибок для функции accept .
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEFAULT | Значение параметра addrlen меньше размера структуры адреса |
WSAEINTR | Работа функции была отменена при помощи функции WSACancelBlockingCall |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEINVAL | Перед вызовом функции accept не была вызывана функция listen |
WSAEMFILE | Нет доступных дескрипторов |
WSAENOBUFS | Установлено слишком много соединений |
WSAENOTSOCK | Указанный в параметре дескриптор не является сокетом |
WSAEOPNOTSUPP | Данный тип сокета нельзя использовать при вызове функций, ориентированных на работу с каналом связи |
WSAEWOULDBLOCK | Сокет отмечен как неблокирующий и в настоящее время нет каналов связи, которые нужно устанавливать |
Вместо того чтобы ожидать соединение, вызывая в цикле функцию accept , ваше приложение может вызвать один раз функцию WSAAsyncSelect , указав ей, что при получении запроса на установку соединения функция окна вашего приложения должна получить сообщение:
В данном случае ожидание соединения выполняется для сокета srv_socket . Последний параметр функции имеет значение FD_ACCEPT . Это означает, что при попытке создания канала связи функция окна с идентификатором hWnd получит сообщение WSA_ACCEPT, определенное в вашем приложении.
Обработчик этого сообщения может выглядеть, например, следующим образом:
В данном случае обработчик сообщения вначале вызывает функцию accept , выполняющую создание канала передачи данных. После этого функция WSAAsyncSelect вызывается еще один раз для того чтобы установить асинхронную обработку приема данных от удаленного клиента, а также обработку ситуации разрыва канала связи.
Сторона клиента
Рассмотрим процедуру установки канала связи со стороны клиента, использованную нами в приложении CLIENT, исходные тексты которого будут приведены ниже.
Для установки соединения в приложении используется функция SetConnection:
Вначале с помощью функции socket эта функция создает сокет. Затем выполняется заполнение адресной информацией структуры dest_sin.
Обратите внимание, что для получения адреса IP мы воспользовались функцией gethostbyname , указав ей имя узла localhost .
Это имя отображается в файле HOSTS на адрес 127.0.0.1 :
- localhost
Адрес 127.0.0.1 является локальным. Вы можете использовать его для тестирования приложений, выполняющих обмен данными при помощи протокола TCP/IP, запуская сервер и клиент на одном и том же компьютере.
После заполнения структуры с адресной информацией функция connect создает канал связи с сервером.
5.5. Передача и прием данных
После того как канал создан, можно начинать передачу данных. Для передачи данных при помощи протокола гарантированной доставки TCP вы можете воспользоваться функциями send и recv , которые входят в программный интерфейс Windows Sockets.
Функция передачи данных send имеет три параметра — дескриптор сокета sock, на котором выполняется передача, адрес буфера buf, содержащего передаваемое сообщение, размер этого буфера bufsize и флаги flags:
В нашем приложении CLIENT мы передаем данные серверу следующим образом:
Параметры функции recv , предназначенной для приема данных, аналогичны параметрам функции send :
Заметим, что функции recv и send возвращают количество, соответственно, принятых и переданных байт данных. Приложение, которое принимает данные, должно вызывать функцию recv в цикле до тех пор, пока не будут приняты все переданные данные. При этом на один вызов функции send может приходиться несколько вызовов функции recv.
В случае ошибки обе эти функции возвращают значение SOCKET_ERROR . Для анализа причин возникновения ошибки следует воспользоваться функцией WSAGetLastError .
Приведем список кодов ошибок, которые могут возникать при вызове команды send:
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEACCES | Указанный адрес является широковещательным ( broadcast ), однако перед вызовом функции не был установлен соответствующий флаг |
WSAEINTR | Работа функции была отменена при помощи функции WSACancelBlockingCall |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEFAULT | Параметр buf указан неправильно (он не указывает на адресное пространство, принадлежащее приложению) |
WSAENETRESET | Необходимо сбросить соединение |
WSAENOBUFS | Возникла блокировка буфера |
WSAENOTCONN | Сокет не подсоединен |
WSAENOTSOCK | Указанный в параметре дескриптор не является сокетом |
WSAESHUTDOWN | Сокет был закрыт функцией shutdown |
WSAEWOULDBLOCK | Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировке |
WSAEMSGSIZE | Был использован сокет типа SOCK_DGRAM (предназначенный для передачи датаграмм). При этом размер пакета данных превышает максимально допустимый для данной реализации интерфейса Windows Sockets |
WSAEINVAL | Сокет не был подключен функцией bind |
WSAECONNABORTED | Сбой из-за слишком большой задержки или по другой причине |
WSAECONNRESET | Сброс соединения удаленным узлом |
При выполнении функции recv могут возникать следующие ошибки:
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAENOTCONN | Сокет не подсоединен |
WSAEINTR | Работа функции была отменена при помощи функции WSACancelBlockingCall |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAENOTSOCK | Указанный в параметре дескриптор не является сокетом |
WSAESHUTDOWN | Сокет был закрыт функцией shutdown |
WSAEWOULDBLOCK | Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировке |
WSAEMSGSIZE | Размер пакета данных превышает размер буфера, в результате чего принятый пакет был обрезан |
WSAEINVAL | Сокет не был подключен функцией bind |
WSAECONNABORTED | Сбой из-за слишком большой задержки или по другой причине |
WSAECONNRESET | Сброс соединения удаленным узлом |
Передача и прием данных в цикле может привести к блокировке работы приложения. Если это неприемлимо, следует воспользоваться асинхронным расширением интерфейса Windows Sockets.
Наше приложение SERVER демонстрирует асинхронный прием данных.
После установки канала связи оно вызывает функцию WSAAsyncSelect , указывая ей в качестве последнего параметра комбинацию констант FD_READ и FD_CLOSE . При этом функция главного окна приложения будет получать сообщение WSA_NETEVENT в тот момент времени, когда чтение данных не вызовет блокировки приложения:
При необходимости выполнения асинхронной посылки данных вы можете указать функции WSAAsyncSelect еще и параметр FD_WRITE .
Если функция WSAAsyncSelect выполнилась успешно, она возвращает нулевое значение, при ошибке — значение SOCKET_ERROR .
В зависимости от значения последнего параметра могут возникать разные коды ошибки, которые можно получить при помощи функции WSAGetLastError. Следующие ошибки могут возникнуть при любом значении параметра:
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEINVAL | Сокет не был подключен функцией bind |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
Дополнительный код ошибки можно получить из параметра lParam при помощи макрокоманды WSAGETSELECTERROR .
При использовании параметра FD_CONNECT возможно появление следующих ошибок:
Код ошибки | Описание |
WSAEADDRINUSE | Указанный адрес уже используется |
WSAEADDRNOTAVAIL | Указанный адрес не доступен |
WSAEAFNOSUPPORT | Для данного сокета нельзя использовать указанное семейство адресов |
WSAECONNREFUSED | Попытка установления канала связи была отвергнута |
WSAEDESTADDRREQ | Необходимо указать адрес получателя пакета |
WSAEFAULT | Неправильно указан параметр namelen |
WSAEINVAL | Сокет уже подключен к адресу |
WSAEISCONN | Сокет уже подсоединен |
WSAEMFILE | Больше нет доступных дескрипторов |
WSAENETUNREACH | Из данного узла и в данное время невозможно получить доступ к сети |
WSAENOBUFS | Нет места для размещения буфера |
WSAENOTCONN | Сокет на подключен |
WSAENOTSOCK | Указан дескриптор файла, а не сокета |
WSAETIMEDOUT | При попытке установления канала связи возникла задержка во времени |
Если используется параметр FD_CLOSE, может возникнуть одна из следующих ошибок:
Код ошибки | Описание |
WSAENETDOWN | Сбой в сети |
WSAECONNRESET | Сброс соединения удаленным узлом |
WSAECONNABORTED | Сбой из-за слишком большой задержки или по другой причине |
В том случае, когда указаны параметры FD_READ , FD_WRITE , FD_OOB , или FD_ACCEPT , может возникнуть ошибка с кодом WSAENETDOWN .
Обработчик сообщения WSA_NETEVENT должен выполнить анализ причины, по которой он был вызван, так как за один вызов функции WSAAsyncSelect можно задать несколько событий, вызывающих генерацию сообщения. Этот анализ проводится, например, следующим образом:
Отметим, что параметр wParam содержит дескриптор сокета, на котором выполняется передача данных, а параметр lParam — код события, которое произошло в сети.
5.6. Приложение SERVER
В этом разделе мы представим вам исходные тексты приложения SERVER, которое выполняет прием сообщений от приложения CLIENT с использованием протокола гарантированной доставки TCP и канала связи. При необходимости вы сможете самостоятельно организовать передачу данных в обратном направлении.
Вы можете запускать приложения SERVER и CLIENT как на одном, так и на разных компьютерах, соединенных локальной или глобальной сетью TCP/IP. В случае запуска этих приложений на одном и том же компьютере в качестве адреса IP используется локальный тестовый адрес 127.0.0.1 .
Создавая проект для этого, а также всех остальных приложений, приведенных в нашей книге, вы должны указать, что для разрешения внешних ссылок необходимо использовать библиотеки объектных модулей wsock32.lib и comctl32.lib . Первая из них нужна для работы с программным интерфейсом Windows Sockets, вторая — для работы с органом управления Statusbar .
Для подключения указанных библиотек из меню Build системы разработки Microsoft Visual C++ версии 4.0 нужно выбрать строку Settings . На экране появится блокнот project Settings, который следует открыть на странице Link. Затем вы должны дописать названия библиотек в поле Object/library modules и нажать кнопку OK.
Исходный текст приложения SERVER представлен в листинге 5 .1.
Листинг 5 .1. Файл server/server.c
Функция WinMain сохраняет идентификатор приложения и затем проверяет, не было ли это приложение уже запущено. При этом используется техника, описанная нами в 22 томе «Библиотеки системного программиста», который называется «Операционная система Windows 95 для программиста».
Далее выполняется обычная регистрация класса главного окна приложения, инициализируется библиотека орагнов управления общего назначения и создается главное окно приложения. После этого окно отображается на экране и запускается цикл обработки сообщений.
Функция окна WndProc обрабатывает как стандартные сообщения WM_CREATE , WM_COMMAND , WM_SIZE , WM_DESTROY , так и сообщения WSA_ACCEPT и WSA_NETEVENT. Первое из них возникает при установке канала связи с клиентом, второе — при поступлении данных от клиента и при разрыве канала связи.
Обработчик сообщения WM_CREATE инициализирует библиотеку Windows Sockets и создает орган управления Statusbar . В окне этого органа управления отображается текущая версия и описание состояния системы Windows Sockets. Если вы не знакомы с указанным органам управления, отсылаем вас к упомянутому 22 тому «Библиотеки системного программиста».
Обработчик сообщения WM_DESTROY вызывает функцию WSACleanup , освобождающую ресурсы, полученные для приложения у системы Windows Sockets и затем завершает цикл обработки сообщений.
Единственное назначение обработчика сообщений WM_SIZE заключается в изменении размеров окна органа управления Statusbar при изменении размеров главного окна приложения.
Обработчик сообщения WM_COMMAND получает управление, когда пользователь выбирает одну из строк в меню File главного меню приложения. Если пользователь выберет строку Start server, будет вызвана функция ServerStart, назначение которой очевидно из ее названия. Аналогично, при выборе строки Stop server будет вызвана функция ServerStop. Если же из меню File выбрать строку Exit, будет уничтожено главное окно приложения.
Функция ServerStart создает сокет для работы с потоком данных и инициализирует его. При этом мы используем произвольно выбранный порт с номером 5000.
Далее функция выполняет привязку сокета к адресу и переключает сокет в режим приема для выполнения ожидания соединения с клиентом, т. е. выполняет описанные нами ранее действия, необходимые для создания канала связи.
Затем вызывается функция WSAAsyncSelect , которой в качестве последнего параметра передается значение FD_ACCEPT , а в качестве предпоследнего — значение WSA_ACCEPT. В результате при поступлении от клиента запроса на создание канала связи функция главного окна приложения получит сообщение WSA_ACCEPT.
Перед возвратом управления функция ServerStart выводит сообщение о запуске сервера в окне органа управления Statusbar .
Функция ServerStop отменяет все извещения, поступающие в главное окно приложения при возникновении событий в сети, вызывая функцию WSAAsyncSelect с нулевым значением двух последних параметров:
Затем она закрывает сокет, вызывая функцию closesocket , и выводит в окне органа управления Statusbar сообщение о завершении работы сервера .
Функция WndProc_OnWSAAccept обрабатывает сообщение WSA_ACCEPT, выполняя описанную нами ранее процедуру создания канала связи.
И, наконец, функция WndProc_OnWSANetEvent выполняет прием строки сообщения, полученной от клиента с отображением этой строки на экране в диалоговой панели.
Файл resource.h, показанный в листинге 5 .2 создается автоматически и содержит описание идентификаторов ресурсов приложения.
Листинг 5 . 2 . Файл server/resource.h
Ресурсы приложения определены в файле server.rc, который представлен в листинге 5 .3.
Листинг 5 . 3 . Файл server/server.rc
5.7. Приложение CLIENT
Исходные тексты приложения CLIENT , предназначенного для совместного использования с только что описанным приложением SERVER, приведены в листинге 5 .4.
После запуска этого приложения вы должны создать канал связи с приложением SERVER, выбрав из меню File строку Connect, после чего можно посылать сообщение Test message, выбирая из этого же меню строку Send Message.
Сервер, получив сообщение, отобразит его на экране в отдельной диалоговой панели.
Листинг 5 .4. Файл client/client.c
Вы сможете разобраться с исходными текстами этого прилжоения самостоятельно, так как все использованные в нем функции были нами уже описаны. Обратим ваше внимание только на функцию SetConnection, предназначенную для установки канала связи с сервером.
Если вы будете проверять работу приложений SERVER и CLIENT на одном и том же компьютере, адрес сервера должен быть указан следующим образом:
Для того чтобы установить канал связи с компьютером по его имени, закройте символом комментария приведенную выше строку и уберите символ комментария со строки, расположенной ниже:
Разумеется, вы должны также изменить имя компьютера.
Можно также указать адрес узла в виде десятичных цифр, для чего следует убрать символ комментария со следующей строки:
Идентификаторы ресурсов приложения CLIENT определены в файле resource.h, представленном в листинге 5 .5.
Листинг 5 .5. Файл client/resource.h
Файл client.rc (листинг 5 .6) содержит определения ресурсов приложения.
Листинг 5 . 6 . Файл client/client.rc
5.8. Приложение SERVERD
В некоторых случаях целесообразно использовать протокол негарантированной доставки UDP , так как он, например, допускает одновременную рассылку пакетов всем узлам сети (в режиме broadcast).
Если узлы обмениваются данными с использованием датаграммного протокола UDP , им не требуется создавать канал данных, поэтому процедура инициализации получается проще.
Сервер UDP должен создать сокет с помощью функции socket и привязать к нему адрес IP , вызвав функцию bind . Клиент UDP выполняет создание и инициализацию сокетов аналогичным образом с помощью все тех же функций socket и bind .
Такие известные вам из предыдущих приложений функции, как connect, listen и accept в приложениях UDP использовать не нужно.
Для обмена данными приложения UDP вызывают функции send to и recv from, аналогичные функциям send и recv, но имеющие одно отличие — при вызове этих функций им необходимо задавать дополнительные параметры, имеющие отношение к адресам узлов. Функции sendto нужно указать адрес, по которому будет отправлен пакет данных, а функции recvfrom — указатель на структуру, в которую будет записан адрес отправителя пакета.
В нашей книге мы привели исходные тексты приложений SERVERD и CLIENTD, которые выполняют те же задачи, что и только что рассмотренные приложения SERVER и CLIENT, но при этом они передают данные при помощи датаграммного протокола UDP .
Исходный текст приложения SERVERD приведен в листинге 5.7.
Листинг 5.7. Файл serverd/serverd.c
Приложение SERVERD во многом напоминает приложение SERVER, поэтому мы рассмотрим только отличия.
Первое отличие заключается в том, что при запуске сервера тип создаваемого сокета указывается как SOCK_DGRAM:
Далее выполняется инициализация сокета и его привязка к адресу, для чего вызывается функция bind . Эта операция, как и в случае протокола TCP , не обязательна.
После выполнения привязки можно приступать к получению пакетов данных от клиента. Для того чтобы не выполнять ожидание пакетов в цикле, наше приложение использует функцию WSAAsyncSelect , указывая с ее помощью, что при получении пакетов данных главное окно приложения должно получать сообщения с кодом WSA_NETEVENT:
На этом инициализация сервера завершается.
Обработчик сообщения WSA_NETEVENT читает полученный пакет с помощью функции recv from:
В качестве предпоследнего параметра этой функции передается адрес структуры типа SOCKADDR _IN, куда функция записывает адрес узла, приславшего пакет. Последний параметр функции recv from должен содержать размер указанной структуры.
Ниже мы привели возможные коды ошибок для функции recv from.
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEFAULT | Слишком малое значение параметра, определяющего размер буфера для приема данных |
WSAEINTR | Работа функции была отменена при помощи функции WSACancelBlockingCall |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEINVAL | Сокет не был подключен функцией bind |
WSAENOTSOCK | Указанный дескриптор не является дескриптором сокета |
WSAESHUTDOWN | Сокет был закрыт функцией shutdown |
WSAEWOULDBLOCK | Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировке |
WSAEMSGSIZE | Размер датаграммы слишком большой, поэтому соответствующий блок данных не помещается в буфер. Принятый блок данных был обрезан |
WSAECONNABORTED | Сбой из-за слишком большой задержки или по другой причине |
WSAECONNRESET | Сброс соединения удаленным узлом |
Заметим, что при обмене данных с использованием протокола UDP на каждый вызов функции send to должен приходиться один вызов функции recv from. Если же вы передается данные через канал с использованием протокола TCP, на один вызов функции send может приходиться несколько вызовов функции recv.
Для отображения адреса узла, пославшего пакет UDP , наше приложение преобразует этот адрес в символьную строку с помощью функции inet_ntoa :
Эта функция записывает полученную строку в статическую область памяти, принадлежащую системе Windows Sockets, поэтому для дальнейшего использования необходимо скопировать строку до следующего вызова любой функции программного интерфейса Windows Sockets .
5.9. Приложение CLIENTD
Исходные тексты приложения CLIENTD , предназначенного для совместной работы с приложением SERVERD, представлены в листинге 5.8. Так как это приложение очень похоже на приложение CLIENT, мы опишем только отличия.
Листинг 5.8. Файл clientd/clientd.c
Функция SetConnection создает сокет типа SOCK_DGRAM, так как передача данных будет выполняться с использованием протокола UDP :
Далее выполняется привязка сокета к адресу с помощью функции bind . При этом указывается нулевое значение порта и адрес INADDR_ANY , так как на данном этапе эти параметры не имеют значения.
Затем функция SetConnection записывает адрес сервера в структуру dest_sin. Этот адрес потребуется для передачи сообщений серверу.
При использовании протокола UDP и если не создан канал между приложениями, для передачи данных следует использовать функцию send to:
В качестве предпоследнего параметра этой фукнции нужно передать адрес заполненной структуры, содержащей адрес узла, куда будет посылаться пакет данных. Через последний параметр функции send to необходимо передать размер указанной структуры.
Привдедем список возможных кодов ошибок для функции send to:
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEACCES | Не был установлен флаг широковещательного адреса |
WSAEINTR | Работа функции была отменена при помощи функции WSACancelBlockingCall |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEFAULT | Неправильно указан адрес буфера, содержащего передаваемые данные |
WSAENETRESET | Необходимо сбросить соединение |
WSAENOBUFS | Произошло зацикливание буферов |
WSAENOTSOCK | Указанный дескриптор не является дескриптором сокета |
WSAESHUTDOWN | Сокет был закрыт функцией shutdown |
WSAEWOULDBLOCK | Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировке |
WSAEMSGSIZE | Размер датаграммы больше, чем это допускается данной реализацией интерфейса Windows Sockets |
WSAECONNABORTED | Сбой из-за слишком большой задержки или по другой причине |
WSAECONNRESET | Сброс соединения удаленным узлом |
WSAEADDRNOTAVAIL | Указанный адрес недоступен |
WSAEAFNOSUPPORT | Данный тип сокета не может работать с указанным семейством адресов |
WSAEDESTADDRREQ | Необходимо указать адрес получателя датаграммы |
WSAENETUNREACH | В данное время и из данного узла невозможно получить доступ к сети |
Заметим, что клиент может создать канал связи с сервером, вызвав функцию connect, и передавать по этому каналу пакеты UDP , пользуясь функциями send и recv . Этот способ удобен тем, что при передаче пакета не нужно каждый раз указывать адрес получателя.