- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在使用 idTCPClient 从 telnet 服务器读取缓冲区的以下代码中遇到问题:
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;
最佳答案
您的代码正试图从 InputBuffer
中读取任意数据块并期望它们是完整且有效的字符串。这样做没有 任何 考虑您接收的数据类型。这是多层次灾难的秘诀。
您已连接到 Telnet 服务器,但您使用的是 TIdTCPClient
直接而不是使用 TIdTelnet
,所以你必须手动解码收到的任何 Telnet 序列 之前 然后您可以处理任何剩余的字符串数据。查看TIdTelnet
的源代码.在OnDataAvailable
之前发生了很多解码逻辑。事件被触发。所有 Telnet 序列数据都在内部处理,然后是 OnDataAvailable
事件提供解码后剩余的任何非 Telnet 数据。
一旦处理了 Telnet 解码,另一个需要注意的问题是 TEncoding.UTF8
只处理正确编码 完成 UTF-8 序列。如果遇到编码错误的序列,或者更重要的是遇到不完整的序列,整个解码失败 它返回一个空字符串。这已经被报告为一个错误(见 QC #79042)。CheckForDataOnSource()
存储套接字中的任何原始字节 那一刻进InputBuffer
. InputBufferAsString()
提取 InputBuffer
中的任何原始字节那一刻并尝试使用指定的编码对其进行解码。 InputBuffer
中的原始字节很有可能并且很可能当您调用 InputBufferAsString()
并不总是包含 完成 UTF-8 序列。有时可能是 InputBuffer
中的最后一个序列仍在等待字节到达套接字,直到下一次调用 CheckForDataOnSource()
才会读取它们。 .这将解释为什么您的 CheckText()
函数在使用 TEncoding.UTF8
时接收空白字符串.
您应该使用 IndyUTF8Encoding()
相反(Indy 实现了自己的 UTF-8 编码器/解码器以避免 TEncoding.UTF8
中的解码错误)。至少,您不会再得到空字符串,但是当 UTF-8 序列跨越多个 CheckForDataOnSource()
时,您仍然可能会丢失数据。调用(不完整的 UTF-8 序列将被转换为 ?
个字符)。仅出于这个原因,您不应该使用 InputBufferAsString()
在这种情况下(即使 TEncoding.UTF8
确实工作正常)。要正确处理此问题,您应该:
1) 扫一扫 InputBuffer
手动,计算多少字节构成 完成 仅 UTF-8 序列,然后将该计数传递给 InputBuffer.Extract()
或 TIdIOHandler.ReadString()
.任何剩余的字节将保留在 InputBuffer
中下一次。为此,您必须摆脱第一个 InputBufferIsEmpty()
打电话就打电话CheckForDataOnSource()
无条件,以便您始终检查更多字节,即使您已经有一些。
2) 使用 TIdIOHandler.ReadChar()
取而代之的是摆脱对 InputBufferIsEmpty()
的调用和 CheckForDataOnSource()
共。缺点是如果 UTF-8 序列解码为 UTF-16 代理对,您将丢失数据。 ReadChar()
可以解码代理,但它不能返回对中的第二个字符(我已经开始研究新的 ReadChar()
重载,用于 Indy 的 future 版本,返回 String
而不是 Char
,因此可以返回完整的代理对)。
关于delphi - 空缓冲区但 IdTCPClient.IOHandler.InputBufferIsEmpty 为假,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8761490/
我在使用 idTCPClient 从 telnet 服务器读取缓冲区的以下代码中遇到问题: procedure TForm2.ReadTimerTimer(Sender: TObject); var
我是一名优秀的程序员,十分优秀!