1

这是一个有趣的问题,我还没有解决。

我正在编写一个通过 Internet 与服务器通信的客户端。我正在使用 RAD Studio 2007 本机个性在 Indy 10 中使用 TIdTcpClient Internet Direct (Indy) 组件。

为了从服务器获取数据,我使用 SSL 通过端口 443 发出 HTTP 请求,其中我的请求详细信息包含在 HTTP 消息正文中。到现在为止还挺好。代码就像魅力一样工作,但有一个例外。

我提交的一个请求应该会从服务器产生大约 336 KB 的响应(HTTP 响应标头包含 Content-Length:344795)。问题是我只得到了 320KB。XML 格式的响应在 XML 元素的中间被明显截断。

值得一提的是,XML 是简单的文本。没有可以解释截断的特殊字符。我的 TIdTcpClient 组件只是报告说,在收到部分响应后,服务器优雅地关闭了连接(这是每个响应都应该完成的方式,即使是那些没有被截断的响应,所以这不是问题)。

我可以对响应也超过几 K 字节的同一服务器进行几乎相同的调用,并且所有这些都可以正常工作。我提出的一个请求返回大约 850 KB,另一个返回大约 300 KB,依此类推。

简而言之,我只在一个特定的请求中遇到这个问题。所有其他请求(其中有很多)都会收到完整的响应。

我已经与服务的创建者进行了交谈,并提供了我的请求示例。他报告说请求是正确的。他还告诉我,当他向他的服务器发出我的相同请求时,他得到了完整的响应。

我不知所措。要么是服务的创建者弄错了,那端的响应实际上有问题,要么是我的请求有一些特殊之处。

这里有我想念的解决方案吗?请注意,我还使用了许多其他读取机制(ReadString、ReadStrings、ReadBytes 等)并且都产生相同的结果,在 320KB 标记处截断这个特定响应。

该代码可能不相关,但无论如何我都会包含它。抱歉,我不能包含 XML 请求,因为它包含专有信息。(ReadTimeout 设置为 20 秒,但请求在 1 秒左右返回,所以不是超时问题。)

函数 TClient.GetResponse(PayloadCDS: TClientDataSet): 字符串;
变量
  s:字符串;
开始
  尝试
    尝试
      s := GetBody(PayloadCDS);
      IdTcpClient1.Host := 主机;
      IdTcpClient1.Port := StrToInt(Port);
      IdTcpClient1.ReadTimeout := ReadTimeout;
      IdTcpClient1.连接;
      IdTcpClient1.IOHandler.LargeStream := 真;
      //IdTcpClient1.IOHandler.RecvBufferSize := 2000000;
      IdTcpClient1.IOHandler.Write(s);
      结果:= IdTcpClient1.IOHandler.AllData;
    除了
      在 E 上:EIdConnClosedGracefully 做
      开始
         //吃掉异常
      结尾;
      在 e: 例外做
      开始
        增加;
      结尾;
    结尾;
  最后
    如果 IdTcpClient1.Connected 然后
      IdTcpClient1.断开连接;
  结尾;
结尾;
4

2 回答 2

1

由于您正在发送 HTTP 请求,因此您应该直接使用 TIdHTTP 组件而不是 TIdTCPClient 组件。如果您继续直接使用 TIdTCPClient,则有很多关于 TIdHTTP 为您管理的 HTTP 协议的细节,您必须手动处理这些细节。

如果您要继续直接使用 TIdTCPClient,那么您至少应该停止使用 TIdIOHandler.AllData() 方法。提取“Content-Length”回复标头(您可以 Capture() 标头到 TStringList 或 TIdHeaderList 中,然后使用其 Values[] 属性),然后将实际报告的字节数传递给 TIdIOHandler.ReadString() 或 TIdIOHandler.ReadStream ()。这将有助于确保读取 I/O 不会因为服务器在回复结束时断开连接而过早停止读取。

于 2009-08-14T20:48:28.383 回答
0

正如我在原始问题中提到的,此连接使用 SSL。这要求您使用 IdSSLIOHandlerSocketOpenSSL 组件,您将其分配给 IdTcpClient 组件的 IOHandler 属性。所有这些都在我最初的设计中,正如我所提到的,我的许多请求都得到了正确的响应。

周末我发现另一个请求返回一个不完整的响应。我捕获了该原始 HTTP 请求,并使用名为 SOAP UI 的工具将该请求提交给服务器。使用 SOAP UI,服务器返回了一个完整的答案。显然,我的客户端出了问题,而不是服务器。

我终于通过摆弄各种属性找到了解决方案。最终纠正该问题的属性位于 IdSSLIOHandlerSocketOpenSSL 类的 SSLOptions 属性中。SSLOptions.Method 的默认值为 sslvSSLv2。当我将 Method 更改为 sslvSSLv23 时,所有响应都返回完整。

为什么在进行此更改之前,我能够完整地检索到​​一些回复,而不是全部回复,这对我来说仍然是个谜。尽管如此,将 IdSSLIOHandlerSocketOpenSSL.SSLOptions.Method 设置为 sslvSSLv23 解决了我的问题。

谢谢 Remy Lebeau,感谢您的建议。

于 2009-08-17T21:58:45.183 回答