delphi - 空缓冲区但 IdTCPClient.IOHandler.InputBufferIsEmpty 为假

标签 delphi telnet tcpclient indy

我在使用 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;

这个过程每 1000 毫秒运行一次,并且当缓冲区有一个值 CheckText 被调用时。

此代码有效,但有时会将空缓冲区返回给 CheckText。

有什么问题?

谢谢

最佳答案

您的代码正试图从 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/

相关文章:

delphi - 自定义组件控件不断重新创建

memcached - JMeter - 使用 beanshell 通过 telnet 执行命令

JAVA服务器和.Net客户端编程

ios - 如何为 iOS telnet 客户端创建 View ?

delphi - 当发送包过于频繁时,Indy TCPServer 无法从 TCPClient 接收所有包

支持异步操作并遵守超时的.NET TcpClient/NetworkStream 实现

delphi - 如何将 const 指针传递给函数?

delphi - 如何禁用WebBrowser组件加载图像?

Delphi:为什么断点有时不可用(IDE 上的绿色突出显示线)?

windows - wscript 和 cscript 之间的区别