Как мы уже не раз говорили, дейтаграмма UDP должна быть прочитана из буфера сокета целиком. Если в буфере, переданном функции recv
recvfrom
, недостаточно места для получения дейтаграммы, эти функции завершаются с ошибкой. При этом в буфер помещается та часть дейтаграммы, которая может в нем поместиться, а оставшаяся часть дейтаграммы теряется. Функция WSARecvEx
отличается от recv
только тем, что в случае, когда размер буфера меньше размера дейтаграммы, она завершается без ошибки (возвращая при этом размер прочитанной части дейтаграммы, т.е. размер буфера) и добавляет флаг MSG_PARTIAL
к параметру flags
. Остаток дейтаграммы при этом также теряется. Таким образом, WSARecvEx
дает альтернативный способ проверки того, что дейтаграмма не поместилась в буфер, и в некоторых случаях этот способ может оказаться удобным.Если при вызове функции WSARecvEx
MSG_PARTIAL
установлен программой, но дейтаграмма поместилась в буфер целиком, функция сбрасывает этот флаг.В описании функции WSARecvEx
Функция WSARecvEx
recvfrom
с такими же возможностями в WinSock нет.Мы уже упоминали о том, что в WinSock 1 существует перекрытый ввод-вывод, но только для систем линии NT. Также в WinSock 1 определена функция AcceptEx
accept
, и позволяет принимать входящие соединения в режиме перекрытого ввода-вывода. В WinSock 1 эта функция не поддерживается в Windows 95, в WinSock 2 она доступна во всех системах. Листинг 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).TOverlapped
POverlapped = TOverlapped;
_OVERLAPPED = record
Internal: DWORD;
InternalHigh: DWORD;
Offset: DWORD;
OffsetHigh: DWORD;
hEvent: THandle;
end;
TOverlapped = _OVERLAPPED;