Потребность в перекрытом вводе-выводе при отправке данных возникает достаточно редко. Но функции WSASend/WSASendTo
могут оказаться удобными при подготовке многокомпонентных пакетов, которые, например, имеют фиксированный заголовок и финальную часть. Для таких пакетов можно один раз подготовить буферы с заголовком и с финальной частью и, пользуясь возможностью отправки данных из несвязных буферов, при отправке каждого пакета менять только его среднюю часть.
2.2.10. Сервер, использующий перекрытый ввод-вывод
В этом разделе мы рассмотрим создание сервера на основе перекрытого ввода-вывода на основе процедур завершения (пример кода с использованием событий есть в MSDN в описании функций WSARecv
— и WSASend
). Перекрытый ввод-вывод лучше подходит для обмена в режиме "запрос-ответ", поэтому мы вновь вернемся к первоначальному протоколу, который не предусматривает отправку сервером сообщений по собственному усмотрению. На компакт-диске этот пример называется OverlappedServеr.
Как обычно, для каждого соединения создается экземпляр записи TConnection
, которая на этот раз выглядит так, как показано в листинге 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
(см. Phase
, которое хранит этап взаимодействия с клиентом. Разумеется, в программе OverlappedServer
взаимодействие с клиентом также разбивается на три этапа, но реализуется другой способ для того, чтобы различать этапы — для каждого этапа создается своя процедура завершения.
Использование одной процедуры завершения для всех трех этапов и распознавание в ней этапов с помощью поля Phase
в случае перекрытого ввода-вывода также возможно. Рекомендуем написать такой вариант сервера в качестве самостоятельного упражнения.
Поле Overlapped
содержит структуру TWSAOverlapped
, которой программа непосредственно не пользуется, она только передает указатель на эту структуру в функции WSARecv
и WSASend
. Напомним, что одновременно может выполняться несколько операций перекрытого ввода-вывода, но у каждой из этих операций должен быть свой экземпляр TWSAOverlapped
. Гак как в нашем случае с одним клиентом в каждый момент времени может выполняться не более одной операции, мы создаем по одному экземпляру TWSAOverlapped
на каждого клиента.
Функция для перекрытого подключения клиентов существует — это AcceptEx
, с которой мы познакомимся в WSARecv
и WSASend
, особенно в таком строго типизированном языке, как Delphi. Поэтому подключение клиентов мы будем отслеживать с помощью уже опробованной технологии асинхронных сокетов на сообщениях. Код запуска сервера OverlappedServer выглядит идентично коду запуска AsyncSelectServer (см. листинг 2.30): точно так же создается сокет, ставится в режим прослушивания, а затем его событие FD_ACCEPT
привязывается к сообщению WM_ACCEPTMESSAGE
.
Сам обработчик WM_ACCEPTMESSAGE
выглядит теперь следующим образом (листинг 2.77).