【问题标题】:Connection Closed Gracefully when IdTCPClient.IOHandler.ReadStream()!IdTCPClient.IOHandler.ReadStream() 时连接正常关闭!
【发布时间】:2010-11-19 23:49:53
【问题描述】:

我是 delphi 新手,这是我的第一个项目。 下面是一小段代码:

procedure TForm1.Button2Click(Sender: TObject);
responseStringFromServer:TStringStream;
begin
 try
  if IdTCPClient1.Connected then
   begin
    dataSentToDevice:= 'http/1.0 content-length: 344 content-type: text/xml <?xml          version="1.0" encoding="UTF-8" ?> ...'
   IdTCPClient1.IOHandler.WriteLn(dataSentToDevice);
   responseStringFromServer := TStringStream.Create;
    IdTCPClient1.IOHandler.ReadStream(responseStringFromServer);
    ...

我有一个连接到本地网络的设备。我设法成功连接到它。发送命令也可以,但是当我这样做时

IdTCPClient1.IOHandler.ReadStream(responseStringFromServer);

然后它等待直到设备完成处理并发生异常:“连接正常关闭”。所以我无法读取设备应该发送给我的数据。设备未关闭。我已阅读其他帖子,并且我了解设备本身会断开连接。

我有一个与之通信的演示程序,它运行良好。我需要在断开连接之前获取响应 xml。

请求也是http,我使用的是IdTCPClient(我需要使用xml请求,我不知道如何使用TidHTTP)。 可能是设备在发送响应后断开连接,因此我的 tcpclient 在接收数据之前获得连接断开标志。

任何帮助将不胜感激!

【问题讨论】:

  • 如果有一个运行良好的演示程序,我会使用网络嗅探器 (WireShark) 来查看它的作用,然后将通信流与 Delphi 应用程序进行比较。也可以使用像 Don's Proxy donsproxy.moneybender.com 这样的 HTTP 代理 - 可能比网络嗅探更容易。
  • 同意。如果您没有设备实际协议的文档,那么数据包嗅探器是下一个最好的选择。

标签: delphi


【解决方案1】:

请求也是http,我是 使用 IdTCPClient(我需要使用 xml 请求,我不知道怎么做 使用 TidHTTP)。

使用 IdHTTP 很简单...

  1. 将它的一个实例放到您的表单上, 选择它。
  2. 在对象检查器中,转到 ProtocolVersion 属性,并设置它 到pv1_0,然后打开它
  3. 请求属性集,并设置 Request.ContentType 到 text/xml,和 Request.ContentEncoding 为 UTF-8, 并设置其他属性如果 必填。
  4. 在表单中添加一个按钮,然后 双击它。
  5. 在您的代码中,创建一个 TStringStream,并加载您的 XML 内容。
  6. 将您的信息流分配给 IdHttp.Request.Source。
  7. 通过给出调用 IdHttp.Get() 方法 它是一个主机地址。
  8. IdHttp.Get() 返回一个字符串 是服务器发送给您的响应。

【讨论】:

  • UTF-8 不是有效的 ContentEncoding 属性值。您正在考虑 CharSet 属性。此外,没有 Request.Stream 属性。您将输入流直接传递给 Post() 的 ASource 参数(要使用 GET 请求发送输入数据,您必须直接调用 DoRequest())。另外,我建议使用 TMemoryStream 而不是 TStringStream,因为 TStringStream 在 D2009 中更改为支持 Unicode,并且您不希望它意外地弄乱 XML 数据。
  • 好的,使用 idhttp 发送数据效果很好。我仍然在使用 IdHttp.get() 过程从设备检索数据时遇到问题。现在它停在 IdHttp.get() 并等待一段时间。然后它抛出 EIdConnClosedGracefully 异常。有没有更好的方法来请求数据或 idhttp.get() 是如何工作的。目前我正在使用 IdHTTP1.Get('deviceIP:port',response);响应是 TMemoryStream 的类型。有没有办法指定应该停止等待响应的返回时间?
  • 好吧,事实证明,我不得不监听另一个端口。不是我发送数据的那个。但它仍然不能正常工作:现在当我调用 idhttp.get() 过程时,它会一直停留在那里,直到发生超时。我是否必须在发送数据之前开始监听端口,还是在发送数据后立即开始监听端口就足够了?
【解决方案2】:

您调用 ReadStream() 的方式,它会将前 4 个字节(如果 TIdIOHandler.LargeStream 属性为 True,则为 8 个字节)解释为指定长度的网络字节顺序的整数(或 Int64)数据,然后它会尝试读取那么多字节。设备实际上是在发送这样的长度值吗?如果不是,则 ReadStream() 将尝试读取错误的字节数。 EIdConnClosedGracefully 异常意味着设备正在关闭其端的套接字。所以要么设备在发送数据后立即关闭连接,要么超时等待你发送下一个命令,你不能这样做,因为你被阻止等待来自上一个命令的错误数据。

【讨论】:

    【解决方案3】:

    正如@Remy Lebeau 和文档所说(当您的编辑插入符号位于 ReadStream 语句上方时按 F1):

    AByteCount 表示要从 IOHandler 读入 AStream 的字节数。当 AByteCount 包含 -1 且 AReadUntilDisconnect 包含 False 时,字节计数从 IOHandler 读取为整数值。调整 AStream 的大小以匹配 IOHandler 的预期大小。

    当您连接到一端也以 INDY WriteStream 编写的服务器、另一端以 ReadStream 或任何其他语言编写的服务器时,如果您按照 INDY 客户端的预期发送该字节数,这将非常有用。

    如果您从 设备 读取数据,请确保设备在流的前端发送该信息或更改您读取数据的方式。如果您知道流的大小,只需传递第二个参数:AByteCount。如果流结束时设备会关闭通道,则第二个参数为-1,第三个参数为True:AReadUntilDisconnect。

    如果设备发送长度未知但使用已知终止符(如 CR/LF)的文本,您最好使用 IOHandler 的 ReadLn 方法来获取该字符串。

    看看是否都不符合您的需求,看看 TIOHandlerClass 和 RTFM 的 Read* 方法,以找到正确的方法来获取 设备发送的数据。

    【讨论】:

      猜你喜欢
      • 2010-11-08
      • 2021-03-17
      • 1970-01-01
      • 2012-02-19
      • 2011-03-09
      • 2014-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多