Чтение онлайн

ЖАНРЫ

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

2.2.4. Новые функции

В этом разделе мы рассмотрим некоторые новые функции, появившиеся в WinSock 2. Большинство из них позволяет выполнять действия, уже знакомые нам из предыдущих разделов, но предоставляет большие возможности, чем стандартные сокетные функции.

Для создания сокета предназначена функция

WSASocket
со следующим прототипом (листинг 2.38).

Листинг 2.38. Функция
WSASocket

// ***** Описание на C++ *****

SOCKET WSASocket(int af, int SockType, int protocol, LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags);

// ***** Описание на Delphi *****

function WSASocket(AF, SockType, Protocol: Integer; lpProtocolInfo: PWSAProtocolInfo; g: TGroup; dwFlags: DWORD): TSocket;

Первые три параметра совпадают

с тремя параметрами функции
socket
. Параметр
lpProtocolInfo
указывает на структуру
TWSAProtocolInfo
, содержащую информацию о протоколе, для которого создается сокет. Если этот указатель равен
nil
, функция создает сокет на основании первых трёх параметров так же, как это делает функция
socket
. С другой стороны, если этот параметр не равен
nil
, то структура, на которую он указывает, содержит всю информацию, необходимую для создания сокета, поэтому первые три параметра должны быть равны константе
FROM_PROTOCOL_INFO
(-1). Параметр
g
зарезервирован для использования в будущем и должен быть равен нулю (тип
TGroup 
совпадает с
DWORD
). Последний параметр
dwFlags
определяет, какие дополнительные возможности имеет создаваемый сокет. Вызов функции
socket
эквивалентен вызову функции
WSASocket
с флагом
WSA_FLAG_OVERLAPPED
, который показывает, что данный сокет можно использовать для перекрытого ввода-вывода (см. разд. 2.2.9). Остальные флаги нужны при многоадресной рассылке (не все из них допустимы для протоколов TCP и UDP). Эти флаги мы рассмотрим в разд. 2.2.11.

В случае TCP и UDP функция

WSASocket
дает следующие преимущества по сравнению с функцией
socket
. Во-первых, через параметр
lpProtocolInfo
появляется возможность явно указать провайдера, который будет выбран программой. Во-вторых, если программа не использует перекрытый ввод-вывод, можно создавать сокеты без флага
WSA_FLAG_OVERLAPPED
, экономя при этом некоторое незначительное количество ресурсов. Кроме того, как это будет обсуждаться далее, с помощью
WSASocket
две разных программы могут работать с одним и тем же сокетом.

Функция

WSAConnect
— это более мощный аналог
connect
. Ее прототип приведен в листинге 2.39.

Листинг 2.39. Функция
WSAConnect
и связанные с ней типы

// ***** Описание на C++ *****

int WSAConnect(SOCKET s, const struct sockaddr FAR* name, int name len, LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPQOS lpSQOS, LPQOS lpGQOS);

typedef struct __WSABUF {

 u_long len;

 char FAR *buf;

} WSABUF, FAR* LPWSABUF;

// ***** Описание на Delphi ******

function WSAConnect(S: TSocket; var Name: TSockAddr; NameLen: Integer; lpCollerData, lpCalleeData: PWSABuf; lpSQOS, lpGQOS: PQOS): Integer;

PWSABuf = ^TWSABuf;

TWSABuf = packed record

 Len: Cardinal;

 Buf: PChar;

end;

Функция

WSAConnect
устанавливает соединение со стороны клиента. Ее первые три параметра совпадают с параметрами функции connect. Параметр
lpCallerData
и
lpCalleeData
служат для передачи данных от клиента серверу и от сервера клиенту при установлении соединения. Они оба являются указателями на структуру
TWSABuf
тип
TWSABuf
, которая содержит размер буфера 
Len
и указатель на буфер
Buf
. Протоколы стека TCP/IP не поддерживают передачу данных при соединении, поэтому для TCP и UDP
lpCallerData 
и
lpCalleeData
должны быть равны
nil
. Параметры
lpSQOS
и
lpGQOS
— это указатели на структуры, с помощью которых программа передает свои требования к качеству обслуживания, причем параметр
lpGQOS
связан с не поддерживаемым в настоящий момент групповым качеством и всегда должен быть равен
nil
. Параметр
lpSQOS
также должен быть равен
nil
, если программа не предъявляет требований к качеству обслуживания. Так как
рассмотрение качества обслуживания выходит за рамки данной книги, мы не приводим здесь определение структуры
SQOS
, которое при необходимости легко найти в MSDN.

