java · 2025-06-30 0

java 网络异常的11种情况及使用 iptables 模拟复现

最近公司的项目在客户侧运行,连接 Oracle 偶然会出现异常的情况。故这里统计了下,出现网络异常的11种情况及模拟复现。

1.模拟复现

1.客户端发送 3 次 ARP 请求,服务端没有响应(host 不存在;或服务器没有响应)
会抛出异常 "没有到主机的路由";

2.客户端发送 TCP SYN 请求,服务端响应 icmp-port-unreachable
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT)
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with icmp-port-unreachable)
会抛出异常 "连接被拒绝";

3.客户端发送 TCP SYN 请求,服务端响应 icmp-net-unreachable
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with icmp-net-unreachable)
会抛出异常 “网络不可达”

4.客户端发送 TCP SYN 请求,服务端响应 icmp-net-unreachable
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with icmp-net-unreachable)
会抛出异常 “没有到主机的路由”

5.客户端发送 TCP SYN 请求,服务端响应 icmp-proto-unreachable
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with icmp-proto-unreachable)
会抛出异常 “不可用的协议”

6.客户端发送 TCP SYN 请求,服务端响应 icmp-net-prohibited
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with icmp-net-prohibited)
会抛出异常 “网络不可达”

7.客户端发送 TCP SYN 请求,服务端响应 icmp-host-prohibited
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with icmp-host-prohibited)
会抛出异常 “没有到主机的路由”

8.客户端发送 TCP SYN 请求,服务端响应 icmp-admin-prohibited
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with icmp-admin-prohibited)
会抛出异常 “没有到主机的路由”

9.客户端发送 TCP SYN 请求,服务端响应 tcp-reset
(可用 iptables 控制,拒绝连接, iptables -t filter -A INPUT -p tcp --dport 1234 -j REJECT --reject-with tcp-reset)
会抛出异常 “连接被拒绝”

10.客户端发送 TCP SYN 请求,服务端不响应
(可用 iptables 控制,丢弃包 iptables -t filter -A INPUT -p tcp --dport 1234 -j DROP)
会抛出异常 "连接超时"

11.客户端服务端三次握手完成,服务端长时间没有发送数据
会抛出异常 "读取超时"

2.示例代码

@Test
public void testConnect1() throws Exception {
    String host = "172.17.0.2";
    int port = 1234;
    // 读取超时5秒
    int readTimeout = 5000;

    long beginTime = System.currentTimeMillis();
    try {
        InetSocketAddress socketAddress = new InetSocketAddress(host, port);

        /**
         * 会抛出
         * 1.ConnectException("没有到主机的路由")
         * 2.ConnectException("连接被拒绝")
         * 3.SocketException("网络不可达")
         * 4.NoRouteToHostException("没有到主机的路由")
         * 5.SocketException("不可用的协议")
         * 6.SocketException("网络不可达")
         * 7.NoRouteToHostException("没有到主机的路由")
         * 8.NoRouteToHostException("没有到主机的路由")
         * 9.ConnectException("连接被拒绝")
         * 10.ConnectException("连接超时") 自测发现 134s
         *
         * @see sun.nio.ch.Net#connect0(boolean, FileDescriptor, InetAddress, int)
         */
        SocketChannel socketChannel = SocketChannel.open(socketAddress);

        Socket socket = socketChannel.socket();
        // 设置读取超时
        socket.setSoTimeout(readTimeout);

        // 获取输入
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        String line;
        /**
         * 会抛出
         * 11.SocketTimeoutException()
         *
         * @see sun.nio.ch.SocketAdaptor$SocketInputStream#read(ByteBuffer)
         */
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    } finally {
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    }
}

@Test
public void testConnect2() throws Exception {
    String host = "172.17.0.2";
    int port = 1234;
    // 连接读取超时 5秒
    int connectTimeout = 5000;
    // 读取超时 5秒
    int readTimeout = 5000;

    long beginTime = System.currentTimeMillis();
    try {
        InetSocketAddress socketAddress = new InetSocketAddress(host, port);

        Socket socket = new Socket();
        /**
         * 会抛出
         * 1.NoRouteToHostException("没有到主机的路由 (Host unreachable)")
         * 2.ConnectException("连接被拒绝 (Connection refused)")
         * 3.SocketException("网络不可达 (connect failed)")
         * 4.NoRouteToHostException("没有到主机的路由 (Host unreachable)")
         * 5.SocketException("不可用的协议 (connect failed)")
         * 6.SocketException("网络不可达 (connect failed)")
         * 7.NoRouteToHostException("没有到主机的路由 (Host unreachable)")
         * 8.NoRouteToHostException("没有到主机的路由 (Host unreachable)")
         * 9.ConnectException("连接被拒绝 (Connection refused)")
         * 10.SocketTimeoutException("connect timed out")
         *
         * @see java.net.PlainSocketImpl#socketConnect(InetAddress, int, int)
         */
        socket.connect(socketAddress, connectTimeout);
        // 设置读取超时
        socket.setSoTimeout(readTimeout);

        // 获取输入
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        String line;
        /**
         * 会抛出
         * 11.SocketTimeoutException("Read timed out")
         *
         * @see java.net.SocketInputStream#socketRead0(FileDescriptor, byte[], int, int, int)
         */
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    } finally {
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    }
}