JAVA set / choose specific NIC from multiple (UDP)
Asked Answered
M

4

9

I am trying to send UDP with datagram in JAVA and my machine have several NIC with different IP's.

How can I set which NIC I want my packet to be sent from ?? (assuming I have more than one on the machine ??)

EDIT I

I am not using Socket, I am using DatagramSocket and tried to do binding like so:

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

But when I do so, I can not connect anymore (or can not get the packet ..). The problem is that I have 2 NIC, but one is for INTERNAL network and the other one is for Internet .. I need all my server data to go only on the INTERNAL one..

EDIT II

For Clarification . This App is a server - and the SERVER has 2 NICS . one LAN and one for WAN.

An alternative way for me would to specify a ROUTING somehow - meaning to tell each packet exactly which NIC to use ..

How to do such a routing in JAVA ??

Monacid answered 5/10, 2012 at 8:50 Comment(0)
B
4

I just had the same problem of you. It was not immediate to solve the problem but finally I wrote some code that can be useful for you:

//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");

I used a lot of output to be sure that the code is working properly and it look like to do it, I am still working on it but I suppose this can be enough for your problem

Brentbrenton answered 30/1, 2015 at 8:52 Comment(1)
Maybe this is not the most accurate solution, but indeed helped a lot.Instinctive
V
2

The Socket class has a constructor that takes a localAddr argument. That might be applicable for you?

Edit: 1) Don't do routing in Java, leave that to the OS.

2) I trust you have visited All About Datagrams?

3) The server can bind to 0.0.0.0 (i.e. any IP on the machine) which is what happens if you only specify a port in theDatagramSocket constructor or it can bind to a specific interface if you choose the DatagramSocket(int port, InetAddress laddr) constructor - this is what you should do!

4) The client then sends whatever it needs to send and the server can respond, using the socket created in 3) and the packet.getAddress()/packet.getPort() destination.

Cheers,

Videogenic answered 5/10, 2012 at 9:4 Comment(6)
Verdammt - apologies for missing that. I'm a bit curious as to why you want to solve this in code rather than rely on IP routing? If you send your UDP packet to a given IP and that server is on the internal network, the IP stack should route that package correctly via the relevant NIC interface automagically. Or am I missing yet more?Videogenic
Also, are you sure that the first element in the enumeration is always your preferred NIC - what if it's the loopback interface or some exotic 6to4 tunnel interface?Videogenic
Thanks again for your help - My question is how to target the right NIC for SENDING and RECIEVING from MY OWN machine . I am the server. and I can GET the packets from all the clients .. but when SENDING, the Clients (sometimes) not receiving - I assume that is because SOME packets (probably) go to the wrong NIC on MY machine.Monacid
And yes, I know this is the right interface because I get it by Index (in an earlier function) . (read also EDIT II)Monacid
In your code sample: First you bind to port 1111 and then you (re)bind to port 0: new InetSocketAddress(nifAddresses.nextElement(), __0__ ) - could that be your problem?Videogenic
well .. I am sorry, this (1111) thing was only to demonstrate here as exampl (xxxx) . In the real code the ports are the same ..Idzik
S
2

Here is mostly complete code I used. In my case, I know the IP address prefix used by my connection. You may need to look for the interface's name and compare it with a value you store in a configuration file.

Note the use of MulticastSocket instead of DatagramSocket so the setNetworkInterface method is available to bind the desired interface. Since MulticastSocket is a child class of DatagramSocket, the switch generally causes no problems.

@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...
Snazzy answered 7/11, 2013 at 0:57 Comment(0)
C
1

From Tutorial docs Here, "To send the data, the system determines which interface is used. However, if you have a preference or otherwise need to specify which NIC to use, you can query the system for the appropriate interfaces and find an address on the interface you want to use."

The NetworkInterFaces can be accessed programmatically as,
Enumeration en = NetworkInterface.getNetworkInterfaces();

Iterating each you can get InetAddress associated with it and use the InetAddress to construct you datagram socket.
There is good info in this question - How to enumerate IP addresses of all enabled NIC cards from Java?

hope that helps,

Confessional answered 5/10, 2012 at 13:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.