JAVA网络编程二(InetAddress类、NetworkInterface类)

Internet地址

InetAddress类

InetAddress类是对JavaIP地址的高层表示。大多数其他网络都用到这个类,包括Socket,ServerSocket,URL,DatagramSocket,DatagraPacket

获取域名的IP地址:

InetAddress address = InetAddress.getByName("www.baidu.com");
system.out.println(address);

该方法会与DNS服务器建立一个连接,来查找地址(如果之前查找过,可能会在本地缓存)。参数也可以是其 IP 地址的文本表示形式。如果提供字面值 IP 地址,则仅检查地址格式的有效性。

获取主机名

address.getHostName();

获取主机的所有地址

InetAddress[] addresses = InetAddress.getAllByName("www.oreilly.com");

查找本机地址

InetAddress me = InetAddress.getLocalHost();

如果查找DNS失败,会返回127.0.0.1的IP地址

通过IP地址或主机名创建InetAddress对象

byte[] address = {(byte)192, (byte)168, (byte) 253, 1};
InetAddress IA = InetAddress.getByAddress(address);
InetAddress IA2 = InetAddress.getByAddress("DESKTOP-D1COEVD", address);
System.out.println(IA + "-----" + IA2);

这两个方法不能保证主机一定存在,如果不存在,将会抛出异常

缓存
DNS的查询开销很大,所以InetAddress会缓存查找的结果。一旦得到一个给定的主机的地址,就不会再次查找,即使你为同一个主机创建一个新的InetAddress对象,也不会再次查找地址。但Java对于不成功的DNS查询只缓存10秒。
这些时间可以用系统属性networkaddress.cache.ttl和networkaddress.cache.negative.ttl来控制。第一个属性制定了成功DNS查找结果在java缓存中保留的时间,第二个是不成功的缓存保留时间。

按IP地址查找
可以用getByName()和一个IP地址作为参数来创建一个InetAddress对象,而不检查DNS。这个对象可能是实际上无法连接的主机。由于IP地址没有主机名稳定,大多是采用主机名获取InetAddress对象

安全性问题
从主机名创建一个新的InetAddress对象被认为是潜在的不安全的操作,因为这需要一个DNS查找,因为DNS查找可能会泄漏信息。

获取方法
InetAddress包含4个获取方法,可以将主机名作为字符串返回,将IP地址返回为字符串和字符数组:

public String getHostName();//在不知道主机名的时候进行DNS查询,返回主机名和IP地址
public String getCanonicalHostName();//即使在知道主机名的情况下仍然查询,返回主机名,常用来在一直IP地址的时候查询主机名
public byte[] getAddress();//返回IP地址,可以用来测试时IPV4还是IPV6地址
public String getHostAddress();//返回IP地址

地址类型
java提供了10个测试ip地址类型的方法,像回送地址,通配地址等

连接可达性
InetAddress类有两个isReachable()方法,可以测试一个特定节点对当前主机是否可达(能否建立一个连接),不可达的原因可能有防火墙、 阻塞等

public boolean isReachable(int timeout) throw IOException
public boolean isReachable(NetworkInterface interface, int ttl, int timeout);//指定从哪个本地网络接口建立连接

Object的方法
InetAddress的equals比较的是IP地址,而不是主机名


Inet4Address和Inet6Address

这两个类分别是IPV4和IPV6地址。Inet6Address多了一个isIPv4CompatibleAddress()方法,表示这个IPV6地址是不是IPV4地址填充的


NetworkInterface类

NetworkInterface类表示一个本地IP地址。这可以是一个物理接口,如额外的以太网卡(常见于防火墙和路由器),也可以是一个虚拟接口,与机器的其他IP地址绑定到同一个物理硬件。NetworkInterface类提供了一些方法可以枚举所有本地地址(而不考虑接口),并由他们创建InetAddress对象,然后这些InetAddress对象可用于创建socket、服务器socket等

工厂方法
由于该对象表示物理硬件和虚拟地址,所以不能任意构造。需要通过工厂方法

public static NetworkInterface getByName(String name) throws SocketException

name表示指定名字的网络接口,如果没有这样的接口就返回null。名字的格式与平台有关,unix,以太网接口的形式为eth0,eth1等

public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException

返回与指定IP绑定的接口

public static Enumeration getNetworkInterfaces() throws SocketException

返回所有的网络接口

获取方法

public Enumeration getInetAddresses();

一个网络接口可以绑定多个IP地址。对于这个接口绑定的每一个IP地址都包含一个InetAddress。

public String getName()

返回名字

public String getDisplayName();

获得更加友好的名字

相关程序

查询主机是否是垃圾发送者
通过服务器的黑洞列表查询

public class SpamCheck {
    public static final String BLACKHOLE = "sbl.spamhaus.rog";

    public static void main(String[] args) {
        for (String arg : args) {
            if (isSpammer(arg)) {
                System.out.println(arg + "is a know spammer.");
            } else {
                System.out.println(arg + "appears letitimate");
            }
        }
    }

    private static boolean isSpammer(String arg) {
        try {
            InetAddress address = InetAddress.getByName(arg);
            byte[] quad = address.getAddress();
            String query = BLACKHOLE;
            //转换成无符号型
            //查询时通过IP地址+BLACKHOLE的形式
            for (byte octet : quad) {
                int unsignedByte = octet < 0 ? octet + 256 : octet;
                query = unsignedByte +"." +query
            }
            //查询失败将会抛出异常
            InetAddress.getByName(query);
            return true;
        } catch (UnknownHostException e) {
            return false;
        }
    }
}

处理WEB服务器的日志文件
WEB服务器可以记录访问主机的IP地址或者名字,如果是名字需要进行一次DNS请求。这种查询可以用这些类完成(采用多线程)
查询类:

public class LookupTask implements Callable<String>{
    private String line;

    public LookupTask(String line) {
        this.line = line;
    }

    @Override
    public String call() throws Exception {
        int index = line.indexOf(" ");
        String address = line.substring(0, index);
        String theRest = line.substring(index);
        String hostname = InetAddress.getByName(address).getHostName();
        return hostname + " " + theRest;
    }
}

主程序:

public class PooledWeblog {
    private final static int NUM_THREADS =4;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
        Queue<LogEntry> results = new LinkedList<>();
        try (BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(new FileInputStream(args[0]), "UTF-8"));) {
            for (String entry =bufferedReader.readLine();entry!=null; entry = bufferedReader.readLine()) {
                LookupTask task = new LookupTask(entry);
                Future<String> future = executorService.submit(task);
                LogEntry result = new LogEntry(entry, future);
                results.add(result);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static class LogEntry {
        String orginal;
        Future<String> future;

        public LogEntry(String orginal, Future<String> future) {
            this.orginal = orginal;
            this.future = future;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值