Indy TCPClient和输入缓冲区中的流浪字节

5

我正在使用以下几行代码通过IP与外部调制解调器/路由器(也称为设备)进行读写。

TCPClient.IOHandler.Write(MsgStr);
TCPClient.IOHandler.InputBuffer.Clear; 
TCPClient.IOHandler.ReadBytes(Buffer, 10, True);

MsgStr 是一个字符串类型,它包含了我要发送到我的设备的文本。 Buffer 被声明为 TIdBytes 类型。 在调用 ReadBytes 之前,我可以确认 IOHandler.InputBufferIsEmpty 立即返回 True。

我期望接收到的前 10 个字节非常具体,因此从我的角度来看,我只对发送字符串后接收到的前 10 个字节感兴趣。

问题是,当与某些设备通信时,第一次发送字符串并建立连接后返回的第一个字节会将一个“错误”(随机)的字节放入我的 Buffer 输出中。随后的字节是正确的。

例如,我期望的 10 个字节可能是:#6A1EF1090#3,但我得到的是.#6A1EF1090。在这个例子中,我有一个不应该出现的句号。

如果我再次尝试发送,就可以正常工作。(也就是在建立连接后发送的第二个写操作)。奇怪的是(对我来说),使用 Socket Sniffer 并没有显示返回的随机字节。如果我创建自己的“服务器”来接收响应并发送回来,它始终可以正常运行。其他软件——也就是不是我编写的软件——可以正常与设备通信(但我当然不知道它们是如何解析数据的)。

在上面的内容中,是否存在任何可能导致此情况发生的错误?请注意,这仅在建立连接后第一次使用 Write 时发生。

谢谢

编辑

我正在使用 Delphi 7 和 Indy 10.5.8

更新

好的。经过多次测试和查看,我离找到解决方法还很远。我得到了两种主要情况:1 - 第一个字节丢失;2 - 接收到的数据包开头出现了“错误”字节。使用 TIdLogEvent 和 TIdLogDebug 都可以显示相应地缺失或初始引入的字节。因此,我认为我的 ReadBytes 语句始终能够准确地显示 Indy 认为存在的内容。

此外,为了进一步测试它,我下载并安装了 ICS 组件。不幸的是(或者幸运,取决于你的角度),ICS 没有显示与 Indy 相同的问题。它没有显示首字节丢失,也没有显示在开始时引入的字节。然而,我只做了初步的测试,但 Indy 的行为“几乎立即”就会产生,而 ICS 还没有产生。

如果有人感兴趣,我可以提供一个小型演示应用程序,以说明此问题和我连接的 IP——它是公共 IP,任何人都可以访问它。否则,现在我只能绕过它。我不想切换到 ICS,因为 ICS 在这种情况下可能运行良好,考虑到这个 socket 的使用几乎是整个程序的关键,完全用 ICS 替换 Indy 将是很麻烦的。


尝试发送一个 AnsiString(sizeof(char)=1),这可能会有所帮助。 - user497849
1
我应该把那段代码放在哪里?顺便提一下,我编辑了我的问题,展示了我使用的 Delphi 版本,以防你认为我正在使用后来使用 Unicode 的 Delphi 版本。 - Jason
您应该使用标签来指定 Delphi 版本。 - user497849
你是否初始化了缓冲区并检查了是不是ReadBytes添加了额外的字节? - mjn
@mjn。是的。我初始化了,就是在ReadBytes之前加了这一行:SetLength(Buffer, 10);。这样足够了吗?在执行ReadBytes之前检查Buffer的内容,监视器中显示为(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)。一旦我跨过ReadBytes(也就是下一行),缓冲区就会填充为(32, 6, 48, 51, 48, 49, 53, 69, 55, 69)。在这种情况下,32是错误字节。6“应该”是第一个。谢谢。 - Jason
1
如果这是一个旧的基于串口的设备,那么我的记忆告诉我,在打开端口时通常会得到一个错误的字符作为第一个字节。这是接口的本质。如果您可以确定您的数据以#开头,请查找并忽略之前的任何内容。 - mj2008
2个回答

3
最后一个参数(True)
TCPClient.IOHandler.ReadBytes(Buffer, 10, True);

如果将参数设置为True,则会导致读取操作追加内容,而不是替换缓冲区的内容。

这要求首先正确设置缓冲区的大小和内容。

如果将参数设置为False,则给定字节数的缓冲区内容将被替换。


不幸的是,将其设置为False没有任何区别 - 如果这就是你的意思。我还尝试了各种SetLength(Buffer,10)与True / False的组合,以防有所帮助,但事实并非如此。但是,考虑到True适用于每个后续的发送/接收,如果那样做可以工作,我会感到惊讶(尽管很高兴)。 :) - Jason

1

ReadBytes() 不会向缓冲区注入恶意字节,因此在提供的有限信息下,我现在只能想到两种可能性:

  1. 设备确实在初始连接时发送了额外的字节,就像 mj2008 建议的那样。如果数据包嗅探器没有检测到它,请将 Indy 的自己的 TIdLog... 组件之一附加到您的 TIdTCPClient 上,例如 TIdLogFileTIdLogEvent,以验证 TIdTCPClient 实际从套接字接收到的内容。

  2. 您有另一个线程同时从同一连接读取,破坏了 InputBuffer。即使调用 TIdTCPClient.Connected() 也会执行读取操作。如果您正在使用线程,请不要在多个线程中同时执行读取操作。


谢谢。我会尝试第一部分,看看是否能提供任何见解,并回报结果。 - Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接