package org.kne.cloud.network; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.net.NoRouteToHostException; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.Consumer; public class IPMulticastDiscovery implements Closeable, AutoCloseable { private static final boolean debug=false; private MulticastSocket soc; private NetworkInterface ninterface; private volatile boolean closed = false; private InetSocketAddress group; private InetSocketAddress bind; private int type; private List msas; private UUID selfUUID; private volatile Consumer con; private long timeInterval; public long getTimeInterval() { return timeInterval; } public void setTimeInterval(long timeInterval) { this.timeInterval = timeInterval; } public NetworkInterface getNinterface() { return ninterface; } public InetSocketAddress getGroup() { return group; } public InetSocketAddress getBind() { return bind; } public Consumer getCon() { return con; } public void setCon(Consumer con) { this.con = con; } public IPMulticastDiscovery(InetSocketAddress bind, InetSocketAddress group, NetworkInterface ninterface, List msas,UUID node,long timeInterval) throws IOException { soc = new MulticastSocket(bind); soc.joinGroup(group, ninterface); this.bind = bind; this.group = group; this.ninterface = ninterface; this.msas = msas; this.selfUUID=node; this.timeInterval=timeInterval; } public void start() { ThreadTool.makeVDaemonThreadIfSupport("线路通知线程", () -> { try { while (!closed) { HashSet s = new HashSet(); synchronized (msas) { for (Iterator iterator = msas.iterator(); iterator.hasNext();) { MultipurposeSocketAddress multipurposeSocketAddress = (MultipurposeSocketAddress) iterator .next(); MultipurposeSocketAddress mpsa = new MultipurposeSocketAddress( multipurposeSocketAddress.getType(), "::0", multipurposeSocketAddress.getPort()); try { if (s.add(mpsa)) { boolean bf = true; Enumeration ei = ninterface.getInetAddresses(); while (ei.hasMoreElements()) { InetAddress inetAddress = (InetAddress) ei.nextElement(); if (inetAddress.equals(multipurposeSocketAddress.getInetAddress())) { bf = false; break; } } if (bf) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dops = new DataOutputStream(baos); dops.writeInt(multipurposeSocketAddress.getPort()); dops.writeUTF(multipurposeSocketAddress.getType()); dops.writeLong(selfUUID.getMostSignificantBits()); dops.writeLong(selfUUID.getLeastSignificantBits()); dops.close(); byte[] b = baos.toByteArray(); DatagramPacket dp = new DatagramPacket(b, b.length, group); soc.send(dp); if(debug) System.out.println("发送广播:"+multipurposeSocketAddress+" "+group+" "+selfUUID); } } } catch (NoRouteToHostException|UnknownHostException e) { } } } Thread.sleep(timeInterval); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } finally { try { close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); ThreadTool.makeVDaemonThreadIfSupport("线路发现线程",()->{ try { loop:while (!closed) { try { byte[] b = new byte[65535]; DatagramPacket dp = new DatagramPacket(b, b.length); soc.receive(dp); ByteArrayInputStream bis = new ByteArrayInputStream(b, 0, dp.getLength()); DataInputStream dis = new DataInputStream(bis); int port = dis.readInt(); String type = dis.readUTF(); long h=dis.readLong(); long l=dis.readLong(); UUID uid=new UUID(h, l); dis.close(); MultipurposeSocketAddress mpsa = new MultipurposeSocketAddress(type, dp.getAddress().getHostAddress(), port); if(debug) { if(uid.equals(selfUUID)) { System.out.println("丢弃广播:"+mpsa+" "+dp.getSocketAddress()+" "+uid); continue; }else { System.out.println("接收广播:"+mpsa+" "+dp.getSocketAddress()+" "+uid); } } InetAddress mpsai=mpsa.getInetAddress(); Enumeration ei = ninterface.getInetAddresses(); while (ei.hasMoreElements()) { InetAddress inetAddress = (InetAddress) ei.nextElement(); if (inetAddress.equals(mpsai)) { continue loop; } } if (con != null) { con.accept(mpsa); } }catch(UnknownHostException e) { }catch(EOFException e) { } } } catch(SocketException e) { if(!isClosed()) e.printStackTrace(); }catch (IOException e) { System.out.println(bind + " " + group + " " + ninterface); e.printStackTrace(); } finally { try { close(); } catch (IOException e) { e.printStackTrace(); } } }); } @Override public void close() throws IOException { soc.close(); closed = true; } public boolean isClosed() { return closed; } }