在什么情况下Socket.getLocalAddress()是IPv6还是IPv4?

时间:2016-08-04 16:19:24

标签: java sockets network-programming ipv6 ipv4

我正在编写一个打开 <a href="//safeweb.norton.com /a> 的Java应用程序,如下所示:

    var nortonlink = element(by.css('[href="//safeweb.norton.com/"]'));

    nortonlink.click();

    expect(browser.getCurrentUrl()).toEqual('https://safeweb.norton.com/');

偶尔执行读写操作。对于将数据与数据包一起发送很重要的一个功能是连接的本地和远程地址。例如,我得到的本地地址字节为:

Socket

我的协议希望在标头中发送发件人的IPv4。但是,有时此函数返回16个字节而不是4个字节,这会导致问题。更令人困惑的是,行为有时会在程序的同一次运行中发生变化,尽管相同的Socket对象为之前的调用返回IPv4 。很难复制,我仍然不确定它在什么情况下会发生。

在什么情况下上面会返回IPv6而不是IPv4?这取决于我正在运行的网络吗?什么会导致它在程序执行过程中发生变化?

2 个答案:

答案 0 :(得分:1)

您正在创建Socket对象而未将其本地显式绑定到IPv4或IPv6地址,因此它将根据您是否connect()创建并绑定内部IPv4或IPv6套接字到远程服务器使用IPv4或IPv6地址。

如果serverInetAddress,则IP版本将取决于您使用Inet4Address还是Inet6Address

但如果serverstring,则必须将其解析为InetAddress,该解决方案将取决于string是否包含文字IPv4地址,文字IPv6地址或主机名。对于文字地址,答案很明显 - 文字IPv4地址将解析为Inet4Address,文字IPv6地址将解析为Inet6Address。但hostname可以采用任何一种方式,具体取决于DNS查找的结果。

如果server是主机名,并且您希望仅将结果限制为IPv4,请直接调用InetAddress.getAllByName()并循环生成的数组(主机名可能分配了多个IP地址), connect()仅限Inet4Address个地址,直到其中一个地址成功:

socketConnection = null;

for(InetAddress addr : InetAddress.getAllByName(server))
{
    if (addr instanceof Inet4Address)
    {
        socketConnection = new Socket();
        try {
            socketConnection.connect(new InetSocketAddress(addr, port));
            break;
        }
        catch (IOException e) {
            socketConnection = null;
        }
    }
}

if (socketConnection == null) {
    throw new ConnectException("Cannot connect to '" + host + "' using IPv4");
}

答案 1 :(得分:1)

我能够确定导致问题的原因,尽管我还不确定究竟发生了什么。如果服务器端连接中断,并且从套接字读取导致Broken pipe错误,则会发生此行为。请参阅下文,了解我如何复制它:

    Socket s = new Socket();
    String server = "1.2.3.4" // not my real server ip
    s.connect(new InetSocketAddress(server, 9050));
    try{
        System.out.println(s.getLocalAddress().getAddress().length);
        byte[] badData = new byte[100];
        // server application will kill the connection when it cant parse this
        // according to application logic
        Arrays.fill(badData, (byte) 0xFF);
        for(int i = 0; i < 1000; i++){
            OutputStream out = s.getOutputStream();
            out.write(badData);
            out.flush();
            Thread.sleep(1);
        }

    }
    catch(SocketException e){
        System.out.println(e.getMessage());
        System.out.println(s.getLocalAddress().getAddress().length);
    }

其中输出以下内容:

4
Broken pipe
16

所以,我已经弄清楚是什么导致了它,但仍然没有深入了解为什么从Java发生这种行为。