之前写了个同样功能的例子,里面用的是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);
}
}