IPv6基本编程——Java

IPv6编程——Java

1. Java支持IPv6

Java 从 1.4 版开始支持 Linux 和Solaris 平台上的 IPv6。1.5 版起又加入了 Windows 平台上的支持。
在 IPv6 的环境下开发 Java 应用,或者移植已有的 IPv4 环境下开发的Java 应用到 IPv6 环境中来,对于 IPv6 网络地址的验证是必须的步骤,尤其是对那些提供了 UI(用户接口)的 Java 应用。

2. 获取本机IPv6地址

有时为了能够注册 listener,开发人员需要使用本机的 IPv6 地址,这一地址不能简单得通过 InetAddress.getLocalhost() 获得。因为这样有可能获得诸如 0:0:0:0:0:0:0:1 这样的特殊地址。使用这样的地址,其他服务器将无法把通知发送到本机上,因此必须先进行过滤,选出确实可用的地址。以下代码实现了这一功能,思路是遍历网络接口的各个地址,直至找到符合要求的地址。

package com.text;

import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class Get_IPv6 {

    public static void main(String[] args) throws IOException{
        String str = getLocalIPv6Address();
        System.out.println(str);
    }

    public static String getLocalIPv6Address() throws IOException {
        InetAddress inetAddress = null;
        Enumeration<NetworkInterface> networkInterfaces =
        NetworkInterface
        .getNetworkInterfaces();
        outer:
        while (networkInterfaces.hasMoreElements()) {
            Enumeration<InetAddress> inetAds =
            networkInterfaces.nextElement()
            .getInetAddresses();
            while (inetAds.hasMoreElements()) {
                inetAddress = inetAds.nextElement();
        //Check if it‘s ipv6 address and reserved address
                if (inetAddress instanceof Inet6Address
                    && !isReservedAddr(inetAddress)) {
                    break outer;
            }
        }
    }
    String ipAddr = inetAddress.getHostAddress();
    // Filter network card No
    int index = ipAddr.indexOf(‘%‘);
    if (index > 0) {
        ipAddr = ipAddr.substring(0, index);
    }
    return ipAddr;
    }

    private static boolean isReservedAddr(InetAddress inetAddr) {
        if (inetAddr.isAnyLocalAddress() || inetAddr.isLinkLocalAddress()
            || inetAddr.isLoopbackAddress()) {
            return true;
    }
    return false;
    }
}

为了支持 IPv6,Java 中增加了两个 InetAddress 的子类:Inet4Address和 Inet6Address。一般情况下这两个子类并不会被使用到,但是当我们需要分别处理不同的 IP 协议时就非常有用,在这我们根据Inet6Address来筛选地址。
isReservedAddr() 方法过滤了本机特殊 IP 地址,包括“LocalAddress”,“LinkLocalAddress”和“LoopbackAddress”。另一个需要注意的地方是:在 windows 平台上,取得的 IPv6 地址后面可能跟了一个百分号加数字。这里的数字是本机网络适配器的编号。这个后缀并不是 IPv6 标准地址的一部分,可以去除。

3. IPv4/IPv6 双环境下,网络的选择和测试

Java 提供了 InetAddress 的两个扩展类以供使用:Inet4Address 和 Inet6Address,其中封装了对于 IPv4 和 IPv6 的特殊属性和行为。然而由于Java 的多态特性,使得程序员一般只需要使用父类 InetAddress,Java 虚拟机可以根据所封装的 IP 地址类型的不同,在运行时选择正确的行为逻辑。所以在多数情况下,程序员并不需要精确控制所使用的类型及其行为,一切交给 Java虚拟机即可。具体的新增类型及其新增方法,请具体参阅 Sun 公司的 JavaDoc。
在 IPv4/IPv6 双环境中,对于使用 Java 开发的网络应用,比较值得注意的是以下两个 IPv6 相关的 Java 虚拟机系统属性。
java.net.preferIPv4Stack=<\true|false>
java.net.preferIPv6Addresses=<\true|false>
程序中设置代码如下:
System.setProperty("java.net.preferIPv6Addresses","true");
preferIPv4Stack(默认 false)表示如果存在 IPv4 和 IPv6 双栈,Java 程序是否优先使用 IPv4 套接字。默认值是优先使用 IPv6 套接字,因为 IPv6 套接字可以与对应的 IPv4 或 IPv6 主机进行对话;相反如果优先使用 IPv4,则只不能与 IPv6 主机进行通信。
preferIPv6Addresses(默认 false)表示在查询本地或远端 IP 地址时,如果存在 IPv4 和 IPv6 双地址,Java 程序是否优先返回 IPv6 地址。Java 默认返回 IPv4 地址主要是为了向后兼容,以支持旧有的 IPv4 验证逻辑,以及旧有的仅支持 IPv4 地址的服务。

