не предусмотрены параметры для задания адреса сетевого интерфейса, через который следует получать групповые сообщения, поэтому всегда используется интерфейс, выбираемый системой для этих целей по умолчанию. Выбрать интерфейс, который система будет назначать по умолчанию, можно с помощью параметра сокета
IP_MULTICAST_IF
. Этот параметр имеет тип
TSockAddr
, причем значимыми полями структуры в данном случае являются
sin_family
и
sin_addr
, а значение поля
sin_port
игнорируется.
Значения констант
IP_MULTICAST_IF
,
IP_MULTICAST_TTL
и
IP_MULTICAST_LOOP
также зависят от версии WinSock. В WinSock 1 они должны быть равны 2, и 4, а в WinSock 2 — 9, 10 и 11 соответственно.
2.2.12. Дополнительные функции
В этом разделе мы рассмотрим некоторые функции, относящиеся в WinSock к дополнительным. В WinSock 1 эти функции вместе со всеми остальными экспортируются библиотекой WSock32.dll, а в WinSock 2 они вынесены в отдельную библиотеку MSWSock.dll (в эту же библиотеку вынесены некоторые устаревшие функции типа
EnumProtocols
).
Начнем мы знакомство с этими функциями с функции
WSARecvEx
(которая, кстати, является расширенной версией функции
recv
, а отнюдь не
WSARecv
, как это можно заключить из ее названия), имеющей следующий прототип:
function WSARecvEx(s: TSocket; var buf; len: Integer; var flags: Integer): Integer;
Видно, что она отличается от обычной функции
recv
только тем, что флаги передаются через параметр-переменную вместо значения. В функции
WSARecvEx
этот параметр не только входной, но и выходной; функция может модифицировать его. Ранее мы познакомились с функцией
WSARecv
, которая также может модифицировать переданные ей флаги, но условия, при которых эти две функции модифицируют флаги, различаются.
При использовании TCP (а также любого другого потокового протокола) флаги не изменяются функцией, и результат работы
WSARecvEx
эквивалентен результату работы
recv
.
Как мы уже не раз говорили, дейтаграмма UDP должна быть прочитана из буфера сокета целиком. Если в буфере, переданном функции
recv
или
recvfrom
, недостаточно места для получения дейтаграммы, эти функции завершаются с ошибкой. При этом в буфер помещается та часть дейтаграммы, которая может в нем поместиться, а оставшаяся часть дейтаграммы теряется. Функция
WSARecvEx
отличается от
recv
только тем, что в случае, когда размер буфера меньше размера дейтаграммы, она завершается без ошибки (возвращая при этом размер прочитанной части дейтаграммы, т.е. размер буфера) и добавляет флаг
MSG_PARTIAL
к параметру
flags
. Остаток дейтаграммы при этом также теряется. Таким образом,
WSARecvEx
дает альтернативный способ проверки того, что дейтаграмма не поместилась в буфер, и в некоторых случаях этот способ может оказаться удобным.
Если при вызове функции
WSARecvEx
флаг
MSG_PARTIAL
установлен программой, но дейтаграмма поместилась в буфер целиком, функция сбрасывает этот флаг.
В описании функции
WSARecvEx
в MSDN можно прочитать, что если дейтаграмма прочитана частично, то следующий вызов функции позволит прочитать оставшуюся часть дейтаграммы. Это не относится к протоколу UDP и справедливо только по отношению к протоколам типа SPX, в которых одна дейтаграмма может разбиваться на несколько сетевых пакетов и потому возможна ситуация, когда в буфере сокета окажется только часть дейтаграммы. В UDP, напомним, дейтаграмма всегда посылается одним IP-пакетом и помещается в буфер сразу целиком.
Функция
WSARecvEx
не позволяет программе определить, с какого адреса прислана дейтаграмма, а аналога функции
recvfrom
с такими же возможностями в WinSock нет.
Мы уже упоминали о том, что в WinSock 1 существует
перекрытый ввод-вывод, но только для систем линии NT. Также в WinSock 1 определена функция
AcceptEx
, которая является более мощным эквивалентом функции
accept
, и позволяет принимать входящие соединения в режиме перекрытого ввода-вывода. В WinSock 1 эта функция не поддерживается в Windows 95, в WinSock 2 она доступна во всех системах. Листинг 2.81 содержит ее прототип.
Листинг 2.81. Функция
AcceptEx
function AcceptEx(sListenSocket, sAcceptSocket: TSocket; lpOutputBuffer: Pointer; dwReceiveDataLength: DWORD; dwLocalAddressLength: DWORD; dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD; lpOverlapped: POverlapped): BOOL;
Функция
AcceptEx
позволяет принять новое подключение со стороны клиента и сразу же получить от него первую порцию данных. Функция работает только в режиме перекрытого ввода-вывода.
Параметр
sListenSocket
определяет сокет, который должен находиться в режиме ожидания подключения. Параметр
sAcceptSocket
— сокет, через который будет осуществляться связь с подключившимся клиентом. Напомним, что функции
accept
и
WSAAccept
сами создают новый сокет. При использовании же
AcceptEx
программа должна заранее создать сокет и, не привязывая его к адресу, передать в качестве параметра
sAcceptSocket
. Параметр
lpOutputBufer
задает указатель на буфер, в который будут помещены, во-первых, данные, присланные клиентом, а во-вторых, адреса подключившегося клиента и адрес, к которому привязывается сокет
sAcceptSocket
. Параметр
dwReceiveDataLength
задает число байтов в буфере, зарезервированных для данных, присланных клиентом,
dwLocalAddressLength
— для адреса привязки сокета
sAcceptSocket
,
dwRemoteAddressLength
— адреса подключившегося клиента. Если параметр
dwReceiveDataLength
равен нулю, функция не ждет, пока клиент пришлет данные, и считает операцию завершившейся сразу после подключения клиента, как функция accept. Для адресов нужно резервировать как минимум на 16 байтов больше места, чем реально требуется. Так как размер структуры
TSockAddr
составляет 16 байтов, на каждый из адресов требуется зарезервировать как минимум 32 байта. Параметр
lpdwBytesReceived
используется функцией, чтобы вернуть количество байтов, присланных клиентом.
Параметр
lpOverlapped
указывает на запись
TOverlapped
, определенную в модуле Windows следующим образом (листинг 2.82).
Листинг 2.82. Тип
TOverlapped
POverlapped = TOverlapped;
_OVERLAPPED = record
Internal: DWORD;
InternalHigh: DWORD;
Offset: DWORD;
OffsetHigh: DWORD;
hEvent: THandle;
end;
TOverlapped = _OVERLAPPED;
Структура
TOverlapped
используется, в основном, для перекрытого ввода-вывода в файловых операциях. Видно, что она отличается от уже знакомой нам структуры
TWSAOverlapped
(см. листинг 2.69) только типом параметра
hEvent
—
THandle
вместо
TWSAEvent
. Впрочем, ранее мы уже обсуждали, что
TWSAEvent
— это синоним
THandle
, так что можно сказать, что эти структуры идентичны (но компилятор подходит к этому вопросу формально и считает их разными).