2015-01-02 90 views
0

我有一個關於驗證ping是否在批處理命令中正確返回的問題。目前我必須檢查ping 3種不同的方式來了解服務器實際上是否已啓動。我想將這些組合成一個單一的ping命令。我曾嘗試使用不同的錯誤級別或不錯誤級別0等。他們都沒有捕獲所有可能的情況。這是我一直使用的是什麼:批處理命令捕獲所有可能的ping問題

Set /p domain=Enter IP address: 
set state=up 

@ping.exe -n 1 %domain% | find "unreachable" > null && set state=down 
if "%state%" == "down" goto :NoServer 

@ping.exe -n 1 %domain% | find "TTL expired" > null && set state=down 
if "%state%" == "down" goto :NoServer 

@ping.exe -n 1 %domain% 
if errorlevel 1 goto :NoServer 

回答

0
ping.exe -n 1 %domain% >tempfile 
if not errorlevel 1 (
findstr /i /c"unreachable" /c:"TTL expired" > null 
if errorlevel 1 goto :OK 
) 

:Noserver 

應該使用單一的平復制測試。我不確定ping是否會針對所有錯誤情況返回errorlevel非零值,或者可能是您的目標字符串和錯誤級別0之一。您需要指定。

+0

> tempfile是做什麼的?我會假設它創建一個臨時文件,但爲什麼? – Konan

+0

'>'是'重定向器'。與'''重定向命令的輸出一樣,作爲下一個輸入的輸入,'>'將輸出重定向到一個新文件(或者替換現有文件)'>>'將輸出重定向到一個新文件(或者附加一個新文件現有文件)和'<'重定向來自文件而不是來自鍵盤的輸入。 – Magoo

+0

謝謝,這是很好的信息! – Konan

4

有兩種方法來檢查ping命令的研製成功或失敗:測試錯誤級別執行後或測試命令的輸出。對於這兩種情況,檢查ipv4或ipv6地址是不一樣的。

問題是:ping如何表現?,它的輸出是什麼? errorlevel是什麼時候設置的?

errorlevel

如果我們與IPv6工作,規則是當存在對所有發送的數據包沒有回覆(所有數據包丟失)

  • errorlevel設置

  • errorlevel沒有設置,如果有回覆任何發送的數據包

ipv6具有一致的行爲,並檢查errorlevel是知道機器是否在線的可靠方法。

在IPv4中的規則不同

  • errorlevel設定當存在要發送的數據包

  • errorlevel中的至少一個沒有答覆時,有給所有的應答沒有被設置發送報文(無丟包)

但是,在IPv4中,在同一個子網查驗的非可用機器並沒有固定的日e errorlevel,你會得到一個「無法達到」的答案,n packets sent, n packed received, 0 packets lost,所有的數據包都會從發送數據包的同一臺機器得到答覆。

當機器位於同一子網中時,此行爲在ipv4中使錯誤級別檢查失敗。

如何解決IPv4中的問題?輸出檢查

可以檢查ping命令的輸出,如果輸出中存在字符串TTL=,目標機器處於聯機狀態。

ping -n 1 10.0.0.1 | find "TTL=" >nul 
if errorlevel 1 ( 
    echo offline 
) else (
    echo online 
) 

但是,這種方法是在IPv4中可以作爲這個領域還沒有被列入平輸出將與IPv6的失敗(並改名,在IPv6中它被稱爲跳限制


對於「一般」解決方案,可以使用(從先前的答案改編而來)(似乎有很多代碼,但幾乎都是註釋)。 ping操作和輸出處理被封裝在一個子例程中,該子例程使用作爲批處理文件的第一個參數傳遞的地址/主機名稱進行調用。

@echo off 

    setlocal enableextensions disabledelayedexpansion 

    if "%~1"=="" goto :eof 

    call :isOnline "%~1" 
    if not errorlevel 1 (echo ONLINE) else (echo OFFLINE) 

    endlocal 
    exit /b 

:isOnline address pingCount 
    setlocal enableextensions disabledelayedexpansion 

    :: send only one ping packed unless it is indicated to send more than one 
    set /a "pingCount=0", "pingCount+=%~2" >nul 2>nul 
    if %pingCount% lss 1 set "pingCount=1" 

    :: a temporary file is needed to capture ping output for later processing 
    set "tempFile=%temp%\%~nx0.%random%.tmp" 

    :: ping the indicated address getting command output and errorlevel 
    ping -w 1000 -n %pingCount% "%~1" > "%tempFile%" && set "pingError=" || set "pingError=1" 

    :: 
    :: When pinging, the behaviours of ipv4 and ipv6 are different 
    :: 
    :: we get errorlevel = 1 when 
    :: ipv4 - when at least one packet is lost. When sending more than one packet 
    ::   the easiest way to check for reply is search the string "TTL=" in 
    ::   the output of the command. 
    :: ipv6 - when all packet are lost. 
    :: 
    :: we get errorlevel = 0 when 
    :: ipv4 - all packets are received. BUT pinging a inactive host on the same 
    ::   subnet result in no packet lost. It is necessary to check for "TTL=" 
    ::   string in the output of the ping command 
    :: ipv6 - at least one packet reaches the host 
    :: 
    :: We can try to determine if the input address (or host name) will result in 
    :: ipv4 or ipv6 pinging, but it is easier to check the result of the command 
    :: 
    ::       +--------------+-------------+ 
    ::       | TTL= present | No TTL | 
    :: +-----------------------+--------------+-------------+ 
    :: | ipv4 errorlevel 0 |  OK  | ERROR | 
    :: |   errorlevel 1 |  OK  | ERROR | 
    :: +-----------------------+--------------+-------------+ 
    :: | ipv6 errorlevel 0 |    |  OK  | 
    :: |   errorlevel 1 |    | ERROR | 
    :: +-----------------------+----------------------------+ 
    :: 
    :: So, if TTL= is present in output, host is online. If TTL= is not present, 
    :: errorlevel is 0 and the address is ipv6 then host is online. In the rest 
    :: of the cases host is offline. 
    :: 
    :: To determine the ip version, a regular expresion to match a ipv6 address is 
    :: used with findstr. As it will be only tested in the case of no errorlevel, 
    :: the ip address will be present in ping command output. 

    set "exitCode=1" 
    >nul 2>nul (
     find "TTL=" "%tempFile%" && (set "exitCode=0") || (
      if not defined pingError (
       findstr /r /c:" [a-f0-9:][a-f0-9]*:[a-f0-9:%%]*[a-f0-9]: " "%tempFile%" && set "exitCode=0" 
      ) 
     ) 
     del /q "%tempFile%" 
    ) 

    :: cleanup and return errorlevel: 0=online , 1=offline 
    endlocal & exit /b %exitCode% 
+0

謝謝你。看起來它比縮短我的原始測試更加延長。這是非常豐富的,但。我剛開始混淆批處理命令。 – Konan

+1

@Konan,如果您在測試ipv4或ipv6地址/主機名稱時不知道先驗,它會更長。如果您只需要ipv4,請使用'find「TTL =」'方法。如果你只需要ipv6,使用'errorlevel'。問題是必須處理 –

+0

我看,我想我認爲我ping所有ipv4,所以我只是修改它以找到「ttl =」和「無法訪問」這應該趕上所有我希望的問題。 – Konan