socket datagramsocket java networking udp multicast

datagramsocket - Java: multidifusión UDP solo funciona en el host local



multicast udp java (1)

Recientemente implementé multicast en mi juego multijugador para localizar juegos que se ejecutan en la red del jugador. Creé dos clases, Heart y Listener . El problema que estoy teniendo es que el oyente solo escucha el latido del corazón a través del localhost , no si estoy ejecutando una parte en otra computadora.

Corazón:

package net.jibini.networking.udp; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import net.jibini.networking.packets.Packet; public class Heart implements Runnable { private String groupName = "229.5.38.17"; private int port = 4567; MulticastSocket multicastSocket; DatagramPacket datagramPacket; public boolean beating = true; public Packet toSend; public Heart(int connectionListenerPort, Packet toSend) { try { this.toSend = toSend; multicastSocket = new MulticastSocket(); multicastSocket.setReuseAddress(true); InetAddress group = InetAddress.getByName(groupName); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(toSend); objectOutputStream.flush(); objectOutputStream.close(); byte[] buf = byteArrayOutputStream.toByteArray(); datagramPacket = new DatagramPacket(buf, buf.length, group, port); new Thread(this).start(); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while (beating) { beat(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } private void beat() { try { multicastSocket.send(datagramPacket); } catch (IOException e) { e.printStackTrace(); } } }

Oyente:

package net.jibini.networking.udp; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import net.jibini.networking.packets.Packet; public class Listener implements Runnable { private boolean run = true; private String groupName = "229.5.38.17"; MulticastSocket multicastSocket; public OnFound onFound; public Listener(OnFound onFound) { try { multicastSocket = new MulticastSocket(4567); multicastSocket.setReuseAddress(true); multicastSocket.joinGroup(InetAddress.getByName(groupName)); this.onFound = onFound; new Thread(this).start(); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while (run) { DatagramPacket datagramPacket = new DatagramPacket(new byte[1500], 1500); try { multicastSocket.receive(datagramPacket); Packet beat = getBeat(datagramPacket); if (beat != null) { onFound.onFound(datagramPacket.getAddress(), beat); } } catch (IOException e) { e.printStackTrace(); } } } public void stop() { run = false; } /*private boolean isLocalhost(String hostAddress) { boolean isLocalhost = false; Enumeration<NetworkInterface> networkInterfaces; try { networkInterfaces = NetworkInterface.getNetworkInterfaces(); if (networkInterfaces != null) { OUTER: while (networkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = networkInterfaces.nextElement(); Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses(); if (inetAddresses != null) { while (inetAddresses.hasMoreElements()) { InetAddress inetAddress = inetAddresses.nextElement(); if (hostAddress.equals(inetAddress.getHostAddress())) { isLocalhost = true; break OUTER; } } } } } } catch (SocketException e) { e.printStackTrace(); } return isLocalhost; }*/ private Packet getBeat(DatagramPacket datagramPacket) { Packet beat = null; byte[] data = datagramPacket.getData(); if (data != null) { try { ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data)); beat = (Packet) objectInputStream.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return beat; } public static class OnFound { public void onFound(InetAddress inet, Packet beat) {} } }

¿Cómo puedo hacerlo para que el oyente escuche el ritmo incluso desde otra computadora?

EDITAR: busca la dirección IPv4 local.

public static InetAddress localAddress() { String ip; try { Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface iface = interfaces.nextElement(); if (iface.isLoopback() || !iface.isUp()) continue; Enumeration<InetAddress> addresses = iface.getInetAddresses(); while(addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); ip = addr.getHostAddress(); if (ip.startsWith("10.") || ip.startsWith("172.31.") || ip.startsWith("192.168")) return addr; } } } catch (SocketException e) { throw new RuntimeException(e); } return null; }


Debe asegurarse de que su oyente se haya unido al grupo de multidifusión en la (s) interfaz (es) correcta (s), y que su remitente esté enviando en la interfaz adecuada.

En ambos casos, puede hacerlo a través de los métodos setInterface o setNetworkInterface .

Supongamos que su remitente tiene direcciones IP 192.168.1.1 y 192.168.2.1, y su receptor tiene direcciones 192.168.1.2 y 192.168.2.2. Si desea que su remitente envíe desde 192.168.1.1, debe llamar a:

multicastSocket.setInterface(InetAddress.getByName("192.168.1.1"));

Su receptor necesitaría recibir en 192.168.1.2:

multicastSocket.setInterface(InetAddress.getByName("192.168.1.2")); multicastSocket.joinGroup(InetAddress.getByName(groupName));

Si desea que su receptor reciba en múltiples interfaces, llame a joinGroup varias veces, primero llamando a setInterface :

multicastSocket.setInterface(InetAddress.getByName("192.168.1.2")); multicastSocket.joinGroup(InetAddress.getByName(groupName)); multicastSocket.setInterface(InetAddress.getByName("192.168.2.2")); multicastSocket.joinGroup(InetAddress.getByName(groupName));

Editar:

Si no conoce su dirección IP local, puede usar InetAddress.getLocalHost() para obtener la IP asociada con el nombre de host de la computadora. Si tiene más de una dirección IP en su sistema, puede llamar a NetworkInterface.getNetworkInterfaces() para obtener una lista de interfaces de red, luego llame a getInetAddresses() en cada una de ellas para obtener las direcciones IP:

for (NetworkInterface intf: NetworkInterface.getNetworkInterfaces()) { for (InetAddress addr: intf.getInetAddresses()) { System.out.println("interface " + intf + ": address " + addr); } }

Editar 2:

Para enviar en múltiples interfaces: En Heart.beat() :

Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface iface = interfaces.nextElement(); if (iface.isLoopback() || !iface.isUp()) continue; Enumeration<InetAddress> addresses = iface.getInetAddresses(); while(addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); multicastSocket.setInterface(addr); multicastSocket.send(datagramPacket); } }

Para recibir en múltiples interfaces: en el constructor para Listener :

Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface iface = interfaces.nextElement(); if (iface.isLoopback() || !iface.isUp()) continue; Enumeration<InetAddress> addresses = iface.getInetAddresses(); while(addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); multicastSocket.setInterface(addr); multicastSocket.joinGroup(InetAddress.getByName(groupName)); } }