根据主机名在局域网跨网段找IP升级版

    之前写了个同样功能的例子,里面用的是TCP socket通信逐个IP进行查找,效率比较低。现在改成UDP进行广播,在限定时间内没找到会放弃。本版本效率应该高很多。当然,条件是被查找的机器也运行以下代码:

public class IpHostInLan1
{
    private static final int PORT = 4322;
    private static final String NOT_FOUND = "NotFound";
    
    private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
    
    private static IpHostInLan1 instance = new IpHostInLan1();
    
    private DatagramSocket ss = null;
    
    private byte[] sendPacket = "Hi".getBytes();
    
    private IpHostInLan1() 
    {
        new Thread() 
        {
            public void run()
            {
                try
                {
                    String localHost = InetAddress.getLocalHost().getHostName();
                    ss = new DatagramSocket(PORT);
                    System.out.println("--------Listening to " + PORT + "----------");
                    byte[] buffer = new byte[4];
                    byte[] response = localHost.getBytes();
                    while (true)
                    {
                        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                        try
                        {
                            ss.receive(packet);
                            SocketAddress peerAddr = packet.getSocketAddress();
                            DatagramPacket responsePacket = new DatagramPacket(response, response.length, peerAddr);
                            ss.send(responsePacket);
                            System.out.println("Server received : " + new String(packet.getData(), 0, packet.getLength()));
                        }
                        catch (IOException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    
    public static IpHostInLan1 instance()
    {
        return instance;
    }
    
    /**
     * 获取主机名对应的IP。如果map中没有那么到局域网里面去找。
     * @param host
     * @return
     */
    public  String getIp(String host, long timeout)
    {
        String ip = map.get(host);
        
        if (ip != null)
        {
            //之前找过,现在不找了
            if (ip.equals(NOT_FOUND)) return null;
            
            return ip;
        }
        
        ip = search(host, timeout);
        if (ip == null)
        {
            map.put(host, NOT_FOUND);
        }
        else
        {
            map.put(host, ip);
        }
        
        return ip;
    }
    
    private String search(final String host, final long timeout) {
        String ip = null;
        try
        {
            ip = InetAddress.getByName(host).getHostAddress();
        }
        catch (Exception e)
        {
            System.out.println("failed to find " + host + " in my own IP segment.");
        }
        
        if (ip == null)
        {
            try
            {
                final DatagramSocket ds = new DatagramSocket(); 
                ds.setSoTimeout(100);
                //开启检查接收结果的线程
                ExecutorService service = Executors.newFixedThreadPool(1);
                final Future<String> future = service.submit(new Callable<String>()
                    {
                        public String call()
                        {
                            long startTime = System.currentTimeMillis();
                            byte[] buffer = new byte[32];
                            while (System.currentTimeMillis()-startTime < timeout)
                            {
                                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                                try
                                {
                                    ds.receive(packet);
                                    String response = new String(packet.getData(), 0, packet.getLength());
                                    String resultIp = packet.getAddress().getHostAddress();
                                    if (host.equals(response))
                                    {
                                        return resultIp;
                                    }
                                    map.put(host, resultIp); //如果有其它回应,缓存起来
                                }
                                catch (IOException e){}
                            }
                            
                            return null;
                        }
                    }
                );
                
                //开启发送线程
                new Thread()
                {
                    public void run()
                    {
                        send(future, ds);
                    }
                }.start();
                
                if (ip == null)
                {
                    try
                    {
                        //在指定时间内等待结果,如果时间到,那么放弃查找
                        ip = future.get(timeout, TimeUnit.MILLISECONDS);
                    }
                    catch (Exception e){}
                }
                service.shutdownNow(); //不用发了
                ds.close(); //放弃查找,关闭该socket
            }
            catch (SocketException e)
            {
                e.printStackTrace();
            }
        }
        
        return ip;
    }
    
    /**
     * 往各个IP发送数据包,如果已经得到结果则停止发送。
     * @param future
     * @param ds
     * @return
     */
    private String send(Future<String> future, DatagramSocket ds) 
    {
        String ip = null;
        try 
        {
            String[] segs = InetAddress.getLocalHost().getHostAddress().split("[.]");
            String prefix = segs[0] + "." + segs[1] + ".";
            int localSeg = Integer.valueOf(segs[2]);
            int i = 1;
            while (localSeg + i < 256 || localSeg - i > -1)
            {
                if (localSeg + i < 256)
                {
                    if (false == send(prefix + (localSeg + i) + ".", ds)) break;
                    try
                    {
                        //检查是否已经有结果了
                        ip = future.get(1, TimeUnit.MILLISECONDS);
                    }
                    catch (Exception e) {}
                    if (ip != null) break;
                }
                if (localSeg - i > -1)
                {
                    if (send(prefix + (localSeg - i) + ".", ds)) break;
                    try
                    {
                        //检查是否已经有结果了
                        ip = future.get(1, TimeUnit.MILLISECONDS);
                    }
                    catch (Exception e) {}
                    if (ip != null) break;
                }
                i++;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        
        return ip;
    }
    
    private boolean send(String prefix, DatagramSocket ds) 
    {
        System.out.format("Searching in %s segment...\n", prefix);
        
        for (int i=2; i<256; i++)
        {
            String ip = prefix + i;
            if (!send(ds, ip))
            {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 往指定的IP发送一个数据包
     * @param ds
     * @param ip
     */
    private boolean send(DatagramSocket ds, String ip)
    {
        try
        {
            InetAddress addr = InetAddress.getByName(ip);
            DatagramPacket p = new DatagramPacket(sendPacket, sendPacket.length, addr, PORT);
            ds.send(p);
        }
        catch (Exception e)
        {
//            e.printStackTrace();
            return false;
        }
        
        return true;
    }
    
    public static void main(String[] args) throws IOException
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while ((line=br.readLine()).equalsIgnoreCase("exit") == false)
        {
            System.out.println(IpHostInLan1.instance().getIp(line, 2000));
        }
        System.exit(0);
    }
}

  

你可能感兴趣的:(socket,效率,UDP,广播,局域网)