TIdTCPClient ignores ReadTimeout



我使用TIdTCPClient发送消息并接收答案。我的消息和答案结构相当好,这意味着它们可以有不同的长度,但总是以#FS字符结尾。

我的Delphi(Alexandria(代码如下:

_TcpClient := TIdTCPClient.Create(Self);
_TcpClient.ReadTimeout := 60000;
_TcpClient.ConnectTimeout := 30000;
_TcpClient.Host := X.X.X.X;
_TcpClient.Port := Y;

然后我发信息:

_TcpClient.Connect;
_TcpClient.IOHandler.Write(messageText);

最后,我等待对方用ACK确认消息(正如我所说,以#FS结束(:

try
ans := TStringStream.Create;
repeat
b := _TcpClient.IOHandler.ReadByte;
ans.Write(b,1);
until b = #FS;
b := _TcpClient.IOHandler.ReadByte;
ans.Write(b, 1);
except
_status := ssAckTimeout;
end;

所有这些都适用于短消息,但对于互联网上较大的消息(约10万条(,它会失败。

最后一块代码在8-10秒后落入except部分,没有读取任何内容。

我对组件工作方式的理解是,它应该逐字节读取,等待ReadTimeout#FS。我不知道为什么它会忽略我的ReadTimeout值,并在8秒后失败。

有人知道答案吗,或者可以提出解决方案吗?

IOHandler.ReadByte()方法确实尊重ReadTimeout属性,尽管您声称它不尊重。它可能比预期更早地引发错误的唯一方法是如果操作系统的套接字堆栈中存在缺陷。

但是,您的代码中存在潜在的缺陷。循环读取直到#FS到达并写入ans,然后它尝试读取超过#FS的一个字节。除非你的消息实际上有这样一个跟踪字节(也许是校验和?(,否则这将失败并破坏你的通信。

在任何情况下,与其在循环中调用ReadByte()更简单的解决方案是使用IOHandler.ReadLn()方法,指定#FS作为结束行的分隔符,例如:

var
ans: string;
...
ans := _TcpClient.IOHandler.ReadLn(#FS);

最新更新