Java IPアドレスの取得方法

「いいNICの日」ということで、JavaでのNIC取得から
IPアドレスの取得方法について少し書いておきます。

Javaでは、まず使用するネットワークインタフェースを定めます
例えばイーサネットカードが2枚刺さっている場合、どちらのイーサネットカードのアドレスを取得するのか決めなければいけません。
取得方法は以下の通り。

for(Enumeration<NetworkInterface> nie = NetworkInterface.getNetworkInterfaces(); nie.hasMoreElements();){
     NetworkInterface ni = nie.nextElement();
     ......
}

NetworkInterfaceクラスのgetNetworkInterfacesメソッドを呼び出すと、使用できるNetwork Interfaceの一覧が返ってきます。
このメソッド、Genericsには対応しているくせにIterableではないEnumerationインスタンスが返って来るので、
Java 5以降で使えるようになったfor each構文ではなく、普通のfor文若しくはwhile文で回して取得してください。
Concurrencyに行うためなのかな・・・。早くこのメソッドは直して欲しい・・・。


愚痴が多くなりましたが、これでNetworkIntefaceを取得できました。
次にIPアドレスの取得です。
NetworkInterfaceには複数のアドレスが付いている場合があります。(v4とv6とかリンクローカルとか)
なので、それのどれを使うかを指定しないといけません。

     ....
     for(Enumeration<InetAddress> iae = ni.getInetAddresses(); ia.hasMoreElements();){
     InetAddress ia = iae.nextElement();
     .....

という感じに、こいつも何故かEnumerationを返すので、for文かwhile文を使ってください。
これでアドレスの取得は終了です。
が、問題はアプリケーションで使用するアドレスをこの一覧の中からどうやって決めるか、ということです。

  • 対処法その1:引数による指定

例えば引数なしで起動したときにIPアドレスに番号を付けて、次の起動時に指定させる・・・といった方法は、次の起動のタイミングでIPアドレスが変わったとか、アドレスが増えたとかいう時に予期せぬアドレスを指定しかねません。
対処法としては例えば引数無しで起動したときにInetAddressのハッシュ値を表示させ、引数の値と先頭一致させる方法が考えられます。
もしくは引数で直接アドレスかドメイン名を指定させる方法もありますが、
それなら最初から指定させておけば良いです。
後、コマンドによる実行が前提となるので、若干めんどくさいです。

  • 対処法その2:System.inもしくはGUIによる選択

取得した情報をSystem.outに出力し、System.inから入力を受け付けて選択する方法。
この場合もプログラムをコマンドライン等から入力する必要があります。
ということで、GUIが使える環境であれば、GUIを開いてユーザに選択してもらうのが一番手っ取り早く済みます。

最後に、私がよく使っているアドレス選択GUI画面のソースコードを以下に載せておきます。
使い方はnewして、addEndTaskにアドレス決定時の処理(Funcインタフェースを実装)して、openGUIでGUIを開きます。
無駄にConcurrentなクラスを使っていますが、あんまり意味はありません。
これと引数指定、もしくはConfigファイルによる指定の併用が割と便利だったりします。

public class SelectNetAddress {

	private final CopyOnWriteArrayList<AddressListElement> addressList;
	private final ConcurrentHashMap<Integer, ListDataListener> listeners;
	private final AtomicReference<AddressListElement> selectedAddr;
	private final CopyOnWriteArrayList<Func> taskList;

	public SelectNetAddress() throws SocketException {
		selectedAddr = new AtomicReference<AddressListElement>();
		addressList = new CopyOnWriteArrayList<AddressListElement>();
		taskList = new CopyOnWriteArrayList<Func>();
		listeners = new ConcurrentHashMap<Integer, ListDataListener>();
		
		for (Enumeration<NetworkInterface> nie = NetworkInterface.getNetworkInterfaces(); nie.hasMoreElements();) {
			NetworkInterface ni = nie.nextElement();
			for (Enumeration<InetAddress> ia = ni.getInetAddresses(); ia.hasMoreElements();) {
				AddressListElement e = new AddressListElement(ni, ia.nextElement());
				addressList.add(e);
			}
		}

	}

	public void openGUI() {
		final JList<AddressListElement> jlist = new JList<>(new ListModel<AddressListElement>() {
			@Override
			public void addListDataListener(ListDataListener l) {
				listeners.put(l.hashCode(), l);
			}

			@Override
			public void removeListDataListener(ListDataListener l) {
				listeners.remove(l.hashCode());
			}

			@Override
			public int getSize() {
				return addressList.size();
			}

			@Override
			public AddressListElement getElementAt(int index) {
				return addressList.get(index);
			}
		});

		final JFrame frame = new JFrame("Address Selector");
		frame.setSize(640, 400);
		frame.setLocation(100, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		SpringLayout sl = new SpringLayout();
		Container cp = frame.getContentPane();
		cp.setLayout(sl);
		cp.add(jlist);

		final JButton button = new JButton("Select");
		cp.add(button);
		button.setEnabled(false);

		jlist.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				button.setEnabled(true);
			}
		});

		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Object obj = jlist.getSelectedValue();
				if (obj instanceof AddressListElement) {
					AddressListElement el = (AddressListElement) obj;
					selectedAddr.set(el);
					frame.setVisible(false);
					frame.dispose();
					for (Func t : taskList) {
						t.func(getAddress());
					}
				}
			}
		});

		sl.putConstraint(SpringLayout.NORTH, jlist, 10, SpringLayout.NORTH, cp);
		sl.putConstraint(SpringLayout.WEST, jlist, 10, SpringLayout.WEST, cp);
		sl.putConstraint(SpringLayout.EAST, jlist, -10, SpringLayout.EAST, cp);

		sl.putConstraint(SpringLayout.SOUTH, jlist, -10, SpringLayout.NORTH, button);

		sl.putConstraint(SpringLayout.SOUTH, button, -10, SpringLayout.SOUTH, cp);
		sl.putConstraint(SpringLayout.WEST, button, 10, SpringLayout.WEST, cp);
		sl.putConstraint(SpringLayout.EAST, button, -10, SpringLayout.EAST, cp);

		frame.setVisible(true);
	}

	public void addEndTask(Func t) {
		taskList.add(t);
	}

	public InetAddress getAddress() {
		return selectedAddr.get().getAddr();
	}
	
	
	public interface Func {
		public void func(InetAddress ia);
	}
}