delphi TID客户端忽略读取超时

bpsygsoo  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(188)

我使用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;

所有这些对于短消息都相当有效,但对于互联网上更大的短消息(~ 100 K),它就失败了。
最后一个代码块在8-10秒后福尔斯except部分,没有阅读任何内容。
我对组件工作原理的理解是,它应该逐字节读取,等待ReadTimeout#FS。我不知道为什么它忽略了我的ReadTimeout值,并在短短8秒后失败。
有人知道答案吗,或者可以提出解决方案吗?

5tmbdcev

5tmbdcev1#

IOHandler.ReadByte()方法 * 确实 * 荣誉ReadTimeout属性,尽管您声称它不支持。它可能比预期更早引发错误的唯一原因是操作系统的套接字堆栈中存在缺陷。
然而,你的代码中有一个 * 潜在的 * 缺陷。你的循环读取直到#FS到达并被写入ans,然后它试图读取超过#FS的 * 一个字节 *。除非你的消息实际上有这样一个尾随字节(也许是校验和?),否则这将失败并破坏你的通信。
在任何情况下,与其在循环中调用ReadByte(),不如使用IOHandler.ReadLn()方法,将#FS指定为结束行的分隔符,例如:

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

相关问题