缓冲区为空,但 IdTCPClient.IOHandler.InputBufferIsEmpty 为 false

2024-06-22

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

有什么问题?

thanks


您的代码正在尝试从以下位置读取任意数据块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因此可以返回完整的代理对)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

缓冲区为空,但 IdTCPClient.IOHandler.InputBufferIsEmpty 为 false 的相关文章

  • EOutOfMemory 使用 Delphi 创建大型 XML

    我正在使用 Delphi 从关系数据库中的数据创建 XML 文档 它在小数据集上测试得很好 但是当我尝试将数据集的大小扩展到生产级别时 它最终在节点创建期间因 EOutOfMemory 异常而崩溃 我正在使用放在表单上的 TXMLDocum
  • 所见即所得与 Unicode

    我在 Delphi 中编写了一个 Windows 程序 该程序使用 GetCharWidth 和 Em Square 将文本非常精确地放置并换行到屏幕和打印机 这对于 ANSI 文本效果很好 您只需要检索和计算 255 个字符的宽度 但当您
  • 命名管道性能问题

    我使用命名管道进行 C 和 Delphi 之间的过程间通信 C 使用System IO Pipes包 而 Delphi 使用Libby s pipes pas 不幸的是 通信几乎是高性能的 分析显示通信占用了整个运行时间的 72 其余的用于
  • 供所有 Win32 程序员在 Windows Aero Glass(DWM、GDI、GDI+)上绘图的文档和 API 示例

    我正在寻找良好的资源来学习使用 Win32 GDI API 或任何替代它的内容 以便使用 Win32 API 直接在玻璃窗体上进行绘制和绘制 当我使用 Delphi 时 我将其标记为 Delphi 或 Visual C 您能找到的任何代码示
  • 确保 StreamReader 不会挂起等待数据

    下面的代码读取从 tcp 客户端流读取的所有内容 并且在下一次迭代中它将仅位于 Read 上 我假设正在等待数据 我如何确保它不会在没有任何内容可供读取时返回 我是否必须设置低超时 并在失败时响应异常 或者有更好的办法吗 TcpClient
  • 如何使用 Delphi 播放单音或自定义波形?

    我查了一些代码 似乎一切都在创建一些数学函数波 但我想要一个单音 或者用自定义单音制作的自定义波 我读了这个如何生成不同频率的连续音调 https stackoverflow com questions 7742377 how can i
  • Indy 10 和 sslvTLSv1_2

    我发布的网站目前支持 TLS v1 1 和 TLS 1 2 他们很快将只允许 TLS 1 2 版连接 为此我将 Delphi 5 升级到了 Indy 10 目前 我在代码中创建组件 并且一次运行 3 个线程一切都运行良好 HTTp TIdH
  • 使用 Delphi 的 7-Zip?

    我想使用 Delphi 的 7 Zip DLL 但一直找不到合适的文档或示例 有谁知道如何使用 Delphi 的 7 Zip DLL 自版本 1 102 起JEDI 代码库 http wiki delphi jedi org index p
  • 无法在 SAMSUNG GALAXY S7 EDGE 上调试

    为什么我无法在 RAD STUDIO 10 Seattle upd 1 中的 SAMSUNG GALAXY S7 EDGE ANDROID 6 0 1 上调试我的应用程序 当我调试时 设备上的应用程序启动 但 RAD STUDIO Delp
  • 安装软件包时出现无法加载软件包 %s 错误

    我正在 Delphi 2007 上进行测试 我的小组项目由 2 个包组成 包运行 bpl 它被标记为 仅运行时 并包含一个名为 uMyTestRun pas 的单元 其中定义了一个空的 TFrame 后代 unit uMyTestRun i
  • 如何从后台线程有效地对 Delphi 6 框架或表单执行图像流预览?

    我有一个 Delphi 6 应用程序 用于接收和处理来自外部摄像头的图像流 我将代码放在后台线程上 因为它占用大量 CPU 而且我不希望它干扰在主线程上运行的用户界面代码 我想使用我从相机的 JPEG 帧创建的 TBitmap 来更新表单或
  • 将数据从 DLL 传递到应用程序时出现问题

    我对如何在我的场景中正确使用指针感到有点困惑 我有一个 DLL 其中包含一些嵌入式资源 我在此 DLL 中公开了一个函数 该函数将这些资源之一的二进制数据传递回其调用应用程序 在本例中 我嵌入了 JPG 图像文件 我的 DLL 确实将文件正
  • 我如何淡入/淡出 TImage?

    我有一个简单的TForm命名为Form1 Image1 是一个TImage加载了一个 PNGImage 和一个 Button1TButton测试事物 成功实现了对图像1的Alpha Blend的方法 代码如下 procedure SetPN
  • 在这些情况下限制破折号的正则表达式模式

    Scenario 我正在使用第三方文件重命名软件 该软件是用 Delphi 编写的 并且具有 pascal 脚本支持 该应用程序允许使用正则表达式来重命名文件 这意味着 如果我需要对文件名执行的操作不能仅使用一个正则表达式来完成 那么我可以
  • 如何在TWebBrowser中显示相对路径图像?

    我正在 DesignMode Doc DesignMode On 中使用 TWebBrowser 来编写 HTML 文档 TWebBrowser 中没有加载文档 磁盘上的 HTML 文件 我直接在 TWebBrowser 中从零开始创建文档
  • 在 DLL 中使用 IXMLDocument 需要 CoInitialize?

    有没有理由使用CoInitialize使用时在我的 DLL 函数中IXMLDocument msxml 包装器 或与此相关的其他 com 对象 调用应用程序 线程是否负责调用CoInitialize CoUninitialize 如果我使用
  • 设置第二个 TFDPhysFBDriverLink - 可能且必要吗?

    我的应用程序有设计时间TFDConnection and TFDPhysFBDriverLink作为源连接 这可能会也可能不会在 Firebird 嵌入模式下打开 如果是这样 FDPhysFBDriverLink VendorLib fbe
  • 将滚动条隐藏在 Delphi dbgrid 中(即使在调整大小时)

    对于我们的 dbgrid 我们希望滚动条始终隐藏 由于 TDBGrid 没有 滚动条 属性 我们使用 ShowScrollBar DBGrid1 Handle SB VERT False ShowScrollBar DBGrid1 Hand
  • Delphi 中动态数组的最大长度?

    我很好奇动态数组可以有多长 所以我尝试了 SetLength dynArray High Int64 它的值为 9 223 372 036 854 775 807 我认为这将是我可以引用的最大数量的索引 它给了我一个 ERangeError
  • 使用 Indy 组件下载、暂停和恢复下载

    实际上我正在使用 TIdHTTP 组件从互联网下载文件 我想知道是否可以使用此组件或另一个 indy 组件暂停和恢复下载 这是我当前的代码 这可以正常下载文件 没有简历 但是 现在我想暂停下载关闭我的应用程序 当我的应用程序重新启动时 然后

随机推荐