2015-01-02 41 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