简体   繁体   English

Indy TIdTCPClient 组件偶尔不超时且不接收数据

[英]Indy TIdTCPClient component occasionally not timing out and receiving no data

I am using the Internet Direct TIdTCPClient component to communicate with a remote service to retrieve a message that is normally about 5k is size.我正在使用 Internet Direct TIdTCPClient 组件与远程服务进行通信,以检索通常大小约为 5k 的消息。 During a typical operation I will send about 400 requests to the service, each one taking about 1 second to complete.在典型操作中,我将向服务发送大约 400 个请求,每个请求大约需要 1 秒才能完成。 Most of the time everything works perfectly.大多数时候一切都很完美。 However, about one percent of the time the request takes 189 seconds and I receive no data at all.但是,大约百分之一的请求需要 189 秒,而我根本没有收到任何数据。 For ease of discussion, I'll call this a failure.为了便于讨论,我称之为失败。

I am particularly interested in understanding exactly what is happening when the failure occurs so that I can take my evidence to the publisher of the service.我特别有兴趣准确了解故障发生时发生的情况,以便我可以将证据提交给服务的发布者。 First of all, the failure is not reproducible.首先,失败是不可重现的。 If I re-send a failed request there is a very high probability (maybe 99 percent) that it will work.如果我重新发送失败的请求,它很有可能(可能是 99%)会起作用。

I also capture the request that I send when a failure occurs, so I am able to confirm that the request is well formed.我还捕获了发生故障时发送的请求,因此我能够确认请求格式正确。

I am assuming that during a failure that I am getting some data, just not all of it.我假设在失败期间我得到了一些数据,而不是全部。 Here is why.这就是为什么。 My IdTCPClient has a 30 second timeout (I've even set it to 5 seconds, but that didn't make a difference).我的 IdTCPClient 有 30 秒的超时时间(我什至将它设置为 5 秒,但这并没有什么不同)。 When the failure occurs, it always fails after 189 seconds (plus about 500 milliseconds).发生故障时,总是在 189 秒(加上大约 500 毫秒)后失败。

As a result, I am thinking that during a failure my component is receiving a trickle of data, which is why my client is not timing out.结果,我认为在失败期间我的组件正在接收涓涓细流的数据,这就是我的客户端没有超时的原因。 And, I am assuming that the disconnection is happening at the service since none of my timeout values are ever set to 189 seconds.而且,我假设服务断开连接,因为我的超时值都没有设置为 189 秒。 On the other hand, reading IOHandler.AllData does not raise an exception (not even an EIdConnClosedGracefully exception).另一方面,读取 IOHandler.AllData 不会引发异常(甚至不会引发 EIdConnClosedGracefully 异常)。 Am I interpreting this evidence correctly?我是否正确解释了这些证据?

What I want to do is to confirm that I am getting some data, just not all of it, before the service terminates the connection.我想要做的是在服务终止连接之前确认我正在获取一些数据,而不是全部数据。 Furthermore, I want to know what that partial data looks like as I believe it can help identify the source of the failure.此外,我想知道部分数据是什么样的,因为我相信它可以帮助确定故障的根源。

Currently, my request is similar to the following:目前,我的请求类似于以下内容:

//ExceptionName is a temporary global variable
//that I am using while trying to solve this issue
ExceptionName = 'no exception';
try
  s := GetRequest(id);
  IdTcpClient1.Host := Host;
  IdTcpClient1.Port := StrToInt(Port);
  IdTcpClient1.ReadTimeout := ReadTimeout;
  try
    IdTcpClient1.Connect;
  except
    on e: exception do
    begin
      ExceptionName := e.ClassName;
      raise EConnectionFailure.Create('Connection refused: ' + e.Message)
    end;
  end;
  IdTcpClient1.IOHandler.Writeln(s);
  try
    Result := IdTcpClient1.IOHandler.AllData;
  except
    on E: EIdConnClosedGracefully do
    begin
       ExceptionName := e.ClassName;
       //eat this exception
    end;
    on e: Exception do
    begin
       ExceptionName := e.ClassName;
      raise;
    end;
  end;
