读取超时TIdTCPClient

时间:2019-12-17 07:11:58

标签: c++builder indy10

美好的一天。我使用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),然后读取了所有到达的数据。 我可以请你回答为什么会这样吗?

2 个答案:

答案 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将保持不变。

如果这不是您想要的行为,请考虑使用ReadTimeoutEIdReadTimeout来代替使用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。