2015-05-23 2 views
0

У меня есть класс Java, предназначенный для облегчения соединений между компьютерами без необходимости явного определения одноранговых адресов.UDP Broadcast and Receive

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

Я получаю следующее сообщение об ошибке:

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) 

Проблема я столкнулся это адрес определяется как Globals.publicAddressявляется адреса многоадресной рассылки. Что мне здесь не хватает?

Globals.publicAddress получен следующим образом. Он должен быть DHCP назначен адрес:

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; 

Я также попробовал следующий метод, чтобы получить действительный адрес вещания:

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; 
} 
+0

Какой адрес? –

+0

@MartinKonecny ​​Адрес - это адрес, который используется в моей локальной сети. – motoku

+0

Если адрес используется, его нельзя использовать для трансляции. Широковещание обычно указывается IP-адресом FF.FF.FF.FF. Какой адрес вы используете, пожалуйста? Это имеет значение. – markspace

ответ

1

я не знал о NetworkInterface, так что было классная новая вещь для меня. Поэтому я собрался и собрал код, который, похоже, работает. Он нуждается в очистке, но он работает в моей системе и, по-видимому, транслируется.

Заметные точки:

  1. Вам не нужно слушать на широковещательный адрес. Поскольку он транслируется, вы получите его независимо от того, какой IP-адрес вы слушаете.

  2. Вам нужно отправить широковещательный адрес, и по какой-то причине это работает только как параметр DatagramPacket, никогда DatagramSocket. Я не знаю почему, но вот как API, похоже, хочет этого.

Удачи.

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); 
     } 
    } 
} 
+0

Нет API-интерфейса DatagramSocket, который отправляет на IP-адрес. Только тот, который отправляет пакет. Вы должны поместить целевой адрес в DatagramPacket. Вот как это работает. – EJP

+0

@EJP Итак, почему у DatagramSocket есть два ctor, которые принимают IP-адреса, а также методы bind() и connect(), которые также принимают IP-адреса? Это довольно запутанно. – markspace

+0

@markspace Я использую модифицированную версию вашего примера [в этом репозитории GitHub.] (Https://github.com/sbpc/LANChat/tree/master/src/lanchat); если вы хотите проверить, что я придумал w/ – motoku