UDP パケットを複数の受信者に送信する方法を実装しようとしています。setReuseAddress(true)
これは、受信する DatagramSocket インスタンスで実行可能な設定であるべきだと思いました。
私の問題は、特定の状況ではローカル コンピューターへの通信を制限する必要があることです。つまり、localhost インターフェイス (以下のデモ コードでは useLocalhost=true) です。このような場合、突然、最初の受信側ソケットのみが着信パケットを取得し、他の 2 つの受信側ソケットには何も表示されなくなります。
これを Windows (oracle 64 ビット) と Linux (OpenJDK 64 ビット) でテストしたため、次の 3 つの可能性しかありません。
- これは意図された既知の動作です (そして、私はメカニズム全体を理解していません - 別名「脳のバグ」)
- Java JRE にバグがあります
- 私のコードにバグがあります。
誰かがそのトピックに関する経験があり、問題がどこにあるかを特定するのを手伝ってもらえますか?
これを示す最小限の実例を以下に示します。実際の外部ホストからのネットワーク パケットをシミュレートするためにブロードキャスト アドレスを使用していることに注意してください。
すべてがうまくいけば、最後に 3 行が表示されます (この順序または別の順序で):
Thread-0 - packet received
Thread-1 - packet received
Thread-2 - packet received
public static void main(String[] args) throws Exception {
boolean useLocalhost = true;
InetSocketAddress addr;
String sendPacketTo = "192.168.1.255"; // we use broadcast so that packet comes from an real external address
if (useLocalhost)
sendPacketTo = "localhost"; // does not work (only listener 1 received packet)
addr = new InetSocketAddress(15002);
new MyThread(addr).start(); // Datagram socket listener 1
new MyThread(addr).start(); // Datagram socket listener 2
new MyThread(addr).start(); // Datagram socket listener 3
DatagramSocket so = new DatagramSocket();
so.setBroadcast(true); // does not change anything
so.connect(new InetSocketAddress(sendPacketTo, 15002));
so.send(new DatagramPacket("test".getBytes(), 4));
Thread.sleep(1000);
System.exit(0);
}
public static class MyThread extends Thread {
DatagramSocket socket;
public MyThread(InetSocketAddress addr) throws SocketException {
super();
setDaemon(true);
socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.setBroadcast(true); // does not change anything
socket.bind(addr);
System.out.println("Listener started: " + socket.getLocalAddress());
}
public void run() {
byte[] buf = new byte[10];
DatagramPacket p = new DatagramPacket(buf, buf.length);
try {
socket.receive(p);
System.out.println(Thread.currentThread().getName() + " - packet received");
} catch (IOException e) {
e.printStackTrace();
}
}
}