美好的一天。我使用TIdTCPClient组件将请求发送到服务器并读取响应。我知道某些请求的响应大小,而其他请求则不知道。
当我知道响应的大小时,我的数据读取代码如下:
IdTCPClient1->Socket->Write(requestBuffer);
IdTCPClient1->Socket->ReadBytes(answerBuffer, expectSize);
当我不知道响应的大小时,我将使用以下代码:
IdTCPClient1->Socket->Write(requestBuffer);
IdTCPClient1->Socket->ReadBytes(answerBuffer, -1);
在两种情况下,我都遇到了问题。 在第一种情况下,如果服务器未返回所有数据(小于ExpectSize),则IdTCPClient1将等待ReadTimeout完成,但answerBuffer中将根本没有数据(即使服务器发送了一些内容)。这是TIdTCPClient背后的逻辑吗?是吗?
在第二种情况下,ReadTimeout根本不起作用。也就是说,ReadBytes函数立即结束,并且没有任何内容写入answerBuffer,或者写入了服务器中的几个字节。但是,我希望由于此函数在这种情况下不知道要读取的字节数,因此它必须等待ReadTimeout并读取这段时间内到达的字节。对于实验,我在读写之间插入了Sleep(500),然后读取了所有到达的数据。 我可以请你回答为什么会这样吗?
答案 0 :(得分:0)
美好的一天。我使用TIdTCPClient组件将请求发送到服务器并读取响应。我知道某些请求的响应大小,而其他请求则不知道。
为什么您不知道所有回复的大小?您的协议实际上是什么样的? TCP是字节流,必须以一种方式对每个消息进行帧构成,以使接收方可以知道每个消息的开始和结束位置,以便正确读取消息并保持流的完整性。这样,消息必须在其有效载荷中包括其大小,或者在消息之间唯一地定界。那么,您的情况是哪种情况?听起来好像您在处理任何一种可能性。
当我不知道响应的大小时,我将使用以下代码:
IdTCPClient1->Socket->Write(requestBuffer); IdTCPClient1->Socket->ReadBytes(answerBuffer, -1);
将AByteCount
设置为-1时,这告诉ReadBytes()
返回IOHandler
的{{1}}中当前可用的任何字节。如果InputBuffer
为空,则InputBuffer
一直等到ReadBytes()
间隔至少有1个字节到达,然后它将实际收到的所有字节返回到{{1} },直至ReadTimeout
的{{1}}指定的最大值。因此,可能仍需要多次读取才能完整阅读整个邮件。
通常,在处理实际协议时,切勿将InputBuffer
设置为-1。 -1仅在代理/流传输任意数据时才使用,当您不在乎实际字节数时。任何其他用途都需要了解协议如何构造消息的详细信息。
在第一种情况下,如果服务器未返回所有数据(小于ExpectSize),则IdTCPClient1将等待ReadTimeout完成,但answerBuffer中将根本没有数据(即使服务器发送了某些内容) )。这是TIdTCPClient背后的逻辑吗?是吗?
是的。当IOHandler
> 0时,RecvBufferSize
等待AByteCount
中指定数目的字节可用,然后再将那么多字节提取到输出AByteCount
中。除非所有请求的字节都可用,否则您的ReadBytes()
将不会被修改。如果InputBuffer
过去了,则会引发TIdBytes
异常,而您的answerBuffer
将保持不变。
如果这不是您想要的行为,请考虑使用ReadTimeout
或EIdReadTimeout
来代替使用answerBuffer
而不是ReadStream()
。
在第二种情况下,ReadTimeout根本不起作用。也就是说,ReadBytes函数立即结束,并且没有任何内容写入answerBuffer。
我从未听说ReadBytes()
没有等待TIdMemoryBufferStream
。仅当TBytesStream
中没有可用的字节并且ReadBytes()
设置为非常小的值(例如0毫秒)时,您描述的内容才会发生。
或写入服务器中的几个字节。
如果您要求ReadTimeout
读取InputBuffer
之间(包括两端)的任意数量的字节,或者如果超时则不读取任何字节,则这是完全合理的结果。
但是,我希望由于此函数在这种情况下不知道要读取的字节数,因此它必须等待ReadTimeout并读取这段时间内出现的字节。
这就是它应该如何工作的,是的。以及它如何一直有效。因此,我建议您在运行时调试ReadTimeout
并找出为什么它无法按您期望的方式工作。另外,请确保您使用的是Indy的最新版本(至少是最近几年的版本)。
答案 1 :(得分:0)
为什么您不知道所有回复的大小?
因为,事实上,我正在对电子设备进行调查。该设备具有自己的网络IP地址和端口。因此,设备可以根据其状态以不同的方式响应相同的请求。严格来说,某些查询可以有两个答案,并且它们的长度不同。在这种情况下,在读取时,我指定AByteCount = -1来读取任何设备响应。
我从没听说过ReadBytes()没有等待ReadTimeout。
您是对的!我错了。当指定AByteCount = -1时,我得到一个字节。如您所说,如果至少有一个字节到达,它将返回并且ReadBytes()结束。
另外,请确保您使用的是Indy的最新版本(或至少是最近几年的版本)。
我正在使用C ++ Builder 10.3 Community Edition,Indy版本10.6.2.5366。