无法使用Java DatagramSocket捕获UDP广播数据包

时间:2013-12-30 18:09:49

标签: java sockets networking udp datagram

我正在创建一个客户端 - 服务器通信应用程序,并希望客户端能够自动检测并连接到服务器,因为它们位于同一网络上。

以前,我的代码适用于Linux和Windows机器。我会播放一条简单的信息,可以阅读。我还可以在使用Wireshark观看网络流量时看到该消息。

我采取的方法是

  1. 获取服务器上网络的广播地址。
  2. 在给定的时间内,广播一条消息(很快将成为服务器IP)
  3. 在客户端,请等待收到消息。
  4. 我对网络很陌生,所以任何明显的错误都可能不会立即显现出来。

    服务器广播代码:

    public class Broadcaster {
        /* ... */
        public void pulse() throws InterruptedException, IOException, SocketException {
            Long elapsed = new Date().getTime();
            Long timeout = elapsed + this.duration;
            DatagramPacket packet = new DatagramPacket(this.message.getBytes(), this.message.length());
            HashSet<InetAddress> channels = Broadcaster.getBroadcastChannels();
    
            while(elapsed <= timeout) {
                for(InetAddress channel : channels) {
                    DatagramSocket socket = new DatagramSocket(this.port);      
                    socket.setBroadcast(true);
                    socket.connect(channel, this.port);
                    socket.send(packet);        
                    System.out.println("Broadcast sent to " + channel.getHostAddress() + " (" + socket.getPort() + "): " + this.message);       
                    socket.close();
                }   
                Thread.sleep(this.frequency);
                elapsed = new Date().getTime();
            }
        }
    
        private static HashSet<InetAddress> getBroadcastChannels() throws SocketException {
            /* Returns 192.168.0.255 */
        }
    
        public static void main(String[] args) {
            Broadcaster heart = new Broadcaster("Hello from the Raspberry Pi!", 120000, 5000, 8027);
            try {
                heart.pulse();
            } catch(SocketException e) {
                /* ...etc... */
            } finally {
                System.out.println("Broadcasting completed.");
            }
        }
    }
    

    客户代码:

    public class BroadcastListener {
        private int port;
        private int length;
    
        public BroadcastListener(int length, int port) {
            this.port = port;
            this.length = length;
        }
    
        public String getNext() throws IOException {
            byte buffer[] = new byte[this.length];  
            DatagramSocket socket = new DatagramSocket(this.port);
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);  
            System.out.println("Waiting on " + socket.getLocalSocketAddress()); 
            socket.receive(packet);
            socket.close();
    
            return new String(buffer);
        }
    
        public static void main(String[] args) {
            System.out.println("Listening for network broadcasts...");
            BroadcastListener broadcast = new BroadcastListener(128, 8027);
    
            try {
                System.out.println("Received broadcast: " + broadcast.getNext());
            } catch(IOException e) {
                System.out.println("Could not receive broadcasts:");
                System.out.println(e.getMessage());
            }
        }
    }
    

    两个设备上显示的广播/网络掩码地址ifconfig输出为netmask 255.255.255.0 broadcast 192.168.0.255

    最让我困惑的是,Wireshark仍然看到广播但是当我运行客户端Java程序时,它只是位于socket.receive(packet);

    Wireshark screenshot on Imgur

    客户和客户服务器在端口8027上。很明显,广播公司正在工作,但客户端广播监听器不是。有谁知道会发生什么?谢谢!

3 个答案:

答案 0 :(得分:1)

如评论中所述:检查防火墙: - )

我认识到的另一件事是,如果我用wireshark嗅探,没有其他进程可以接收该数据报。在意识到这一点后,我编写了一个nodejs脚本,默认情况下为exclusive = false,但即使这样也无济于事。也许有一个内核标志或东西,UDP数据报不能被消费&#39;通过一个过程。

答案 1 :(得分:0)

看起来您的服务器可能在与客户端不同的地址上进行广播。您的客户端未分配InetAddress,请尝试在BroadcastListener

中使用此构造函数作为套接字
DatagramSocket socket = new DatagramSocket(new InetSocketAddress("192.168.0.255", this.port));

如果这不起作用,您可以尝试将服务器和客户端绑定到127.0.0.1

答案 2 :(得分:0)

您不断创建和销毁DatagramSockets。如果数据包在您没有DatagramSocket绑定到端口的时刻到达您的主机,它将被丢弃。

创建一个 DatagramSocket并在此代码的生命周期中保持打开状态。