更改日期到将来之后发生java.net.UnknownHostException

时间:2014-09-25 01:00:55

标签: java date urlconnection disconnect unknown-host

按照以下说明操作后发生java.net.UnknownHostException:

说明:

  1. 断开计算机与Internet的连接(例如:关闭调制解调器)
  2. 将操作系统日期更改为将来的14天
  3. 运行以下代码
  4. 点击“执行测试”按钮
  5. 您将收到异常消息,但这是正确的,因为互联网已断开连接
  6. 在消息窗口中单击“确定”
  7. 重新连接互联网
  8. 将操作系统日期更改回今天的日期
  9. 点击“执行测试”按钮
  10. 您将收到异常消息,但您不应该,因为互联网已连接
  11. 您可以反复点击“执行测试”按钮,尽管已连接到互联网,但仍会获得相同的例外情况。
  12. 如果您在浏览器上测试网址(http://test.com),则可以使用
  13. 为什么会这样?我想这不应该发生。

    简单代码:

    公共类TestUrlConnection {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run(){
                createAndShowGui();
            }
        });
    }
    
    private static void createAndShowGui(){
        final JFrame frame = new JFrame("Test URL Connection");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
        JButton btOk = new JButton("Perform Test");     
        btOk.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e){
                try{
                    String content = readContentFromTestUrl();
                    if(content!=null)
                        JOptionPane.showMessageDialog(frame, "OK. URL Connection returned Content.\nContent length = "+content.length());
                    else
                        JOptionPane.showMessageDialog(frame, "Content is null, but no exception");
                }
                catch(IOException exc){
                    JOptionPane.showMessageDialog(frame, "Exception:\n\n"+stackTraceToString(exc));
                }
            }
        });
    
        frame.setContentPane(btOk);     
        frame.setMinimumSize(new Dimension(250,100));
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }   
    
    private static String readContentFromTestUrl() throws IOException{
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
    
        try {
            URL url = new URL("http://test.com");
            URLConnection urlConnection = url.openConnection();
            urlConnection.setUseCaches(false);
    
            is = urlConnection.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
    
            String inputLine;
            String content = "";
    
            while ((inputLine = br.readLine()) != null)
                content += inputLine + "\n";
    
            return content;
        }
        finally{
            if(is!=null){try{is.close();}catch(IOException e){e.printStackTrace();}}
            if(isr!=null){try{isr.close();}catch(IOException e){e.printStackTrace();}}
            if(br!=null){try{br.close();}catch(IOException e){e.printStackTrace();}}
        }
    }
    
    private static String stackTraceToString(IOException exc){
        exc.printStackTrace();
        StringWriter sw = new StringWriter();
        exc.printStackTrace(new PrintWriter(sw));
        String s = sw.toString();
        return s.substring(0, s.length()>600 ? 600 : s.length());
    }
    

    }

1 个答案:

答案 0 :(得分:2)

DNS查询很昂贵且结果变化很少,因此几乎每个网络实施都会缓存DNS查找结果,这样如果您在几秒钟内打开100个连接,则不必执行100个DNS查询,返回相同的IP地址。 / p>

Java实现没有什么不同,它可以缓存正面和负面(失败)查询。

默认情况下,否定结果会缓存10秒,但显然您的测试指出:

  1. 在执行另一次查找时检查先前缓存的结果是否有效,从实现的角度来看这很好。
  2. 缓存不是考虑时钟变化的,因此每个人都在改变运行Java网络的服务器的日期,应考虑这一点,以及许多其他不考虑时钟变化的软件包。
  3. 所以,会发生的事情是Java缓存test.com是无法解决的。它应该只存在10秒,所以它放在那里有一个时间戳。你改变时钟,这个时间戳而不是在10秒后失效,可能在14天10秒后失效。

    您可以看到它正在使用缓存值,因为首次点击该按钮需要花费大量时间,而其他点击几乎是静止的。

    一个简单的解决方案,也证明问题出在DNS缓存中,就是将此行添加为主要的第一行:

    java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "0");
    

    这告诉java不要缓存负DNS结果,如果你尝试,你会发现它会按预期运行。但是,禁用此类缓存会降低您的性能并导致安全问题,因此如果您突然更改计算机的日期,我建议重新启动JVM(以及大多数其他长时间运行的进程)。