【问题标题】:Binding a Java application to an interface将 Java 应用程序绑定到接口
【发布时间】:2013-06-02 15:44:47
【问题描述】:

我对具有 2 个接口的 GNU/Linux 服务器具有 root 访问权限。我正在使用 Jericho 和 HtmlUnit 来抓取一些网页。我想指定 HTTP 连接应该使用哪个接口。有没有办法在命令行或 Java 中做到这一点?

【问题讨论】:

    标签: java linux ip


    【解决方案1】:

    我想指定 HTTP 连接应该使用哪个接口。

    每个网络接口都有自己唯一的 IP 地址。您可以通过连接到接口 IP 地址上的端口来绑定到接口。

    我无法访问套接字。我给 HtmlUnit 一个 URL。

    无论您使用的是套接字(通过Socket / InetAddress)还是HTTP 连接(通过URL),您都使用相同的方法 - 绑定到 IP 地址 + 端口。

    确定哪个接口有哪个地址

    • 使用 Linux 命令:

       ip a
       ip link show
       /sbin/ifconfig -a
       lshw -class network
      
    • 使用 Java(java.net.NetworkInterface 类):

       import java.io.*;
       import java.net.*;
       import java.util.*;
       import static java.lang.System.out;
      
       public class ListNIFs {
           public static void main(String args[]) throws SocketException {
               Enumeration<NetworkInterface> nets = 
                   NetworkInterface.getNetworkInterfaces();
      
               for (NetworkInterface netIf : Collections.list(nets)) {
                   out.printf("Display name: %s\n", netIf.getDisplayName());
                   out.printf("Name: %s\n", netIf.getName());
                   Enumeration<InetAddress> inetAddresses = netIf.getInetAddresses();
                   for (InetAddress add : Collections.list(inetAddresses)) {
                       out.printf("Address: %s\n", add.getName().getAddress().getHostAddress());
                   }
                   displaySubInterfaces(netIf);
                   out.printf("\n");
               }
           }
      
           static void displaySubInterfaces(NetworkInterface netIf) throws SocketException {
               Enumeration<NetworkInterface> subIfs = netIf.getSubInterfaces();            
               for (NetworkInterface subIf : Collections.list(subIfs)) {
                   out.printf("\tSub Interface Display name: %s\n", subIf.getDisplayName());
                   out.printf("\tSub Interface Name: %s\n", subIf.getName());
                   Enumeration<InetAddress> inetAddresses = subIf.getInetAddresses();
                   for (InetAddress add : Collections.list(inetAddresses)) {
                       out.printf("\t Sub Interface Address: %s\n", add.getName().getAddress().getHostAddress());
                   }
               }
            }
       }  
      

    HTML 单元:指定 IP 地址和端口

    如果您正在调用HTMLUnitWebClient,例如:

    com.gargoylesoftware.htmlunit.WebClient webClient = new WebClient();
    com.gargoylesoftware.htmlunit.html.HtmlPage page = 
        webClient.getPage("http://mycompany.org/mypage");
    

    那么您可以执行以下任何操作:

    com.gargoylesoftware.htmlunit.html.HtmlPage page = 
        webClient.getPage("http://255.255.255.0:80/mypage");
    
    java.net.URL url = new java.net.URL("http://255.255.255.0:80/mypage");
    page = webClient.getPage(url);
    
    com.gargoylesoftware.htmlunit.WebRequest req = 
        new com.gargoylesoftware.htmlunit.WebRequest(url, com.gargoylesoftware.htmlunit.HttpMethod.GET);
    page = webClient.getPage(req);
    

    您也可以使用HTMLUnit HttpWebConnection

    com.gargoylesoftware.htmlunit.HttpWebConnection conn = 
        new com.gargoylesoftware.htmlunit.HttpWebConnection(webClient);
    java.net.URL url = new java.net.URL("http://255.255.255.0/mypage");
    com.gargoylesoftware.htmlunit.WebRequest req = 
        new com.gargoylesoftware.htmlunit.WebRequest(url, com.gargoylesoftware.htmlunit.HttpMethod.POST);
    com.gargoylesoftware.htmlunit.WebRequest resp = conn.getResponse(req);
    

    Core Java:为 HTTP 连接指定 URL 的选项

    创建一个 URL 以连接到资源(文件、网页等)。您可以使用主机字符串(自动 DNS 查找)或 IP 地址指定 URL。您可以选择添加端口:

        // does not encode URL for you (manually include %20, etc)
        java.net.URL url = 
            new URL("http://255.255.255.20:80/docs/books/tutorial/index.html?name=networking#DOWNLOADING");
        java.net.URL url2 = new URL("http", "255.255.255.20", 80, 
                                    "/docs/books/tutorial/index.html?name=networking#DOWNLOADING");
        java.net.URL url3 = new java.net.URL("https://maps.google.com/maps?q=sydney");
        java.net.URL url4 = new java.net.URL("https", "maps.google.com", 80, "/maps?q=sydney");
    
        // does encoding of URL string for you 
        java.net.URI uri5 = new URI("http", "example.com", "/hello world/", "");
        java.net.URL url5 = uri2.toURL();
    
        // Can then pass URL to HTMLUnit, or invoke yourself 
        // (see Java Network Tutorial for details):
    
        java.net.URLConnection conn = url.openConnection();
        java.net.HttpConnection httpConn = (HttpConnection)conn;
        // preconnection: call setAllowUserInteraction/setDoInput/setDoOutput/    
        //                     setIfModifiedSince/setUseCaches/setRequestProperty
        httpConn.connect();  // or getInputStream/getOutputStream/getContent/getHeaderField
        // postconnection: call getContentEncoding/getContentLength/getContentType
        //                      getDate/getExpiration/getLastModifed
    

    Core Java:指定 InetAddress 的选项(用于套接字连接)

    使用 IP 地址

        // 4 bytes:
        byte[] ip4Address = {101,119,11,106};  
        java.net.InetAddress addressObj = java.net.InetAddress.getByAddress(ip4Address); 
    
        // or use ip6Address, 16 bytes (2001:0db8:85a3:0000:0000:8a2e:0370:7334):
        // Any hex value above 0x7f must be cast to byte, because byte is signed (-128 to 127)
        byte[] ip6Address = {0x20,0x01,0x0d,(byte)0xb8,(byte)0x85,(byte)0xa3,0x00,0x00,0x00,0x00,(byte)0x8a,0x2e,0x03,0x70,0x73,0x34}; 
    

    使用 URL 字符串(DNS 查找)

        java.net.InetAddress addressObj = java.net.InetAddress.getByName("www.google.com");
    

    【讨论】:

    • 255.255.255.0 是我的一个接口的本地 IP 还是 mycompany.org 的远程 IP?
    • 这是您想使用套接字调用的接口的 IP 地址。即页面在哪里 - 大概是 mycompany.org
    • 我不清楚。我想从我的一个界面访问外部网页。所以我需要调用的任何方法都应该涉及外部网站和我的接口的 IP。
    • @mossaab 你找到解决方案了吗?
    【解决方案2】:

    在 Java 中,您必须将 Socket 绑定到您要使用的 NIC 的本地 IP 地址。 如果您使用的是 0.0.0.0,它会绑定到 ALL。 指定它只使用你想要的那个。

    【讨论】:

    • 我无法访问套接字。我给 HtmlUnit 一个 URL。
    • HtmlUnit 文档对此有何评论?
    • 没什么。它只是调用 Apache Commons HttpClient。 Jericho 不使用这个库。我不想研究这些库的具体细节。我正在尝试做的是:“嘿,Java,你为什么不为每个 IP 调用使用 IP 地址 A.B.C.D?”
    • 如果它是开源的,为什么不看一下实现(这是这个概念的最大优势)?找到绑定套接字的库类,更改或扩展它并说:“嘿 Lib-Socket-Implementation,使用这个 IP”!抱歉,这是我目前最有建设性的建议,因为我不熟悉您的任何库...
    • 请忽略这里涉及的库,请注意我的问题是关于 Java 和/或 Linux,而不是关于特定库。我不是手动创建套接字。我想实例化 HttpURLConnection conn = (HttpURLConnection) myURL.openConnection(),并确保它通过特定的接口。
    【解决方案3】:

    有两种制作方法。

    1. 在 Java 中,关键是在调用 HTTPConnection#open() 方法之前指定要使用的源地址:

      InetAddress favourateAddr = InetAddress(byte[] {1,2,3,4}); // 1.2.3.4是你要使用的网卡的ip地址

      yourHTTPConnObj.setLocalAddress(favourateAddr);

      //然后打开http连接 你的HTTPConnObj.open();

    2. 在 Linux 中,由第 3 层实用程序决定谁将选择 NIC 的路由。所以你需要使用目标地址来自定义路由表来强制你的连接从哪个网卡开始。这很简单,只需一个路由命令。见this link

    【讨论】:

    • 我试过sudo /sbin/route add -host 8.8.8.8 dev eth1。但是当我在 8.8.8.8 上 ping 时,我得到了Destination Host Unreachable
    猜你喜欢
    • 2011-01-28
    • 2016-02-02
    • 2015-11-22
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    相关资源
    最近更新 更多