Из сказанного следует, что при использовании протокола TCP функция
WSAAccept
по сравнению с accept даёт два принципиальных преимущества: позволяет управлять качеством обслуживания и запрещать подключение нежелательных клиентов.
Некоторые протоколы поддерживают передачу информации не только при установлении связи, но и при её завершении. Для таких протоколов в WinSock2 предусмотрены функции
WSASendDisconnect
и
WSARecvDisconnect
. Так как протокол TCP не поддерживает передачу данных при закрытии соединения, для него эти функции не дают никаких преимуществ по сравнению с вызовом функции
shutdown
, поэтому мы не будем их здесь рассматривать.
Далее мы рассмотрим несколько новых
функций, унифицирующих работу с различными протоколами.
Функция
inet_addr
, как это уже упоминалось, жестко связана с протоколом IP и не имеет смысла для других протоколов. WinSock 2 предлагает вместо нее функцию
WSAStringToAddress
, имеющую следующий прототип (листинг 2.43).
Листинг 2.43. Функция
WSAStringToAddress
// ***** Описание на C++ *****
INT WSAStringToAddress(LPTSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFO lpProtocolInfo, LPSOCKADDR lpAddress, LPINT lpAddressLength);
// ***** Описание на Delphi *****
function WSAStringToAddress(AddresString: PChar; AddressFamily: Integer; lpProtocolInfo: PWSAProtocolInfo; var Address: TSockAddr; var AddressLength: Integer): Integer;
Данная функция преобразует строку, задающую адрес сокета, в адрес, хранящийся в структуре
TSockAddr
. Параметр
AddressString
указывает на строку, хранящую адрес, параметр
AddressFamily
— на семейство адресов, для которого осуществляется трансляция. Если есть необходимость выбрать конкретный провайдер для протокола, в функцию может быть передан параметр
lpProtocolInfo
, в котором указан идентификатор провайдера. Если же программу устраивает провайдер по умолчанию, параметр
lpProtocolInfo
должен быть равен
nil
. Адрес возвращается через параметр
Address
. Параметр
AddressLength
при вызове функции должен содержать размер буфера, переданного через
Address
, а на выходе содержит реально использованное число байтов в буфере.
Функция возвращает 0 в случае успешного выполнения и
SOCKET_ERROR
— при ошибке.
Допустимый формат строки определяется протоколом (некоторые протоколы вообще не поддерживают текстовую запись адреса, и для них функция
WSAStringToAddress
неприменима). Для семейства
AF_INET
, к которому относятся TCP и UDP, адрес может задаваться в виде "IP1.IP2.IP3.IР4:Port" или "IP1.IP2.IP3.IP4", где IРn — n– й компонент IP-адреса, записанною в виде 4-байтных полей,
Port
— номер порта. Если порт явно не указан, устанавливается нулевой номер порта.
Таким образом, чтобы в структуре
TSockAddr
оказался, например, адрес 192.168.100.217 и порт с номером 5000, необходимо выполнить следующий код (листинг 2.44).
function WSAAddressToString(var Address: TSockAddr; dwAddressLength: DWORD; lpProtocolInfo: PWSAProtocolInfo; lpszAddressString: PChar; var AddressStringLength: DWORD): Integer;
Как нетрудно догадаться по названию функции, она преобразует адрес, заданный структурой
TSockAddr
, в строку. Адрес задаётся параметром
Address
, параметр
dwAddressLength
определяет длину буфера
Address
. Необязательный параметр
lpProtocolInfo
содержит указатель на структуру
TWSAProtocolInfo
, с помощью которой можно определить, какой именно провайдер должен выполнить преобразование. Параметр
lpszAddressString
содержит указатель на буфер, заранее выделенный программой, в который будет помещена строка. Параметр
AddressStringLength
на входе должен содержать размер буфера, заданного параметром
lpszAddressString
, а на выходе содержит длину получившейся строки.
Функция возвращает ноль в случае успеха и
SOCKET_ERROR
— при ошибке. Ранее мы уже обсуждали различные форматы представления целых чисел, а также то, что формат, предусмотренный сетевым протоколом, может не совпадать с форматом, используемым узлом. Напомним, что для преобразования из сетевого формата в формат узла предназначены функции
htons
,
ntohs
,
htonl
и
ntohl
, привязанные к протоколам стека TCP/IP (другие протоколы могут иметь другой формат представления чисел). WinSock 2 предлагает аналоги этих функций
WSAHtons
,
WSANtohs
,
WSAHtonl
и
WSANtohl
, которые учитывают особенности конкретного протокола. Мы здесь рассмотрим только функцию
WSANtohl
, преобразующую 32-битное целое из сетевого формата в формат узла. Остальные три функции работают аналогично. Листинг 2.46 содержит прототип функции
WSANtohl
.
Листинг 2.46. Функция
WSANtohl
// ***** Описание на C++ *****
int WSANtohl(SOCKET s, u_long netlong, u_long FAR *lphostlong);
// ***** Описание на Delphi *****
function WSANtohl(S: TSocket; NetLong: Cardinal; var HostLong: Cardinal): Integer;
Параметр
S
задает сокет, для которого осуществляется преобразование. Так как сокет всегда связан с конкретным протоколом, этого параметра достаточно, чтобы библиотека могла определить, по какому закону преобразовывать число из сетевого формата в формат хоста. Число в сетевом формате задаётся параметром
NetLong
, результат преобразования помещается в параметр
HostLong
.
Функция возвращает ноль в случае успешного выполнения операции и
SOCKET_ERROR
— при ошибке.
Если программа работает только с протоколами стека TCP/IP, старые варианты функций удобнее новых, потому что возвращают непосредственно результат преобразования, который можно использовать в выражениях. При работе с новыми функциями для получения результата следует заводить отдельную переменную, поэтому эти функции целесообразны тогда, когда программа должна единым образом работать с разными протоколами. Последняя функция, которую мы здесь рассмотрим, не имеет прямых аналогов среди старых функций. Называется она
WSADuplicateSocket
и служит для копирования дескриптора сокета в другой процесс. Прототип функции