Сегодня я столкнулся с странным поведением с использованием Indy 10 (поставляется с Delphi 2010). Вот проблема:Почему IOHandler.ReadStream блокирует поток, когда клиент подключается к серверу в Indy?
Предположим, у нас есть IdTcpClient в нашем клиенте, и IdTCPServer в нашем приложении сервера, и этот код в OnExecute обработки события для нашего IdTCPServer:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
AStream: TStringStream;
S: string;
begin
AStream := TStringStream.Create;
try
AContext.Connection.IOHandler.ReadStream(AStream);
S := AStream.DataString;
finally
AStream.Free;
end;
end;
Теперь, когда клиент пытается подключиться к серверу, используя TIdTcpClient.Connect; на сервере вызывается TIdTcpServer.OnExecute, и поток, выполняющийся внутри обработчика событий OnExecute, блокируется, когда выполнение достигает строки AContext.Connection.IOHandler.ReadStream (AStream)!
Когда я отслеживаю код, проблема возникает, когда ReadLongInt вызывается внутри ReadStream для получения количества байтов. ReadLongInt вызывает ReadBytes. Внутри ReadBytes значение FInputBuffer.Size равно нулю. Там, в цикле ReadFromSource вызывается, и в конечном итоге выполнение достигает TIdSocketListWindows.FDSelect, который вызывает функцию «выбрать» из WinSock2, и выполнение останавливается здесь, и от этого клиентского соединения ничего не будет получено. Я попытался дать значение параметрам AByteCount и AReadUntilDisconnect, но это не изменило поведение.
Если я заменил ReadStream на ReadLn, то подключение к серверу не блокирует выполнение кода, а данные, отправленные с клиента, считываются сервером.
С кодом что-то не так? Или это ошибка?
С уважением
Благодарим за подробное описание. В документации Indy упоминается, что если AByteCount равен -1 и AReadUntilDisconnect является False, количество байтов считывается как целое число из IOHandler, но я не знал, что он будет считан из первых 4 или 8 байтов полученных данных. Я думал, что когда AReadUntilDisconnect является False, а AByteCount равно -1, ReadStream будет читать до тех пор, пока в буфере ввода есть что-то. В любом случае, еще раз спасибо за вашу помощь. – vcldeveloper
Все методы чтения IOHandler получают свои данные только из InputBuffer. Метод ReadBytes(), который другие методы вызывают внутренне, гарантирует, что InputBuffer имеет достаточное количество байтов, доступных в нем для каждой операции чтения. Если InputBuffer уже имеет 4 байта, то ReadStream() получает их как есть. Если InputBuffer еще не имеет 4 байта, ReadBytes() делает это, то ReadStream() получает их из InputBuffer впоследствии. В любом случае все данные поступают из сокета в InputBuffer по каждому методу чтения по мере необходимости. –