Между функциями

connect
и
WSAConnect
существует небольшое различие при работе с сокетами, не поддерживающими соединение. Как вы знаете из разд. 2.1.9, функция
connect
может использоваться с такими сокетами для задания адреса отправки по умолчанию и автоматической фильтрации входящих пакетов. Для того чтобы отменить такое "соединение", нужно при вызове функции
connect
указать адрес
INADDR_ANY
и нулевой порт. В случае
WSAConnect
для отмены "соединения" требуется, чтобы все без исключения поля структуры
Name
, включая
sin_family
, были нулевыми. Это сделано для того, чтобы обеспечить независимость от протокола: при любом протоколе для разрыва "соединения" должно устанавливаться одно и то же значение
Name
.

Если программа не предъявляет требований к качеству обслуживания, то для протоколов TCP и UDP функция

WSAConnect
не предоставляет никаких преимуществ по сравнению с
connect
.

Функция

accept
из стандартной библиотеки сокетов позволяет серверу извлечь из очереди соединений информацию о подключившемся клиенте и создать сокет для его обслуживания. Эти действия выполняются безусловно, для любых подключившихся клиентов. Если сервер допускает подключение не любых клиентов, а только тех, которые отвечают некоторым условиям (для протокола TCP эти условия могут заключаться в том, какие IP-адреса и какие порты допустимо использовать клиентам), сразу после установления соединения его приходится разрывать, если клиент не удовлетворяет этим условиям. Для упрощения этой операции в WinSock 2 предусмотрена функция
WSAAccept
, прототип которой приведен в листинге 2.40. 

Листинг 2.40. Функция
WSAAccept

// ***** Описание на C++ *****

SOCKET WSAAccept(SOCKET S, struct sockaddr FAR* addr, LPINT addrlen, LPCONDITIONPROC lpfnCondition, dwCallbackData);

// ***** описание на Delphi *****

function WSAAccept( S: TSocket; Addr: PSockAddr; AddrLen: PInteger; lpfnCondition: TConditionProc; dwCallbackData: DWORD): TSocket;

По сравнению с уже известной нам функцией

accept
функция
WSAAccept
имеет два новых параметра:
lpfnCondition
и
dwCallbackData
.
lpfnCondition
является указателем на функцию обратного вызова. Эта функция объявляется и реализуется программой.
WSAAccept
вызывает ее внутри себя и в зависимости от ее результата принимает или отклоняет соединение. Параметр
dwCallbackData
не имеет смысла для самой функции
WSAAccept
и передается без изменений в функцию обратного вызова. Тип
TConditionProc
должен быть объявлен следующим образом (листинг 2.41).

Листинг 2.41. Тип
TConditionProc

// ***** Описание на C++ *****

typedef (int*)(LPWSABUF lpCallerId, LPWSABUF lpCallerData, LPQOS lpSQOS, LPQOS lpGQOS, LPWSABUF lpCalleeId, LPWSABUF lpCalleeData, GROUP FAR* g, DWORD dwCallbackData) LPCONDITIONPROC;

// ***** Описание на Delphi *****

TConditionProc = function(lpCallerId, lpCallerData: PWSABuf; lpSQOS, lpGQOS: PQOS; lpCalleeID, lpCalleeData: PWSABuf; g: PGroup; dwCallbackData: DWORD): Integer; stdcall;

Параметр

lpCallerId
указывает на буфер, в котором хранится адрес подключившегося клиента. При работе со стеком TCP/IP
lpCallerId^.Len
будет равен
SizeOf(TSockAddr)
, a
lpCallerId^.Buf
будет указывать на структуру
TSockAddr
, содержащую адрес клиента. Параметр
lpCallerData
определяет буфер, в котором хранятся данные, переданные клиентом при соединении. Как уже отмечалось, протоколы стека TCP/IP не поддерживают передачу данных при соединении, поэтому для них этот параметр будет равен nil. Параметры
lpSQOS
и
lpGQOS
задают требуемое клиентом качество обслуживания для сокета и для группы соответственно. Так как группы сокетов в текущей реализации WinSock не поддерживаются, параметр
lpGQOS
будет равен
nil
. Параметр
lpSQOS
тоже будет равен
nil
, если клиент не задал качество обслуживания при соединении.

Поделиться с друзьями: