JAVA 设置/从多个 (UDP) 中选择特定的 NIC

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12742733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 10:01:57  来源:igfitidea点击:

JAVA set / choose specific NIC from multiple (UDP)

javaudpsetdatagramnic

提问by user1722362

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

我试图在 JAVA 中发送带有数据报的 UDP,我的机器有几个具有不同 IP 的 NIC。

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

如何设置我希望从哪个 NIC 发送数据包?(假设我的机器上有多个??)

EDIT I

编辑我

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

我没有使用 Socket,我使用的是 DatagramSocket 并尝试像这样进行绑定:

/*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..

但是当我这样做时,我无法再连接(或无法获取数据包..)。问题是我有 2 个 NIC,但一个用于内部网络,另一个用于 Internet。

EDIT II

编辑二

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

为了澄清 。这个应用程序是一个服务器 - 并且服务器有 2 个 NICS。一个局域网,一个用于广域网。

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

我的另一种方法是以某种方式指定 ROUTING - 意思是告诉每个数据包确切地使用哪个 NIC ..

How to do such a routing in JAVA ??

如何在JAVA中做这样的路由?

回答by Niles

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

我使用了很多输出来确保代码正常工作并且看起来像这样做,我仍在努力,但我想这足以解决您的问题

回答by Anders R. Bystrup

The Socketclass has a constructor that takes a localAddrargument. That might be applicable for you?

Socket类有一个构造函数,需要一个localAddr说法。那可能适用于你吗?

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

编辑:1)不要在 Java 中进行路由,将其留给操作系统。

2) I trust you have visited All About Datagrams?

2) 我相信您已经访问过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 theDatagramSocketconstructor or it can bind to a specific interface if you choose the DatagramSocket(int port, InetAddress laddr)constructor - this is what you should do!

3)服务器可以绑定到0.0.0.0(即机器上的任何IP),如果您只在DatagramSocket构造函数中指定一个端口就会发生这种情况,或者如果您选择DatagramSocket(int port, InetAddress laddr)构造函数,它可以绑定到特定的接口——这是您应该做的!

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.

4) 客户端然后发送它需要发送的任何内容,服务器可以使用在 3) 中创建的套接字和 packet.getAddress()/packet.getPort() 目的地进行响应。

Cheers,

干杯,

回答by abpan

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."

来自 Tutorial docs Here,“要发送数据,系统会确定使用哪个接口。但是,如果您有偏好或需要指定使用哪个 NIC,您可以查询系统以获取适当的接口并在您要使用的界面。”

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

NetworkInterFaces 可以通过编程方式访问,
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?

迭代每个您可以获得与其关联的 InetAddress 并使用 InetAddress 来构造您的数据报套接字。
这个问题中有很好的信息 -如何从 Java 枚举所有启用的 NIC 卡的 IP 地址?

hope that helps,

希望有帮助,

回答by Mike Schoonover

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.

这是我使用的大部分完整代码。就我而言,我知道我的连接使用的 IP 地址前缀。您可能需要查找接口的名称并将其与存储在配置文件中的值进行比较。

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.

请注意使用 MulticastSocket 而不是 DatagramSocket,因此 setNetworkInterface 方法可用于绑定所需的接口。由于 MulticastSocket 是 DatagramSocket 的子类,切换一般不会引起问题。

@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...