Ваш код пытается прочитать произвольные блоки данных из InputBuffer
и ожидает, что они будут полными и допустимыми строками.Он делает это без ЛЮБОГО рассмотрения того, какие данные вы получаете.Это рецепт для аварии на нескольких уровнях.
Вы подключены к серверу Telnet, но вы используете TIdTCPClient
вместо использования TIdTelnet
, поэтому вы ДОЛЖНЫ декодировать вручнуюлюбые полученные последовательности Telnet ДО вы можете затем обработать любые оставшиеся строковые данные.Посмотрите на исходный код TIdTelnet
.Существует много логики декодирования, которая имеет место до того, как событие OnDataAvailable
сработало.Все данные последовательности Telnet обрабатываются внутренне, затем событие OnDataAvailable
предоставляет все данные, не относящиеся к Telnet, оставшиеся после декодирования.
После того, как вы позаботились о декодировании Telnet, следует обратить внимание на еще одну проблему:что TEncoding.UTF8
обрабатывает только правильно закодированные COMPLETE UTF-8 последовательности.Если он встречает плохо закодированную последовательность или, что еще важнее, встречает неполную последовательность, ВЕСЬ ДЕКОД ДЕЙСТВУЕТ НЕ и возвращает пустую строку.Об этом уже сообщалось как об ошибке (см. QC # 79042 ).
CheckForDataOnSource()
сохраняет все необработанные байты в сокете в этот момент в InputBuffer
.InputBufferAsString()
извлекает любые необработанные байты в InputBuffer
в этот момент и пытается декодировать их, используя указанную кодировку.Очень возможно и вероятно, что необработанные байты, которые находятся в InputBuffer
при вызове InputBufferAsString()
, не всегда содержат COMPLETE UTF-8 последовательностей.Скорее всего, иногда последняя последовательность в InputBuffer
все еще ожидает поступления байтов в сокет, и они не будут считываться до следующего вызова CheckForDataOnSource()
.Это объясняет, почему ваша функция CheckText()
получает пустые строки при использовании TEncoding.UTF8
.
Вместо этого следует использовать IndyUTF8Encoding()
(Indy реализует свой собственный кодер / декодер UTF-8, чтобы избежать ошибки декодирования в TEncoding.UTF8
).По крайней мере, вы больше не будете получать пустые строки, однако вы все равно можете потерять данные, когда последовательность UTF-8 охватывает несколько вызовов CheckForDataOnSource()
(неполные последовательности UTF-8 будут преобразованы в ?
символов).Только по этой причине вам не следует использовать InputBufferAsString()
в этой ситуации (даже если TEncoding.UTF8
работал правильно).Для правильной обработки вы должны:
1) отсканировать вручную InputBuffer
, рассчитав, сколько байтов составляет COMPLETE только последовательности UTF-8, а затем передать этот счет InputBuffer.Extract()
или TIdIOHandler.ReadString()
.Любые оставшиеся байты останутся в InputBuffer
в следующий раз.Чтобы это сработало, вам придется избавиться от первого InputBufferIsEmpty()
вызова и просто безоговорочно позвонить CheckForDataOnSource()
, чтобы вы всегда проверяли наличие дополнительных байтов, даже если у вас уже есть некоторые.
2) useTIdIOHandler.ReadChar()
вместо этого и избавьтесь от звонков на InputBufferIsEmpty()
и CheckForDataOnSource()
в целом.Недостатком является то, что вы потеряете данные, если последовательность UTF-8 декодируется в суррогатную пару UTF-16.ReadChar()
может декодировать суррогаты, но не может вернуть второй символ в паре (я начал работать над новыми ReadChar()
перегрузками для будущего выпуска Indy, которые возвращают String
вместо Char
, поэтому полные суррогатные пары могут бытьвозвращается).