简体   繁体   English

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

[英]Cannot capture UDP broadcast packets with Java DatagramSocket

I am creating a client-server communication application and would like the client to be able to detect and connect to the server automatically, given that they are on the same network. 我正在创建一个客户端-服务器通信应用程序,并且希望客户端能够自动检测并连接到服务器,因为它们位于同一网络上。

Previously, my code was working across a Linux and Windows machine. 以前,我的代码是在Linux和Windows计算机上运行的。 I would broadcast a simple message and it could be read. 我会广播一条简单的消息,它可以被读取。 I could also see the message while watching network traffic with Wireshark. 在使用Wireshark观看网络流量时,我也可以看到该消息。

The approach I am taking is to 我正在采取的方法是

  1. Get the broadcast address(es) on the network on the server. 获取服务器上网络上的广播地址。
  2. For a given duration, broadcast a message (soon to be the server IP) 在给定的时间段内,广播一条消息(即将成为服务器IP)
  3. On the client side, wait until a message is received. 在客户端,等待直到收到消息。

I am quite new to networking, so any obvious errors may not be immediately obvious to me. 我对联网很陌生,因此任何明显的错误可能对我来说都不是立即显而易见的。

Server broadcast code: 服务器广播代码:

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.");
        }
    }
}

Client code: 客户代码:

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());
        }
    }
}

The broadcast/netmask address as seen on both devices ifconfig output is netmask 255.255.255.0 broadcast 192.168.0.255 如看到的两个设备广播/掩码地址ifconfig输出是netmask 255.255.255.0 broadcast 192.168.0.255

What confuses me the most is that Wireshark is still seeing the broadcast but when I run the client Java program, it just sits at socket.receive(packet); 最让我感到困惑的是,Wireshark仍在观看广播,但是当我运行客户端Java程序时,它只是位于socket.receive(packet);

Wireshark screenshot on Imgur Imgur上的Wireshark屏幕截图

Both client & server are on port 8027. It is clear that the broadcaster is working, but the client broadcast listener is not. 客户端和服务器都在端口8027上。很明显,广播服务器正在工作,但客户端广播侦听器却没有。 Does anyone have any idea what could be happening? 有谁知道会发生什么? Thanks! 谢谢!

As mentioned in the comments: Check your firewall :-) 如评论中所述:检查防火墙:-)

Another thing i recognized was that if I sniff with wireshark, no other processes could receive that datagrams. 我认识到的另一件事是,如果我嗅着Wireshark,其他进程将无法接收到该数据报。 After realizing that, I wrote a nodejs script, which exclusive=false by default but even that did not help. 在意识到这一点之后,我编写了一个nodejs脚本,默认情况下,exclusive = false仍然没有帮助。 Maybe there is a kernel flag or something, that UDP datagrams cannot be 'consumed' by one process. 也许有一个内核标志之类的东西,UDP数据报不能被一个进程“消耗”。

It looks like your server may be brodcasting on a different address than your client. 看来您的服务器可能在与客户端不同的地址上广播。 Your client is not being assigned an InetAddress, try using this constructor for your socket in BroadcastListener 没有为您的客户端分配InetAddress,请尝试在BroadcastListener为套接字使用此构造函数

DatagramSocket socket = new DatagramSocket(new InetSocketAddress("192.168.0.255", this.port));

If that doesnt work you might try binding both your server and client to 127.0.0.1 如果这样不起作用,您可以尝试将服务器和客户端都绑定到127.0.0.1

You keep creating and destroying DatagramSockets . 您一直在创建和销毁DatagramSockets If the packet arrives at your host at a moment when you don't have a DatagramSocket bound to the port, it will be thrown away. 如果数据包在您没有绑定到端口的DatagramSocket的瞬间到达主机,它将被丢弃。

Create one DatagramSocket and leave it open for this life of this code. 创建一个 DatagramSocket并在此代码的此期间保持打开状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM