【问题标题】:Indy TIdIcmpClient - how to detect a timeout?Indy TIdIcmpClient - 如何检测超时?
【发布时间】:2016-06-29 03:06:23
【问题描述】:

(使用 Delphi 2009)我正在尝试使用 Indy TidIcmpClient 编写一个简单的网络连接监视器。这个想法是 ping 一个地址,然后在附加的 TidIcmpClient.OnReply 处理程序中测试返回了多少数据。如果回复包含 > 0 字节,那么我知道连接成功,但如果 TidIcmpClient 超时或回复包含 0 字节,我将假设链接已关闭

我很难理解 TidIcmpClient 的逻辑,因为没有 'OnTimeout' 事件。

两个子问题...

是否无论如何都会调用 TidIcmpClient.OnReply,无论是 (a) 接收到数据时还是 (b) 达到超时时,以先到者为准?

我如何区分由于超时而导致的零字节回复和在超时期限内恰好包含零字节(或不可能发生)的真实回复?

换句话说,这种代码是否可以,或者我需要做其他事情来判断它是否超时

procedure TForm1.IdIcmpClient1Reply(ASender: TComponent; const AReplyStatus: TReplyStatus);
begin
if IdIcmpClient1.ReplyStatus.BytesReceived = 0 then
  //we must have timed out, link is down
else
  //got some data, connection is up
end;

procedure DoPing;
begin
IdIcmpClient1.ReceiveTimeout := 200;
IdIcmpClient1.Host := '8.8.8.8';
IdIcmpClient1.Ping;
end;

【问题讨论】:

    标签: delphi ping indy


    【解决方案1】:

    Ping() 退出时,ReplyStatus 属性包含传递给OnReply 事件的AReplyStatus 参数的相同信息(您将忽略该参数)。 Ping() 只需在退出之前调用 OnReply 处理程序,将 ReplyStatus 属性传递给它,因此您实际上不需要在示例中使用 OnReply 事件。所做的只是不必要地分解您的代码。

    procedure DoPing;
    begin
      IdIcmpClient1.ReceiveTimeout := 200;
      IdIcmpClient1.Host := '8.8.8.8';
      IdIcmpClient1.Ping;
      // process IdIcmpClient1.ReplyStatus here as needed...
    end;
    

    话虽如此,您没有正确处理ReplyStatus 数据。即使 ping 失败,BytesReceived 字段也可以大于 0。顾名思义,它只是报告实际收到的 ICMP 响应字节数。 ICMP 定义了许多不同类型的响应。 ReplyStatusType 字段将设置为实际收到的响应类型。定义了 20 个值:

    type
      TReplyStatusTypes = (rsEcho,
        rsError, rsTimeOut, rsErrorUnreachable,
        rsErrorTTLExceeded,rsErrorPacketTooBig,
        rsErrorParameter,
        rsErrorDatagramConversion,
        rsErrorSecurityFailure,
        rsSourceQuench,
        rsRedirect,
        rsTimeStamp,
        rsInfoRequest,
        rsAddressMaskRequest,
        rsTraceRoute,
        rsMobileHostReg,
        rsMobileHostRedir,
        rsIPv6WhereAreYou,
        rsIPv6IAmHere,
        rsSKIP);
    

    如果 ping 成功,ReplyStatusType 将是 rsEchoReplyData 字段将包含传递给 Ping()ABuffer 参数的(可选)数据。您可能还需要注意 FromIpAddressToIpAddress 字段,以确保响应实际上来自预期的目标机器。

    如果发生超时,ReplyStatusType 将改为 rsTimeOut

    试试这个:

    procedure DoPing;
    begin
      IdIcmpClient1.ReceiveTimeout := 200;
      IdIcmpClient1.Host := '8.8.8.8';
      IdIcmpClient1.Ping;
      if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsEcho then
      begin
        // got some data, connection is up
      end
      else if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsTimeout then
      begin
        // have a timeout, link is down
      end
      else
      begin
        // some other response, do something else...
      end;
    end;
    

    【讨论】:

    • 非常有用的回复雷米。这充分说明了这一点。
    • @RemyLebeau 为什么我收到套接字错误访问被拒绝 10013?防火墙已关闭。
    • 好的,找到了这个:stackoverflow.com/questions/13611525/…
    【解决方案2】:

    IdIcmpClient 组件具有 OnReply 事件。此事件将 AReplyStatus 参数作为类型 TReplyStatus。 TReplyStatus 具有ReplyStatusType 属性。此属性的类型是 TReplyStatusTypes。 TReplyStatusTypes 具有 rsTimeOut 值。因此,将代码添加到 OnReply 事件并检查超时或其他错误。

    procedure TForm1.IdIcmpClient1Reply(ASender: TComponent;
      const AReplyStatus: TReplyStatus);
    begin
      if AReplyStatus.ReplyStatusType = rsTimeOut then
      begin
        //do someting on timeout.
      end;
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 2021-07-31
      • 1970-01-01
      • 2022-12-24
      • 2016-06-18
      • 2021-12-28
      • 1970-01-01
      相关资源
      最近更新 更多