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.*; import java.util.Enumeration; 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 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 getInterface() { return ninterface; } public InetSocketAddress getGroup() { return group; } public InetSocketAddress getBind() { return (InetSocketAddress) soc.getLocalSocketAddress(); } 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(null); soc.setReuseAddress(true); soc.bind(bind); soc.setNetworkInterface(ninterface); soc.joinGroup(group, ninterface); this.group = group; this.ninterface = ninterface; this.msas = msas; this.selfUUID=node; this.timeInterval=timeInterval; } public void start() { ThreadTool.makeVDaemonThreadIfSupport("线路通知线程", () -> { try { while (!closed) { /*MultipurposeSocketAddress mpsa = new MultipurposeSocketAddress( multipurposeSocketAddress.getType(), "::0", multipurposeSocketAddress.getPort());*/ if(msas!=null) { synchronized (msas) { for (Iterator iterator = msas.iterator(); iterator.hasNext(); ) { MultiProtocolSocketAddress multiProtocolSocketAddress = (MultiProtocolSocketAddress) iterator .next(); try { send(multiProtocolSocketAddress); } 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 { MultiProtocolSocketAddress mpsa = receive(); if (mpsa == null) continue; 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(getBind() + " " + group + " " + ninterface); e.printStackTrace(); } finally { try { close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } private MultiProtocolSocketAddress receive() throws IOException { 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); String val = dis.readUTF(); long h=dis.readLong(); long l=dis.readLong(); UUID uid=new UUID(h, l); dis.close(); MultiProtocolSocketAddress mpsa = new MultiProtocolSocketAddress(val); if(mpsa.getInetAddress().isAnyLocalAddress()){ mpsa=new MultiProtocolSocketAddress(mpsa.getProtocol(),dp.getAddress().getHostAddress(),mpsa.getPort()); } if(debug) { if(uid.equals(selfUUID)) { System.out.println(ninterface.getDisplayName()+" 丢弃广播:"+mpsa+" "+dp.getSocketAddress()+" "+uid); return null; }else { System.out.println(ninterface.getDisplayName()+ " 接收广播:"+mpsa+" "+dp.getSocketAddress()+" "+uid); } } return mpsa; } private void send(MultiProtocolSocketAddress multiProtocolSocketAddress) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dops = new DataOutputStream(baos); dops.writeUTF(multiProtocolSocketAddress.toString()); 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(ninterface.getDisplayName()+" 发送广播:"+ multiProtocolSocketAddress +" "+group+" "+selfUUID); } @Override public void close() throws IOException { soc.close(); closed = true; } public boolean isClosed() { return closed; } }