Java检测网络地址和服务器是否可用

本文介绍了一款用于检测机房设备IP是否可达及web服务器运行状态的Java实用工具。该工具能够实现对不同协议(HTTP/HTTPS)的web服务器进行访问检查,并验证普通IP地址的连通性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做一个机房巡检的小程序,希望在程序中可以检测机房的各设备IP是否能ping通,以及搭建有web服务器的设备运行是否正常,也就是能正常访问,在网上搜索了相关资料学习后,发现要么只有测试ping的,要么只有测试服务器的,所以我将他们整合起来做成一个Util,方便使用。以下是Util源码:

package core.util;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

public class NetStateUtil {
    static HostnameVerifier hv = new HostnameVerifier() {  
        public boolean verify(String urlHostName, SSLSession session) {  
            return true;  
        }  
    };  
    public String connectingAddress(String remoteInetAddr){
        boolean flag=false;
        String tempUrl=remoteInetAddr.substring(0, 5);//取出地址前5位
        if(tempUrl.contains("http")){//判断传过来的地址中是否有http
            if(tempUrl.equals("https")){//判断服务器是否是https协议
                try {
                    trustAllHttpsCertificates();//当协议是https时
                } catch (Exception e) {
                    e.printStackTrace();
                }  
                HttpsURLConnection.setDefaultHostnameVerifier(hv);//当协议是https时
            }
            flag=isConnServerByHttp(remoteInetAddr);
        }else{//传过来的是IP地址
            flag=isReachable(remoteInetAddr);
        }
        if(flag){
            return "正常";
        }else{
            return "异常";
        }
    }
    /**
     * 传入需要连接的IP,返回是否连接成功
     *
     * @param remoteInetAddr
     * @return
     */
    public static boolean isReachable(String remoteInetAddr) {// IP地址是否可达,相当于Ping命令
        boolean reachable = false;
        try {
            InetAddress address = InetAddress.getByName(remoteInetAddr);
            reachable = address.isReachable(1500);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return reachable;
    }

    public static boolean isConnServerByHttp(String serverUrl) {// 服务器是否开启
        boolean connFlag = false;
        URL url;
        HttpURLConnection conn = null;
        try {
            url = new URL(serverUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(3 * 1000);
            if (conn.getResponseCode() == 200) {// 如果连接成功则设置为true
                connFlag = true;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            conn.disconnect();
        }
        return connFlag;
    }
    /*以下是Https适用*/
    private static void trustAllHttpsCertificates() throws Exception {  
        javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];  
        javax.net.ssl.TrustManager tm = new miTM();  
        trustAllCerts[0] = tm;  
        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext  
                .getInstance("SSL");  
        sc.init(null, trustAllCerts, null);  
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc  
                .getSocketFactory());  
    }  
 
    static class miTM implements javax.net.ssl.TrustManager,  
            javax.net.ssl.X509TrustManager {  
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
            return null;  
        }  
 
        public boolean isServerTrusted(  
                java.security.cert.X509Certificate[] certs) {  
            return true;  
        }  
 
        public boolean isClientTrusted(  
                java.security.cert.X509Certificate[] certs) {  
            return true;  
        }  
 
        public void checkServerTrusted(  
                java.security.cert.X509Certificate[] certs, String authType)  
                throws java.security.cert.CertificateException {  
            return;  
        }  
 
        public void checkClientTrusted(  
                java.security.cert.X509Certificate[] certs, String authType)  
                throws java.security.cert.CertificateException {  
            return;  
        }  
    }  
    /*以上是Https适用*/
}

测试的时候只需要将IP地址或web服务器的地址传过去就可以进行检测,检测返回的结果是“正常”或“异常”:

       NetStateUtil netStateUtil=new NetStateUtil();
        String url1="https://1.1.1.1:2017";//测试https
        String url2="http://1.1.1.1:2017";//测试http
        String url3="1.1.1.1";//测试普通ip
        System.out.println(url1+":"+netStateUtil.connectingAddress(url1));
        System.out.println(url2+":"+netStateUtil.connectingAddress(url2));
        System.out.println(url3+":"+netStateUtil.connectingAddress(url3));

说明一下,上面的几个url的字符串中的ip我已经更改过了,大家拿去后更改成自己想测试的ip即可

