您的代码正在尝试从以下位置读取任意数据块InputBuffer
并期望它们是完整且有效的字符串。它这样做没有ANY考虑您收到的数据类型。这在多个层面上都是灾难的根源。
您已连接到 Telnet 服务器,但正在使用TIdTCPClient
直接而不是使用TIdTelnet
, 那么你MUST手动解码接收到的任何 Telnet 序列BEFORE然后您可以处理任何剩余的字符串数据。查看源代码TIdTelnet
。在解码之前发生了很多解码逻辑OnDataAvailable
事件被触发。所有 Telnet 序列数据均在内部处理,然后OnDataAvailable
事件提供解码后剩余的所有非 Telnet 数据。
一旦你完成了 Telnet 解码,你需要注意的另一个问题是TEncoding.UTF8
只处理正确编码的COMPLETEUTF-8 序列。如果它遇到编码错误的序列,或者更重要的是遇到不完整的序列,整个解码失败它返回一个空字符串。这已被报告为错误(请参阅质量控制#79042 http://qc.embarcadero.com/wc/qcmain.aspx?d=79042).
CheckForDataOnSource()
存储套接字中的所有原始字节在那一刻进入InputBuffer
. InputBufferAsString()
提取其中的任何原始字节InputBuffer
在那一刻并尝试使用指定的编码对其进行解码。很可能并且很有可能,原始字节位于InputBuffer
你打电话时InputBufferAsString()
并不总是包含COMPLETEUTF-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()
or TIdIOHandler.ReadString()
。任何剩余的字节将保留在InputBuffer
下次。为了让它发挥作用,你必须摆脱第一个InputBufferIsEmpty()
打电话就打电话CheckForDataOnSource()
无条件地这样你总是会检查更多的字节,即使你已经有一些字节。
2) use TIdIOHandler.ReadChar()
相反,并摆脱对InputBufferIsEmpty()
and CheckForDataOnSource()
共。缺点是,如果 UTF-8 序列解码为 UTF-16 代理对,您将丢失数据。ReadChar()
可以解码代理,但它不能返回该对中的第二个字符(我已经开始研究新的ReadChar()
Indy 未来版本的重载将返回String
代替Char
因此可以返回完整的代理对)。