Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Проблемы с чтением буфера из Telnet-сервера с помощью `IdTCPClient`

Delphi , Интернет и Сети , Telnet

Проблемы с чтением буфера из Telnet-сервера с помощью IdTCPClient

В данной статье мы рассмотрим проблему, с которой сталкиваются разработчики, пытающиеся прочитать буфер данных из Telnet-сервера с помощью компонента IdTCPClient в Delphi. Мы также предложим решение этой проблемы и рассмотрим альтернативные варианты.

Описание проблемы

Разработчик столкнулся с проблемой при чтении буфера данных с Telnet-сервера с помощью компонента IdTCPClient. Приложение периодически проверяет наличие данных в буфере и, если данные есть, передает их на обработку в функцию CheckText(). Однако, sometimes функция CheckText() получает пустой буфер, хотя, согласно свойству InputBufferIsEmpty, буфер не должен быть пустым.

Код, вызывающий проблему

procedure TForm2.ReadTimerTimer(Sender: TObject);
var
   S: String;
begin
   if IdTCPClient.IOHandler.InputBufferIsEmpty then
   begin
     IdTCPClient.IOHandler.CheckForDataOnSource(10);
     if IdTCPClient.IOHandler.InputBufferIsEmpty then Exit;
   end;
   S := idTCPClient.IOHandler.InputBufferAsString(TEncoding.UTF8);
   CheckText(S);
end;

Альтернативный ответ

Один из пользователей предложил удалить параметр кодировки из метода InputBufferAsString(). Однако, это решение приводит к тому, что полученный текст содержит нечитаемые символы.

Подтвержденный ответ

Проблема заключается в том, что код пытается читать произвольные блоки данных из буфера ввода и ожидает, что они будут полными и валидными строками. При этом он не учитывает тип данных, которые получает. Это может привести к катастрофическим последствиям.

Разработчик подключается к Telnet-серверу, но использует TIdTCPClient напрямую, а не TIdTelnet, что требует от него самостоятельно декодировать любые последовательности Telnet, прежде чем обрабатывать оставшиеся строковые данные. В коде TIdTelnet есть много логики декодирования, которая обрабатывается перед запуском события OnDataAvailable. Все последовательности Telnet обрабатываются внутри, а событие OnDataAvailable предоставляет любые оставшиеся не-Telnet данные.

После того, как декодирование Telnet взято под контроль, другой проблемой является то, что TEncoding.UTF8 обрабатывает только правильно закодированные полные последовательности UTF-8. Если он встречает плохо закодированную последовательность или, что более важно, неполную последовательность, вся декодировка терпит неудачу и возвращает пустую строку. Это уже было отмечено как ошибка (см. https://qc.embarcadero.com/wc/qcmain.aspx?d=79042).

Метод CheckForDataOnSource() сохраняет любые raw-байты, которые находятся в сокете в данный момент, в буфере ввода. Метод InputBufferAsString() извлекает любые raw-байты, которые находятся в буфере ввода в данный момент, и пытается их декодировать с помощью указанной кодировки. Очень возможно и вероятно, что raw-байты, которые находятся в буфере ввода при вызове InputBufferAsString(), не всегда содержат полные последовательности UTF-8. Вероятно, последняя последовательность в буфере ввода все еще ждет байты, которые поступят в сокет, и они не будут прочитаны до следующего вызова CheckForDataOnSource(). Это объясняет, почему функция CheckText() получает пустые строки при использовании TEncoding.UTF8.

Рекомендуется использовать IndyUTF8Encoding() вместо этого (Indy реализует собственный кодировщик/декодер UTF-8, чтобы избежать ошибки декодирования в TEncoding.UTF8). Во всяком случае, вы больше не получите пустые строки, но все еще можете потерять данные, когда UTF-8-последовательность охватывает несколько вызовов CheckForDataOnSource() (неполные последовательности UTF-8 превратятся в символы "?"). Из-за этой причины вы не должны использовать InputBufferAsString() в данной ситуации (даже если TEncoding.UTF8 работал бы правильно). Чтобы правильно обработать это, вы должны либо:

1) Сканировать буфер ввода вручную, вычисляя, сколько байтов составляет полные последовательности UTF-8, и затем передавать это количество в InputBuffer.Extract() или TIdIOHandler.ReadString(). Любые оставшиеся байты останутся в буфере ввода для следующего раза. Для этого вам придется избавиться от первого вызова InputBufferIsEmpty() и просто вызвать CheckForDataOnSource() безусловно, чтобы всегда проверять наличие дополнительных байтов, даже если у вас уже есть некоторые. 2) Использовать TIdIOHandler.ReadChar() вместо этого и избавиться от вызовов InputBufferIsEmpty() и CheckForDataOnSource() целиком. Недостатком является то, что вы потеряете данные, если UTF-8-последовательность декодируется в пару суррогатов UTF-16. ReadChar() может декодировать суррогаты, но не может возвратить второй символ в паре (я начал работать над новыми перегрузками ReadChar() для будущего выпуска Indy, которые возвращают String, чтобы полные пары суррогатов могли быть возвращены).

Пример кода для первого способа

procedure TForm2.ReadTimerTimer(Sender: TObject);
var
   S: String;
   Index: Integer;
begin
   IdTCPClient.IOHandler.CheckForDataOnSource(10);
   if IdTCPClient.IOHandler.InputBufferLength > 0 then
   begin
      Index := 0;
      while (Index < IdTCPClient.IOHandler.InputBufferLength) and (IdTCPClient.IOHandler.InputBuffer[Index] < $80) do
         Inc(Index);
      S := IdTCPClient.IOHandler.InputBufferAsString(Index, TEncoding.UTF8);
      CheckText(S);
   end;
end;

Пример кода для второго способа

procedure TForm2.ReadTimerTimer(Sender: TObject);
var
   S: String;
begin
   while IdTCPClient.IOHandler.ReadChar(S) do
      CheckText(S);
end;

Используя один из этих подходов, вы сможете правильно обрабатывать данные, получаемые из Telnet-сервера с помощью IdTCPClient.

Создано по материалам из источника по ссылке.

Статья описывает проблему чтения буфера данных из Telnet-сервера с помощью компонента `IdTCPClient` в Delphi, а также предлагает решения для устранения этой проблемы.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Telnet ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-19 13:29:56
2024-11-21 12:07:43/0.004148006439209/0