204 lines
5.7 KiB
Java
204 lines
5.7 KiB
Java
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<MultiProtocolSocketAddress> msas;
|
|
private UUID selfUUID;
|
|
|
|
private volatile Consumer<MultiProtocolSocketAddress> 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<MultiProtocolSocketAddress> getCon() {
|
|
return con;
|
|
}
|
|
|
|
public void setCon(Consumer<MultiProtocolSocketAddress> con) {
|
|
this.con = con;
|
|
}
|
|
|
|
public IPMulticastDiscovery(InetSocketAddress bind, InetSocketAddress group, NetworkInterface ninterface,
|
|
List<MultiProtocolSocketAddress> 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<MultiProtocolSocketAddress> 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<InetAddress> 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;
|
|
}
|
|
|
|
}
|