' - ошибка при чтении длины строки: ' + GetErrorString);
RemoveConnection(NewConnection);
end;
end;
end;
end;
После того как сокет для взаимодействия с подключившимся клиентом создан, следует отменить для него асинхронный режим, унаследованный от слушающего сокета, т.к. при перекрытом вводе-выводе этот режим не нужен. Затем, после создания экземпляра
TConnection
и добавления его в список, запускается первая операция перекрытого чтения с помощью функции
WSARecv
. Об окончании этой операции будет сигнализировать вызов функции
ReadLenCompleted
, которая передана в
WSARecv
в качестве параметра.
Как мы уже говорили ранее, в программе
OverlappedServer
есть три разных функции завершения:
ReadLenCompleted
,
ReadMsgCompleted
и
SendMsgCompleted
. Последовательность работы с ними такая: сначала для чтения длины строки вызывается
WSARecv
, в качестве
буфера передастся
Connection.MsgSize
, в качестве функции завершения —
ReadLenCompleted
(это мы уже видели в листинге 2.77). Когда вызывается
ReadLenCompleted
, это значит, что операция чтения уже завершена и прочитанная длина находится в
Connection.MsgSize
. Поэтому в функции
ReadLenCompleted
выделяем нужный размер для строки
Connection.Msg
и запускаем следующую операцию перекрытого чтения — с буфером
Connection.Msg
и функцией завершения
ReadMsgCompleted
. В этой функции полученная строка показывается пользователю, формируется ответ, и запускается следующая операция перекрытого ввода-вывода — отправка строки клиенту. В качестве буфера в функцию
WSASend
передаётся
Connection.Msg
, а в качестве функции завершения —
SendMsgCompleted
. В функции
SendMsgCompleted
вновь вызывается
WSARecv
с буфером
Connection.MsgSize
и функцией завершения
ReadLenCompleted
, и таким образом сервер возвращается к первому этапу взаимодействия с клиентом.
Описанную простую последовательность действий портит то, что из-за возможной отправки данных по частям можно столкнуться с ситуацией, когда функция завершения вызвана для уведомления о том, что получена или отправлена часть данных. Чтобы получить остальную их часть, необходимо вновь вызвать функцию чтения или записи с той же функцией завершения, а указатель на буфер должен при этом указывать на оставшуюся незаполненной часть переменной, в которую помещаются данные. С учетом этого, а также необходимости обработки ошибок, функции завершения выглядят так, как показано в листинге 2.78.
Листинг 2.78. Функции завершения
// Функция ReadLenCompleted используется в качестве функции завершения