4. socket 支持 IPv6 通信示例

客户端:

package com.text2;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.util.Enumeration;

public class Click {
    public static void main(String[] args) throws IOException {
        //获取本机IPv6地址getLocalIPv6Address()方法在上面已经提到
        String servernameString = getLocalIPv6Address();
        System.out.println("客户端启动…");
        System.out.println("当接收到服务器端字符为 \"OK\" 的时候, 客户端将终止\n");
        while (true) {
            Socket socket = null;
            try {
                // 创建一个流套接字并将其连接到指定主机上的指定端口号
                socket = new Socket(servernameString, 8080);
                // 读取服务器端数据
                DataInputStream input = new DataInputStream(socket.getInputStream());
                // 向服务器端发送数据
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                System.out.print("请输入: \t");
                String str = new BufferedReader(new InputStreamReader(System.in)).readLine();
                out.writeUTF(str);
                String ret = input.readUTF();
                System.out.println("服务器端返回过来的是: " + ret);
                if ("OK".equals(ret)) {
                    System.out.println("客户端将关闭连接");
                    Thread.sleep(500);
                    break;
                }
                out.close();
                input.close();
            } catch (Exception e) {
                System.out.println("客户端异常:" + e.getMessage());
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        socket = null;
                        System.out.println("客户端 finally 异常:" + e.getMessage());
                    }
                }
            }
        }
    }
    public static String getLocalIPv6Address() throws IOException {
        InetAddress inetAddress = null;
        Enumeration<NetworkInterface> networkInterfaces =
        NetworkInterface
        .getNetworkInterfaces();
        outer:
        while (networkInterfaces.hasMoreElements()) {
            Enumeration<InetAddress> inetAds =
            networkInterfaces.nextElement()
            .getInetAddresses();
            while (inetAds.hasMoreElements()) {
                inetAddress = inetAds.nextElement();
        //Check if it‘s ipv6 address and reserved address
                if (inetAddress instanceof Inet6Address
                    && !isReservedAddr(inetAddress)) {
                    break outer;
                }
            }
        }
        String ipAddr = inetAddress.getHostAddress();
        // Filter network card No
        int index = ipAddr.indexOf(‘%‘);
        if (index > 0) {
            ipAddr = ipAddr.substring(0, index);
        }
        return ipAddr;
    }

    private static boolean isReservedAddr(InetAddress inetAddr) {
        if (inetAddr.isAnyLocalAddress() || inetAddr.isLinkLocalAddress()|| inetAddr.isLoopbackAddress()) {
            return true;
            }
        return false;
    }
}

服务器端:

package com.text2;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("服务器启动…\n");
        Server server = new Server();
        server.init();
    }

    public void init() {
        try {
            ServerSocket serverSocket = new ServerSocket(8080);
            while (true) {
                // 一旦有堵塞, 则表示服务器与客户端获得了连接
                Socket client = serverSocket.accept();
                // 处理这次连接
                new HandlerThread(client);
            }
        } catch (Exception e) {
            System.out.println("服务器异常: " + e.getMessage());
        }
    }

    private class HandlerThread implements Runnable {
        private Socket socket;

        public HandlerThread(Socket client) {
            socket = client;
            new Thread(this).start();
        }

        public void run() {
            try {
                // 读取客户端数据
                DataInputStream input = new DataInputStream(socket.getInputStream());
                String clientInputStr = input.readUTF();
                //这里要注意和客户端输出流的写方法对应,否则会抛 EOFException
                // 处理客户端数据
                System.out.println("客户端发过来的内容:" + clientInputStr);
                // 向客户端回复信息
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                System.out.print("请输入:\t");
                // 发送键盘输入的一行
                String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
                out.writeUTF(s);
                out.close();
                input.close();
            } catch (Exception e) {
                    System.out.println("服务器 run 异常: " + e.getMessage());
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (Exception e) {
                        socket = null;
                        System.out.println("服务端 finally 异常:" + e.getMessage());
                    }
                }
            }
        }
    }
}

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

