美好的一天。我使用 TIdTCPClient 组件向服务器发送请求并读取响应。我知道某些请求的响应大小,但不知道其他请求的响应大小。
为什么您不知道所有响应的大小?你的协议实际上是什么样的? TCP 是一个字节流,每条消息必须以这样一种方式构建,即接收者可以知道每条消息的开始和结束位置,以便正确读取消息并保持流的完整性。因此,消息必须要么在其有效负载中包含它们的大小,要么在消息之间进行唯一分隔。那么,您的情况是哪种情况?这听起来不像你正在处理这两种可能性。
当我不知道响应的大小时,我使用以下代码:
IdTCPClient1->Socket->Write(requestBuffer);
IdTCPClient1->Socket->ReadBytes(answerBuffer, -1);
当您将AByteCount 设置为-1 时,这会告诉ReadBytes() 返回IOHandler 的InputBuffer 中当前可用的任何字节。如果InputBuffer 为空,ReadBytes() 会等待,直到ReadTimeout 间隔,至少 1 个字节到达,然后它将实际接收到的任何字节返回到InputBuffer,直到指定的最大值IOHandler 的 RecvBufferSize。因此,可能仍需要多次阅读才能完整阅读整条消息。
一般来说,在处理实际协议时,您永远不应该将AByteCount 设置为 -1。 -1 仅适用于代理/流式传输任意数据时,您不关心字节实际是什么。任何其他用途都需要了解协议中有关如何构建消息的详细信息。
第一种情况,如果服务器没有返回所有数据(小于expectSize),那么IdTCPClient1会等待ReadTimeout完成,但是answerBuffer中根本没有数据(即使服务器发送了一些东西) )。这是 TIdTCPClient 背后的逻辑吗?对吗?
是的。当AByteCount > 0 时,ReadBytes() 会等待InputBuffer 中可用的指定字节数,然后再将那么多字节提取到输出TIdBytes 中。除非所有请求的字节都可用,否则您的 answerBuffer 不会被修改。如果ReadTimeout 过去,则会引发EIdReadTimeout 异常,并且您的answerBuffer 保持不变。
如果这不是您想要的行为,那么考虑使用ReadStream() 而不是ReadBytes(),使用TIdMemoryBufferStream 或TBytesStream 来读入。
在第二种情况下,ReadTimeout 根本不起作用。也就是说,ReadBytes 函数立即结束,没有任何内容写入 answerBuffer。
我从未听说过ReadBytes() 不等待ReadTimeout。只有在InputBuffer 中没有可用字节并且ReadTimeout 设置为某个非常小的值(例如0 毫秒)时,您所描述的才会发生。
或从服务器写入几个字节。
这是一个非常合理的结果,因为您要求 ReadBytes() 读取介于 1..RecvBufferSize 之间的任意数量的字节(含),或者如果超时时间已过则不读取任何字节。
但是,我预计由于本例中的此函数不知道要读取的字节数,因此它必须等待 ReadTimeout 并读取在此期间到来的字节。
它应该是这样工作的,是的。以及它一直是如何运作的。所以我建议你在运行时调试到ReadBytes() 并找出它为什么没有按照你期望的方式工作。此外,请确保您使用的是最新版本的 Indy(或至少是最近几年的版本)。