<think>根据用户的问题,他想要了解在Java中如何探测服务器是否可达或可用,以便在访问多个服务器时实现故障转移策略(第一个不通就访问下一个)。结合之前的对话历史,用户可能更关注简单、高效的探测方法,用于自定义故障转移逻辑。 从引用中可以看到几种探测服务器可达性的方法: 1. **使用`InetAddress.isReachable()`方法**(引用[1][5]):这是Java标准库提供的方法,通过ICMP协议(需要系统支持)或TCP端口7(Echo服务)来探测主机是否可达。但该方法在不同平台上的行为可能不一致,且受防火墙设置影响。 2. **调用系统Ping命令**(引用[4]):通过执行操作系统的ping命令(如`ping 127.0.0.1 -n 10 -w 4`)并解析输出结果来判断可达性。这种方法更接近用户习惯的ping行为,但依赖于操作系统,且需要处理命令输出。 3. **基于TCP端口连接**(引用[3]):尝试建立到服务器特定端口(如Redis的6379端口)的TCP连接,如果连接成功则认为服务器可用。这种方法更适用于有特定服务端口的场景。 针对用户需求,以下是几种探测方法的详细实现: ### 方法1:使用`InetAddress.isReachable()`(简单但可能不可靠) ```java import java.net.InetAddress; public class ServerReachability { public static boolean isServerReachable(String host, int timeout) { try { InetAddress address = InetAddress.getByName(host); return address.isReachable(timeout); } catch (Exception e) { return false; // 任何异常都视为不可达 } } } ``` **缺点**: - 在Windows上默认使用ICMP,但可能需要管理员权限。 - 在Linux/Unix上,如果ICMP被防火墙禁止,则可能回退到TCP端口7(Echo),但该端口通常未开放[^1]。 - 超时时间可能不精确。 ### 方法2:执行系统Ping命令(跨平台兼容性好) ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class PingCommand { public static boolean ping(String host, int count, int timeoutSeconds) { String command = buildCommand(host, count, timeoutSeconds); try { Process process = Runtime.getRuntime().exec(command); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream()) ); String line; int successCount = 0; while ((line = reader.readLine()) != null) { // 根据输出行判断成功次数(适配中英文环境) if (line.contains("TTL=") || line.contains("ttl=")) { successCount++; } } int exitCode = process.waitFor(); // 如果成功次数等于测试次数,则认为完全可达 return successCount >= count; } catch (Exception e) { return false; } } private static String buildCommand(String host, int count, int timeoutSeconds) { String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win")) { return "ping -n " + count + " -w " + (timeoutSeconds * 1000) + " " + host; } else { return "ping -c " + count + " -W " + timeoutSeconds + " " + host; } } } ``` **优点**:行为与命令行ping一致,结果更可靠。 **缺点**:需要处理不同操作系统的命令格式,且可能被安全策略限制。 ### 方法3:TCP端口探测(推荐用于服务可用性检查) 如果服务器运行了特定服务(如HTTP、Redis),直接尝试建立TCP连接更能反映服务可用性: ```java import java.net.Socket; public class TcpProbe { public static boolean isPortReachable(String host, int port, int timeout) { try (Socket socket = new Socket()) { socket.connect(new java.net.InetSocketAddress(host, port), timeout); return true; } catch (Exception e) { return false; } } } ``` **适用场景**:当您知道服务器应开放的端口时(如HTTP服务端口80),此方法最有效。 ### 故障转移策略整合示例 结合TCP端口探测实现故障转移: ```java import java.util.List; public class ServerFailover { private static final List<String> SERVERS = List.of("server1:80", "server2:80", "server3:80"); public static void main(String[] args) { for (String server : SERVERS) { String[] parts = server.split(":"); String host = parts[0]; int port = Integer.parseInt(parts[1]); if (TcpProbe.isPortReachable(host, port, 3000)) { System.out.println("服务器 " + server + " 可用,执行请求..."); // 执行实际请求逻辑 break; } else { System.out.println("服务器 " + server + " 不可用,尝试下一个..."); } } } } ``` ### 总结建议 - **简单场景**:使用`InetAddress.isReachable()`,但注意其局限性[^1]。 - **高可靠性要求**:执行系统Ping命令(方法2)或TCP端口探测(方法3)。 - **服务端应用**:优先选择TCP端口探测,因为它直接检查服务端口是否响应。 §§相关问题§§ 1. `InetAddress.isReachable()`方法在LinuxWindows上的实现差异有哪些? 2. 如何通过Java实现类似Ping命令的延迟丢包率统计? 3. 在防火墙限制ICMP的环境下,如何准确探测服务器可用性? 4. 使用TCP探测时,如何避免因连接池耗尽导致的误判?</think>### Java 探测服务器可达性的方法总结 在 Java 中探测服务器是否可达(可用)是实现故障转移策略的关键步骤。以下是几种常用方法,结合您的需求(第一个不通就访问下一个)提供具体实现: --- ### 1. 使用 `InetAddress.isReachable()`(标准库方法) **原理**:通过 ICMP 协议(Ping)或 TCP 端口 7(Echo 服务)探测可达性[^1][^5]。 **适用场景**:简单的主机可达性检查(无需特定端口)。 ```java import java.net.InetAddress; public class ServerProbe { public static boolean isServerReachable(String host, int timeout) { try { return InetAddress.getByName(host).isReachable(timeout); } catch (Exception e) { return false; // 不可达 } } } ``` **用法示例**: ```java List<String> servers = Arrays.asList("192.168.1.10", "192.168.1.20", "192.168.1.30"); int timeout = 3000; // 3秒超时 for (String server : servers) { if (ServerProbe.isServerReachable(server, timeout)) { System.out.println(server + " 可达,执行操作"); break; // 成功则停止尝试 } System.out.println(server + " 不可达,尝试下一台"); } ``` **优缺点**: - ✅ 无需额外依赖 - ❌ 受系统防火墙限制(部分环境需管理员权限) - ❌ 默认行为可能因操作系统而异(Windows/Linux 实现不同)[^1] --- ### 2. 执行系统 Ping 命令(兼容性更强) **原理**:调用操作系统的 `ping` 命令并解析输出结果[^2][^4]。 **适用场景**:需要精确控制 Ping 参数或跨平台兼容的场景。 ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class PingCommand { public static boolean ping(String host, int count, int timeoutSec) { try { // 构建命令(兼容 Windows/Linux) String command = System.getProperty("os.name").toLowerCase().contains("win") ? "ping -n " + count + " -w " + (timeoutSec * 1000) + " " + host : "ping -c " + count + " -W " + timeoutSec + " " + host; Process process = Runtime.getRuntime().exec(command); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); int successCount = 0; String line; while ((line = reader.readLine()) != null) { // 检测成功响应行(兼容中英文) if (line.contains("TTL=") || line.contains("ttl=")) { successCount++; } } return successCount >= count; // 成功次数达标 } catch (Exception e) { return false; } } } ``` **用法示例**: ```java if (PingCommand.ping("example.com", 3, 2)) { System.out.println("服务器可达"); } ``` **优点**: - ✅ 行为与命令行一致,结果可靠 - ✅ 可自定义 Ping 次数超时 - ✅ 跨平台兼容性好[^4] --- ### 3. TCP 端口探测(服务级可用性检查) **原理**:尝试建立 TCP 连接检测特定端口是否开放[^3]。 **适用场景**:需要验证具体服务(如 HTTP/Redis)是否可用。 ```java import java.net.Socket; public class PortProbe { public static boolean isPortReachable(String host, int port, int timeout) { try (Socket socket = new Socket()) { socket.connect(new java.net.InetSocketAddress(host, port), timeout); return true; // 连接成功 } catch (Exception e) { return false; // 连接失败 } } } ``` **用法示例**: ```java // 检测 Redis 服务是否可用 if (PortProbe.isPortReachable("redis-server.com", 6379, 3000)) { System.out.println("Redis 服务在线"); } ``` --- ### 故障转移策略整合示例 结合以上方法实现完整故障转移: ```java public class FailoverStrategy { private static final List<String> SERVERS = Arrays.asList( "primary-server:8080", "backup-server:8080", "fallback-server:8080" ); public static void executeRequest() { for (String server : SERVERS) { String[] parts = server.split(":"); String host = parts[0]; int port = Integer.parseInt(parts[1]); // 先检测主机可达性 if (!PingCommand.ping(host, 1, 2)) { System.out.println(host + " 主机不可达"); continue; } // 再检测服务端口 if (PortProbe.isPortReachable(host, port, 3000)) { System.out.println("正在使用服务器: " + server); // 执行实际业务请求 break; } } } } ``` --- ### 选择建议 1. **简单主机探测** → `InetAddress.isReachable()` 2. **精确 Ping 检测** → 执行系统 Ping 命令 3. **服务可用性验证** → TCP 端口探测 4. **生产环境推荐**:结合 `PingCommand` + `PortProbe` 双重检查 > ⚠️ **注意**: > - 防火墙可能阻塞 ICMP(Ping)请求,TCP 端口探测更可靠[^3] > - 超时时间建议设置在 2-5 秒之间,避免用户等待过长 > - 高并发场景使用连接池管理 Socket,避免资源耗尽 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值