简体   繁体   中英

UDP Broadcast and Receive

I have a Java class intended to facilitate connections between computers without the need for explicitly defining peer addresses.

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.MulticastSocket;
import java.net.SocketException;

public class Broadcasts {

    private final Runnable receiver;
    private final Runnable sender;
    private boolean run = true;

    public Broadcasts(TheThing parent) {
        receiver = new Runnable() {
            public void run() {
                byte data[] = new byte[0];
                DatagramPacket packet = new DatagramPacket(data, data.length);
                try {
                    DatagramSocket socket = new DatagramSocket();
                    while (run) {
                        socket.receive(packet);
                        parent.newAddress(packet.getAddress());
                    }
                } catch (SocketException ex) {
                    ex.printStackTrace();
                    parent.quit();
                } catch (IOException ex) {
                    ex.printStackTrace();
                    parent.quit();
                }
            }
        };
        sender = new Runnable() {
            public void run() {
                byte data[] = new byte[0];
                DatagramPacket packet = new DatagramPacket(data, data.length);
                try {
                    MulticastSocket socket = new MulticastSocket();
                    socket.setBroadcast(true);
                    socket.joinGroup(Globals.publicAddress);
                    while (run) {
                        socket.send(packet);
                        Thread.sleep(Globals.UDPINTERVAL);
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                    parent.quit();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                    parent.quit();
                }
            }
        };
        new Thread(receiver).start();
        new Thread(sender).start();
    }

    public void quit() {
        run = false;
    }
}

I get the following error:

java.net.SocketException: Not a multicast address
    at java.net.MulticastSocket.joinGroup(MulticastSocket.java:310)
    at the.thing.Broadcasts$2.run(Broadcasts.java:42)
    at java.lang.Thread.run(Thread.java:745)

The problem I am facing is the address defined as Globals.publicAddress is a multicast address. What am I missing here?

Globals.publicAddress is obtained with the following method. It should be the DHCP assigned address:

private static InetAddress getPublicIface() {
    InetAddress result = null;
    Enumeration e;
    try {
        e = NetworkInterface.getNetworkInterfaces();
    } catch (SocketException ex) {
        return null;
    }
    while (e.hasMoreElements() && result == null) {
        NetworkInterface n = (NetworkInterface) e.nextElement();
        Enumeration ee = n.getInetAddresses();
        while (ee.hasMoreElements()) {
            InetAddress i = (InetAddress) ee.nextElement();;
            if (i.getHostAddress().startsWith("192.168.")) {
                result = i;
                break;
            }
        }
    }
return result;

I have also tried the following method to obtain a valid broadcasting address:

private static InetAddress getPublicIface() {
    InetAddress result = null;
    Enumeration e;
    try {
        e = NetworkInterface.getNetworkInterfaces();
    } catch (SocketException ex) {
        return null;
    }
    while(e.hasMoreElements() && result == null) {
        NetworkInterface iface = (NetworkInterface) e.nextElement();
        try {
            if(iface == null || iface.isLoopback() || !iface.isUp() ||
                    iface.isVirtual() || !iface.supportsMulticast())
                continue;
        } catch (SocketException ex) {
            continue;
        }
        Iterator it = iface.getInterfaceAddresses().iterator();
        while (it.hasNext()) {
            InterfaceAddress address = (InterfaceAddress) it.next();
            if(address == null || address.getBroadcast() == null)
                continue;
            result = address.getBroadcast();
            break;
        }
    }
    return result;
}

I didn't know about NetworkInterface , so that was a cool new thing for me. So I grepped around and put together some code that seems to work. It needs clean-up, but it runs on my system and seems to actually broadcast.

Salient points:

  1. You don't need to listen on the broadcast address. Since it's broadcast, you'll get it no matter what IP address you listen on.

  2. You do have to send to the broadcast address, and for some reason this seems to work only as a parameter of DatagramPacket , never DatagramSocket . I dunno why, but that's how the API seems to want it.

Good luck.

public class BroadcastTest
{
   private static final int RANDOM_PORT = 4444;

   public static void main( String[] args )
           throws Exception
   {
      InetAddress addr = getBroadcastAddrs().get(0);
      System.err.println( addr );
      new Thread( new BroadcastServer( RANDOM_PORT ) ).start();
      DatagramSocket dsock = new DatagramSocket();
      byte[] send = "Hello World".getBytes( "UTF-8" );
      DatagramPacket data = new DatagramPacket( send, send.length, addr, RANDOM_PORT );
      dsock.send( data );
   }

   public static List<InetAddress> getBroadcastAddrs() throws SocketException {
      Set<InetAddress> set = new LinkedHashSet<>();
      Enumeration<NetworkInterface> nicList = NetworkInterface.
              getNetworkInterfaces();
      for( ; nicList.hasMoreElements(); ) {
         NetworkInterface nic = nicList.nextElement();
         if( nic.isUp() && !nic.isLoopback() )  {
            for( InterfaceAddress ia : nic.getInterfaceAddresses() )
               set.add( ia.getBroadcast() );
         }
      }
      return Arrays.asList( set.toArray( new InetAddress[0] ) );

   }
}

class BroadcastServer implements Runnable {
   private final int port;

   public BroadcastServer( int port )
   {
      this.port = port;
   }

   @Override
   public void run()
   {
      try {
         DatagramSocket dsock = new DatagramSocket( port );
         DatagramPacket data = new DatagramPacket( new byte[2048], 2048 );
         dsock.receive( data );
         System.out.println( new String( data.getData(), "UTF-8" ) );
      } catch( SocketException ex ) {
         Logger.getLogger( BroadcastServer.class.getName() ).
                 log( Level.SEVERE, null, ex );
      } catch( IOException ex ) {
         Logger.getLogger( BroadcastServer.class.getName() ).
                 log( Level.SEVERE, null, ex );
      }
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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