时间: 2024-10-16 06:09:40

IPv6基本编程——Java的相关文章

socket编程-java

一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机. 而TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的. 目前较为流行的网络编程模型是客户机/服务器(C/S)结构.即通信双方一方作为服务器等待客户提出请求并予以响应.客户则

How to support both ipv4 and ipv6 address for JAVA code.

IPv6 have colon character, for example FF:00::EEIf concatenate URL String, IPv6 URL will like: http://FF:00::EE:8888/a/b/cActually we want: http://[FF:00::EE]:8888/a/b/cSimply concatenate URL will cause error. Take above line for example. If not use

Atitit.异步编程 java .net php python js 的比较

Atitit.异步编程 java .net php python js 的比较 1. 1.异步任务,异步模式,  APM模式,,  EAP模式, TAP 1 1.1.       APM模式: BeginXXX/EndXXX, IAsyncResult 2 1.2.       EAP模式(基于事件的异步模式) 2 1.3.      TAP(基于任务的异步模式) 2 2. 异步的实现机制::主要是通过线程and线程池实现的... 2 3. 异步编程的开发::当前都是通过api的,将来应该可以使

LINUX 下 ipv6 socket 编程

大家都知道,随着互联网上主机数量的增多,现有的32位IP地址已经不够用了,所以推出了下一代IP地址IPv6,写网络程序的要稍微改变一下现有的网络程序适应IPv6网络是相当容易的事.对于我们来说就是IP地址变化了,所以程序里在用到IP地址的地方做相应的改变就可以了. 记住:主要是改变程序里设置IP地址和端口等部分的代码. 服务器端源代码如下:/***********************/#include <stdio.h>#include <stdlib.h>#include &

网络编程-Java中的Internet查询

前提 在深入理解URL.URI等概念,或者学些Socket相关的知识之,有必要系统理解一下Internet相关的一些基础知识. Internet地址 连接到Internet(因特网)的设备称为节点(node),而任意一个计算机节点称为主机(host).每个节点或者主机都由至少一个唯一的数来标识,这称为Internet地址或者IP地址. IP和域名 如果使用Java作为开发语言的话,不需要担心IP或者域名的工作原理,但是我们需要理解IP寻址的一些基础知识.我们目前常用的网络都是IPv4网络,每个计

基础编程-java之股神

买了一支股票,他知道从他买股票的那天开始,股票会有以下变化:第一天不变,以后涨一天,跌一天,涨两天,跌一天,涨三天,跌一天...依此类推. 为方便计算,假设每次涨和跌皆为1,股票初始单价也为1,请计算买股票的第n天每股股票值多少钱? 这是本人在某网站看到的简单编程题.大伙们可以尝试看看! 个人认为多做些算法编程题,有利于提高自己的编程水平,偏向机器思维 下面是脑残博主的暴力式答题: public class Demo1 { public static void main(String[] arg

多线程编程——java

1.进程和线程 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线程:表示程序的执行流程,是CPU调度执行的基本单位:线程有自己的程序计数器.寄存器.堆栈和帧.同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源. 2.多线程 多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立.线程又称为

JDBC编程JAVA

学习资料<疯狂java讲义> 环境:MYSQL Java 1.7 java用JDBC操作数据库是java编程的基础之一.而掌握SQL是JDBC编程的基础.JDBC是sun公司制定的接口API,各个数据库产商根据接口API提供实现类(驱动程序),这是面向接口编程的典型应用. 可以把 SQL 分为两个部分:数据操作语言 (DML) 和 数据定义语言 (DDL). SQL (结构化查询语言)是用于执行查询的语法.但是 SQL 语言也包含用于更新.插入和删除记录的语法. 查询和更新指令构成了 SQL

并发编程—— Java 内建线程机制【上】

不理解多线程程序设计, 就无法真正理解 JavaSE 和 JDK 源码: 因为线程特性已经与Java 语言紧密地融合在一起. 如何学习多线程程序设计呢? 那看上去似乎总是显得有些神秘.首先, 必须透彻理解并发程序设计的基本原理和机制, 否则, 只是学习使用那些关键字.类的招式,恐怕只能获得Superficial 的认识, 因为多线程程序设计的难点就在于,在任何情况下都能正确工作, easily writing programs that appear to work but will fail