Все перечисленные функции формально исключены из спецификации WinSock 2, хотя фактически они присутствуют в библиотеке WS2_32.dll и при необходимости могут быть задействованы (это, правда, осложняется тем, что в новых версиях MSDN отсутствует их описание). Тем не менее причин ориентироваться на эту неудобную модель в 32-разрядных версиях Windows, видимо, нет. Описание этих функций мы здесь привели только для того, чтобы упоминания об ошибках
WSAEINPROGRESS
и
WSAECANCELLED
, которые иногда встречаются в MSDN, не смущали вас.
2.2.3. Информация о протоколе
Ранее мы уже видели, что передача данных через сокет
осуществляется одними и теми же функциями независимо от протокола. Но при этом программа должна учитывать, является ли протокол потоковым, дейтаграммным или иным. Кроме того, информация о протоколе требуется для создания сокета и для распределения ролей между клиентом и сервером при установлении соединения. Чтобы работать с любым протоколом, программа должна иметь возможность получить всю эту информацию и выполнить на основе ее те или иные действия. Могут также понадобиться такие сведения, как максимальное число сокетов, поддерживаемых провайдером протокола, допустимый диапазон адресов, максимальный размер сообщений для дейтаграммных протоколов и т.д. Для хранения полного описания протокола и его провайдера в WinSock 2 предусмотрена структура
WSAPROTOCOL_INFO
. Она не описана в модуле WinSock, т.к. в WinSock 1 ее нет. Тем, кто захочет использовать эту структуру, придется самостоятельно добавлять ее описание в программу. Листинг 2.36 показывает, как выглядит эта структура.
Листинг 2.36. Тип
WSAPROTOCOL_INFO
// ***** Описание на C++ *****
typedef struct _WSAPROTOCOLCHAIN {
int ChainLen;
DWORD ChainEntries[MAX_PROTOCOL_CHAIN];
} WSAPROTOCOLCHAIN, *LPWSAPROTOCOLCHAIN;
typedef struct _WSAPROTOCOL_INFO {
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlgs4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
TCHAR szProtocol[WSAPROTOCOL_LEN - 1];
} WSAPROTOCOL_INFO, *LPWSAPROTOCOL_INFO;
// ***** Описание на Delphi *****
TWSAProtocolChain = packed record
ChainLen: Integer;
ChainEntries: array[0..MAX_PROTOCOL_CHAIN - 1] of DWORD;
end;
//Структура на C++ содержит тип TCHAR, который, как мы
// говорили в главе 1, может означать как Char,
//
так и WideChar, т.е. структура должна иметь
// два варианта описания: TWSAProtocolInfoA для
// однобайтной кодировки и TWSAProtocolInfo для
// двухбайтной. Соответственно, все функции
// использующие эту структуру, реализованы
// в системных библиотеках в двух вариантах.
// Здесь мы приводим только ANSI-вариант.
PWSAProtocolInfo = ^TWSAProtocolInfo;
TWSAProtocolInfo = packed record
dwServiceFlags1: DWORD;
dwServiceFlags2: DWORD;
dwServicsFlags3: DWORD;
dwServiceFlags4: DWORD;
dwProviderFlags: DWORD;
ProviderId: GUID;
dwCatalogEntryId: DWORD;
ProtocolChain: TWSAProtocolChain;
iVersion: Integer;
iAddressFamily: Integer;
iMaxSockAddr: Integer;
iMinSockAddr: Integer;
iSocketType: Integer;
iProtocol: Integer;
iProtocolMaxOffset: Integer;
iNetworkByteOrder: Integer;
iSecurityScheme: Integer;
dwMessageSize: DWORD;
dwProviderReserved: DWORD;
szProtocol: array [0..WSAPROTOCOL_LEN] of Char;
end;
Расшифровка полей типа
TWSAProtocolInfo
есть в MSDN, мы здесь не будем ее приводить.
Сама функция
WSAEnumProtocols
, которая позволяет получить список всех протоколов, провайдеры которых установлены на компьютере, приведена в листинге 2.37.
Листинг 2.37. Функция
WSAEnumProtocols
// ***** описание на C++ *****
int WSAEnumProtocols(LPINT lpiProtocols, LPWSAPROTOCOL_INFO lpProtocolBuffer, LPDWORD lpdwBufferLength);
// ***** Описание на Delphi *****
function WSAEnumProtocols(lpiProtocols: PInteger; lpProtocolBuffer: PWSAProtocolInfo; var BufferLength: DWORD): Integer;
Примечание
В старых версиях MSDN в описании этой функции есть небольшая опечатка: тип параметра
lpdwBufferLength
назван
LLPDWORD
вместо
LPDWORD
.
Библиотека WS2_32.dll придерживается тех же правил насчет ANSI- и Unicode-вариантов функций, что и другие системные библиотеки (см. разд. 1.1.12), поэтому в ней нет функции с именем
WSAEnumProtocols
, а есть
WSAEnumProtocolsA
и
WSAEnumProtocolsW
. Эти функции работают с разными вариантами структуры
WSAPROTOCOL_INFO
, которые различаются типом элементов в последнем массиве —