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

Потребность в перекрытом вводе-выводе при отправке данных возникает достаточно редко. Но функции WSASend/WSASendTo могут оказаться удобными при подготовке многокомпонентных пакетов, которые, например, имеют фиксированный заголовок и финальную часть. Для таких пакетов можно один раз подготовить буферы с заголовком и с финальной частью и, пользуясь возможностью отправки данных из несвязных буферов, при отправке каждого пакета менять только его среднюю часть.

2.2.10. Сервер, использующий перекрытый ввод-вывод

В этом разделе мы рассмотрим создание сервера на основе перекрытого ввода-вывода на основе процедур завершения (пример кода с использованием событий есть в MSDN в описании функций WSARecv — и WSASend). Перекрытый ввод-вывод лучше подходит для обмена в режиме "запрос-ответ", поэтому мы вновь вернемся к первоначальному протоколу, который не предусматривает отправку сервером сообщений по собственному усмотрению. На компакт-диске этот пример называется OverlappedServеr.

Как обычно, для каждого соединения создается экземпляр записи TConnection, которая на этот раз выглядит так, как показано в листинге 2.76.

Листинг 2.76. Тип TConnection

// Информация о соединении с клиентом:

// ClientSocket - сокет, созданный для взаимодействия с клиентом

// ClientAddr - строковое представление адреса клиента

// MsgSite - длина строки, получаемая от клиента

// Msg - строка, получаемая от клиента или отправляемая ему

// Offset - количество байтов, уже полученных от клиента

// или отправляемых ему на данном этапе

// BytesLeft - сколько байтов осталось получить от клиента

// или отправить ему на данном этапе

// Overlapped - структура для выполнения перекрытой операции

PConnection = ^TConnection;

TConnection = record

 ClientSocket: TSocket;

 ClientAddr: string;

 MsgSize: Integer;

 Msg: string;

 Offset: Integer;

 BytesLeft: Integer;

 Overlapped: TWSAOverlapped;

end;

Основное отличие этого варианта типа TConnection от того, что применялся ранее в примерах NonBlockingServer и AsyncSelectServer (см. разд. 2.1.16 и 2.2.6, а также листинг 2.31) — это отсутствие поля Phase, которое хранит этап взаимодействия с клиентом. Разумеется, в программе OverlappedServer взаимодействие с клиентом также разбивается на три этапа, но реализуется другой способ для того, чтобы различать этапы — для каждого этапа создается своя процедура завершения.

Примечание

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

Поле Overlapped содержит структуру TWSAOverlapped, которой программа непосредственно не пользуется, она только передает указатель на эту структуру в функции WSARecv и WSASend. Напомним, что одновременно может выполняться несколько операций перекрытого ввода-вывода, но у каждой из этих операций должен быть свой экземпляр TWSAOverlapped. Гак как в нашем случае с одним клиентом в каждый момент времени может выполняться не более одной операции, мы создаем по одному экземпляру TWSAOverlapped на каждого клиента.

Функция для перекрытого подключения клиентов существует — это AcceptEx, с которой мы познакомимся в разд. 2.2.12. Но она неудобна при работе совместно с WSARecv и WSASend, особенно в таком строго типизированном языке, как Delphi. Поэтому подключение клиентов мы будем отслеживать с помощью уже опробованной технологии асинхронных сокетов на сообщениях. Код запуска сервера OverlappedServer выглядит идентично коду запуска AsyncSelectServer (см. листинг 2.30): точно так же создается сокет, ставится в режим прослушивания, а затем его событие FD_ACCEPT привязывается к сообщению WM_ACCEPTMESSAGE

Сам обработчик WM_ACCEPTMESSAGE выглядит теперь следующим образом (листинг 2.77).

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