2016-06-28 222 views
0

(使用Delphi 2009)我正在嘗試使用Indy TidIcmpClient編寫簡單的網絡連接監視器。想法是ping一個地址,然後在附加的TidIcmpClient.OnReply處理程序中測試返回了多少數據。如果答覆包含> 0字節,那麼我知道連接成功,但如果TidIcmpClient超時或答覆包含0個字節,我將假定鏈接已關閉Indy TIdIcmpClient - 如何檢測超時?

我很難理解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; 

回答

6

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成功,則ReplyStatusTypersEcho,並且​​字段將包含被傳遞給的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; 
+0

非常有用的回覆雷米。這完全解釋了它。 – user3209752

+0

@RemyLebeau爲什麼我得到套接字錯誤訪問被拒絕10013?防火牆關閉。 – grinner

+0

好吧,發現這個:https://stackoverflow.com/questions/13611525/does-indy-ping-require-uac-elevation – grinner

0

IdIcmpClient companent有OnReply事件。此事件具有類型爲TReplyStatus的AReplyStatus參數。 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;