finally
  if IdTcpClient1.Connected then
    IdTcpClient1.Disconnect;
end;

Using IOHandler.AllData to read the data is very convenient, but I cannot retrieve any data following a failure (AllData returns an empty string).使用 IOHandler.AllData 读取数据非常方便,但是失败后我无法检索任何数据(AllData 返回一个空字符串)。 I've tested IOHandler.InputBufferIsEmpty after a failure, and it returns True.我在失败后测试了 IOHandler.InputBufferIsEmpty,它返回 True。

I've also tried other methods to read the data, such as IOHandler.ReadStream (this produced the same result as reading AllData).我还尝试了其他方法来读取数据,例如 IOHandler.ReadStream(这与读取 AllData 产生的结果相同)。 I also used IOHandler.ReadBytes and IOHandler.ReadByte (in conjunction with IOHandler.CheckForDataOnSource).我还使用了 IOHandler.ReadBytes 和 IOHandler.ReadByte(与 IOHandler.CheckForDataOnSource 一起使用)。 Nothing has worked.没有任何效果。

Am I wrong about partial data transmission?我对部分数据传输有误吗? If so, why would I see a consistent 189.nnnn seconds delay before the failure.如果是这样,为什么我会在失败前看到一致的 189.nnnn 秒延迟。

If partial data transmission is a possibility, what approach should I take to capture every byte of data received before the failure.如果部分数据传输是可能的,我应该采取什么方法来捕获故障前接收到的每个数据字节。

I am using Delphi 2009 for this project and Indy 10, but I don't think the version has anything to do with it.我在这个项目和 Indy 10 中使用 Delphi 2009,但我认为版本与它没有任何关系。 I don't think this is an Indy issue.我认为这不是印地问题。


Edit: I have inspected the communication between my Indy client and the server using WireShark.编辑:我已经使用 WireShark 检查了我的 Indy 客户端和服务器之间的通信。 When one of these failures occur, after sending my request the server sent two [ACK] packets followed by silence for just over 189 seconds.当其中一个故障发生时,在发送我的请求后,服务器发送了两个 [ACK] 数据包,然后静默超过 189 秒。 After that delay, the response included [FIN, PSH, ACK] but no application data.在该延迟之后,响应包括 [FIN, PSH, ACK] 但没有应用程序数据。

When the communication worked normally, the two ACK packets returned by the server in response to my request was followed by an application data packet.当通信正常时,服务器响应我的请求返回的两个 ACK 包后面跟着一个应用程序数据包。


Edit: Have reported the issue to the publisher of the Web service, and am waiting for a reply.编辑:已将问题报告给 Web 服务的发布者,正在等待回复。


Edit: Ok, the publisher of the Web service has responded.编辑:好的,Web 服务的发布者已经回复。 They acknowledged problems on their end and have addressed some of those.他们最终承认了问题,并解决了其中的一些问题。 We are no longer getting timeouts.我们不再超时。 Most responses are received in about 2 seconds, with a few taking slightly longer.大多数响应在大约 2 秒内收到,少数需要稍长的时间。 The publisher is working to fix the remaining issues.出版商正在努力解决剩余的问题。

Thank you everyone for your input.谢谢大家的意见。

You need to run Fiddler2 and watch the traffic.您需要运行 Fiddler2 并观察流量。 It inserts itself as a proxy and sniffs evertying that uses the WinInet stack.它将自己作为代理插入,并嗅探使用 WinInet 堆栈的 evertying。 Then you know whether you've gotten any data or not, and exactly what you're sending and receiving.然后你就知道你是否收到了任何数据,以及你正在发送和接收的确切信息。 http://www.fiddler2.com/fiddler2/ http://www.fiddler2.com/fiddler2/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM