Читаем О чём не пишут в книгах по Delphi полностью

// ***** Описание на 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, если клиент не задал качество обслуживания при соединении.

Параметр lpCalleeId содержит адрес интерфейса, принявшего соединение (поля структуры при этом используются так же, как у параметра lpCallerId). Ранее уже обсуждалось, что сокет, привязанный к адресу INADDR_ANY, прослушивает все сетевые интерфейсы, имеющиеся на компьютере, но каждое подключение, созданное с его помощью, использует конкретный интерфейс. Параметр lpCalleeId содержит адрес, привязанный к конкретному соединению. Параметр lpCalleeData указывает на буфер, в который сервер может поместить данные для отправки клиенту. Этот параметр также не имеет смысла для протокола TCP, не поддерживающего отправку данных при соединении.

Параметр g выходной, он позволяет управлять присоединением создаваемого функцией WSAAccept сокета к группе. Параметр, как и все, связанное с группами, зарезервирован для использования в будущем.

Примечание

Если вы пользуетесь старой версией MSDN, то можете не обнаружить там описания параметра g — оно там отсутствует. Видимо, просто по ошибке.

И наконец, через параметр dwCallbackData в функцию обратного вызова передается значение параметра dwCallbackData, переданное в функцию WSAAccept. Программист должен сам решить, как ему интерпретировать это значение.

Функция должна вернуть CF_ACCEPT (0), если соединение принимается, CF_REJECT (1), если оно отклоняется, и CF_DEFER (2), если решение о разрешении или запрете соединения откладывается. Если функция обратного вызова вернула CF_REJECT, to WSAAccept завершается с ошибкой WSAECONNREFUSED, если CF_DEFER — то с ошибкой WSATRY_AGAIN (в последнем случае соединение остаётся в очереди, и информация о нем вновь будет передана в функцию обратного вызова при следующем вызове WSAAccept). Обе эти ошибки не фатальные, сокет остается в режиме ожидания соединения и может принимать подключения от новых клиентов.

Ранее уже обсуждалось, что функция connect на стороне клиента считается успешно завершенной тогда, когда соединение встало в очередь, а не тогда, когда оно реально принято сервером через функцию accept. По умолчанию для клиента, соединение с которым сервер отклонил, нет разницы, вызвал ли сервер функцию WSAAccept и сразу отклонил соединение, или установил его с помощью accept, а потом разорвал. В обоих случаях клиент сначала получит информацию об успешном соединении с сервером, а потом это соединение будет разорвано. Но при использовании WSAAccept можно установить такой режим работы, когда сначала выполняется функция. заданная параметром lpCondition, и лишь потом клиенту отправляется разрешение или запрет на подключение. Включается этот режим установкой параметра слушающего сокета SO_CONDITIONAL_ACCEPT, что иллюстрирует листинг 2.42.

Листинг 2.42. Включение режима ожидания реального подключения

var

 Cond: BOOL;

begin

 Cond := True;

 setsockopt(S, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, PChar(@Cond), SizeOf(Cond));

Этот режим снижает нагрузку на сеть и повышает устойчивость сервера против DoS-атак, заключающихся в многократном подключении-отключении посторонних клиентов, поэтому в серьезных серверах рекомендуется использовать эту возможность.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже