9 votes

JAVA définit / choisit un NIC spécifique parmi plusieurs (UDP)

J'essaie d'envoyer un datagramme UDP en JAVA et ma machine a plusieurs NIC avec des IP différentes.

Comment puis-je définir la carte réseau à partir de laquelle je veux que mon paquet soit envoyé (en supposant que j'en ai plusieurs sur la machine) ?

EDIT I

Je n'utilise pas Socket, mais DatagramSocket et j'ai essayé de faire la liaison comme suit :

/*binding */
        DatagramSocket ds = new DatagramSocket(1111);
        NetworkInterface nif = NetworkInterface.getByIndex(nicIndex);
        Enumeration<InetAddress> nifAddresses = nif.getInetAddresses();
        ds.bind(new InetSocketAddress(nifAddresses.nextElement(), 0));

Mais lorsque je fais cela, je ne peux plus me connecter ou je ne peux pas obtenir le paquet ). Le problème est que j'ai 2 NIC, mais l'une est pour le réseau INTERNE et l'autre pour Internet . J'ai besoin que toutes les données de mon serveur aillent uniquement sur le réseau INTERNE

EDIT II

Pour plus de clarté . Cette application est un serveur - et le SERVEUR a 2 NICS . un LAN et un WAN.

Une autre solution serait de spécifier un routage d'une manière ou d'une autre, c'est-à-dire d'indiquer à chaque paquet quelle carte réseau utiliser

Comment faire un tel routage en JAVA ?

4voto

Niles Points 441

Je viens d'avoir le même problème que vous. Il n'a pas été immédiat de résoudre le problème mais finalement j'ai écrit un code qui peut être utile pour vous :

//set Network Interface
        NetworkInterface nif = NetworkInterface.getByName("tun0");
        if(nif==null){
            System.err.println("Error getting the Network Interface");
            return;
        }
        System.out.println("Preparing to using the interface: "+nif.getName());
        Enumeration<InetAddress> nifAddresses = nif.getInetAddresses();
        InetSocketAddress inetAddr= new InetSocketAddress(nifAddresses.nextElement(),0);

        //socket.bind(new InetSocketAddress(nifAddresses.nextElement(), 0));
        DatagramSocket socket = new DatagramSocket(inetAddr);
        System.out.println("Interface setted");

J'ai utilisé beaucoup de sorties pour être sûr que le code fonctionne correctement et il semble le faire, je travaille encore dessus mais je suppose que cela peut être suffisant pour votre problème.

2voto

Anders R. Bystrup Points 7500

El Socket a un Constructeur qui prend un localAddr argument. Cela pourrait s'appliquer à vous ?

Edit : 1) Ne faites pas de routage en Java, laissez cela au système d'exploitation.

2) J'espère que vous avez visité Tout sur les datagrammes ?

3) Le serveur peut se lier à 0.0.0.0 (c'est-à-dire n'importe quelle IP de la machine), ce qui est le cas si vous ne spécifiez qu'un port dans le champ DatagramSocket ou il peut se lier à une interface spécifique si vous choisissez l'option DatagramSocket(int port, InetAddress laddr) Constructeur - c'est ce que vous devez faire !

4) Le client envoie alors ce qu'il a besoin d'envoyer et le serveur peut répondre, en utilisant la socket créée en 3) et la destination packet.getAddress()/packet.getPort().

A la vôtre,

2voto

Mike Schoonover Points 71

Voici le code le plus complet que j'ai utilisé. Dans mon cas, je connais le préfixe de l'adresse IP utilisée par ma connexion. Vous devrez peut-être chercher le nom de l'interface et le comparer avec une valeur que vous stockez dans un fichier de configuration.

Notez l'utilisation de MulticastSocket au lieu de DatagramSocket afin que la méthode setNetworkInterface soit disponible pour lier l'interface souhaitée. Comme MulticastSocket est une classe enfant de DatagramSocket, le changement ne pose généralement aucun problème.

@Override
public void connect() throws InterruptedException
{

    NetworkInterface iFace;

    iFace = findNetworkInterface();

    connectControlBoard(iFace);

    connectUTBoards(iFace);

}//end of Capulin1::connect
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Capulin1:findNetworkInterface
//
// Finds the network interface for communication with the remotes. Returns
// null if no suitable interface found.
//
// The first interface which is connected and has an IP address beginning with
// 169.254.*.* is returned.
//
// NOTE: If more than one interface is connected and has a 169.254.*.*
// IP address, the first one in the list will be returned. Will need to add
// code to further differentiate the interfaces if such a set up is to be
// used. Internet connections will typically not have such an IP address, so
// a second interface connected to the Internet will not cause a problem with
// the existing code.
//
// If a network interface is not specified for the connection, Java will
// choose the first one it finds. The TCP/IP protocol seems to work even if
// the wrong interface is chosen. However, the UDP broadcasts for wake up calls
// will not work unless the socket is bound to the appropriate interface.
//
// If multiple interface adapters are present, enabled, and running (such as
// an Internet connection), it can cause the UDP broadcasts to fail.
//

public NetworkInterface findNetworkInterface()
{

    logger.logMessage("");

    NetworkInterface iFace = null;

    try{
        logger.logMessage("Full list of Network Interfaces:" + "\n");
        for (Enumeration<NetworkInterface> en =
              NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {

            NetworkInterface intf = en.nextElement();
            logger.logMessage("    " + intf.getName() + " " +
                                                intf.getDisplayName() + "\n");

            for (Enumeration<InetAddress> enumIpAddr =
                     intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {

                String ipAddr = enumIpAddr.nextElement().toString();

                logger.logMessage("        " + ipAddr + "\n");

                if(ipAddr.startsWith("/169.254")){
                    iFace = intf;
                    logger.logMessage("==>> Binding to this adapter...\n");
                }
            }
        }
    }
    catch (SocketException e) {
        logger.logMessage(" (error retrieving network interface list)" + "\n");
    }

    return(iFace);

}//end of Capulin1::findNetworkInterface
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Capulin1::connectControlBoards
//

public void connectControlBoard(NetworkInterface pNetworkInterface)
                                                    throws InterruptedException
{

    logger.logMessage("Broadcasting greeting to all Control boards...\n");

    MulticastSocket socket;

    try{
        socket = new MulticastSocket(4445);
        if (pNetworkInterface != null) {
            try{
                socket.setNetworkInterface(pNetworkInterface);
            }catch (IOException e) {}//let system bind to default interface
        }

    }
    catch (IOException e) {
        logSevere(e.getMessage() + " - Error: 204");
        logger.logMessage("Couldn't create Control broadcast socket.\n");
        return;
    }

...use the socket here...

1voto

abpan Points 111

Extrait de la documentation du Tutoriel Ici , " Pour envoyer les données, le système détermine quelle interface est utilisée. Toutefois, si vous avez une préférence ou si vous devez spécifier quelle NIC utiliser, vous pouvez interroger le système pour connaître les interfaces appropriées et trouver une adresse sur l'interface que vous voulez utiliser."

Les NetworkInterFaces peuvent être accédées de manière programmatique comme,
Enumeration en = NetworkInterface.getNetworkInterfaces() ;

En itérant chacun d'eux, vous pouvez obtenir l'adresse InetAddress qui lui est associée et l'utiliser pour construire votre socket de datagramme.
Il y a de bonnes informations dans cette question - Comment énumérer les adresses IP de toutes les cartes NIC activées à partir de Java ?

J'espère que cela vous aidera,

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X