这里是Java网络编程
,Java Socket编程
相关的学习手记
。这里按照官方的Java 8 Toturial
教程的Custom Networking学习路径
,对相关的一些内容进行解读(并不完全,如果有错请联系我,谢谢^ _ ^),同时在学习的过程中加入个人的理解与对代码运行的思考。
下面是整个专栏的文章链接,用于快速的导航。
0
. 整个系列文章介绍1
. Java网络编程假定你需要一些基本的网络知识。2
. Java操作URL;java.net.URL,java.net.URLConnection3
. Java Socket编程;关于Socket的使用; java.net.Socket ,java.net.ServerSocket4
. Java UDP Datagrams数据报编程;Java单播,多播编程;java.net.DatagramPacket,java.net.DatagramSocket,java.net.MulticastSocket5
. 使用Java访问系统(电脑,机器)的网络信息,如网卡信息,网络状态等;java.net.NetworkInterface6
. 在Java客户端上操作,管理Cookie;7
. 在1~6节的编程实践中,我遇到的一些问题;
摘要与说明
原文来自Java 8官方Tutorial
文章会加入自己的学习时想到的一些内容。
题目本来是:Programmatic Access to Network Parameters
,这里我写成访问系统网络的相关信息
,当然也可以写作访问网络参数的编程接口
啦。不纠结了。。。
系统常常会有多个活跃的网络接口可用于连接,例如
{
wired Ethernet
,802.11 b/g (wireless)
,bluetooth
}
。一些应用可能需要访问它们的信息来执行特定的网络活动。
{
无线,有线,蓝牙}
java.net.NetworkInterface
类提供了访问这些信息的接口。
这篇文章就探讨一下这个类的一般用法,并且提供一些例子,比如说列出你的电脑上所有的
网络接口(network interfaces)
,以及接口相关的信息如IP地址,网络状态
。
下面给出本文的导航,点击相应标题能够查看该小节的详细内容。
1. 什么是网络接口?(What Is a Network Interface?)
- 介绍网络接口,以及解释你为什么想要使用它
2. 检索网络接口(Retrieving Network Interfaces)
- 用一个例子来说明客户端程序如何检索(retrieve)机器上的所有网络接口
3. 列出网络接口地址(Listing Network Interface Addresses)
- 教你怎么列出机器上所有网络接口的IP地址
4. 网络接口参数(信息)(Network Interface Parameters)
- 教你怎么判定一个网络接口
- 是否
正在工作(is running)
- 是否是一个
回环接口(a loopback interface)
- 是否是一个
点到点的接口(a point-to-point interface)
- 是否是一个
虚拟接口(a virtual interface)
- 是否
支持多播(supports multicasting)
1. 什么是网络接口?(What Is a Network Interface?)
网络接口(network interface)是计算机互连或者网络互连的端点。网络接口一般来说是一个
网络接口卡(NIC,network interface card)
,也就是我们日常所说的网卡
,但是它(network interface)却不一定是以物理形式而存在的。相反,网络接口可能用软件来实现。拿回环接口( loopback interface)
举个例子,IPv4的127.0.0.1和IPv6的 ::1
都没有对应的物理设备,而是一种模拟网络接口的软件
。回环接口通常在测试环境下使用。
java.net.NetworkInterface
能表示软/硬两种形式的网络接口
NetworkInterface
对于对多宿主系统(multi-homed system,带有多个网卡的系统)也是有用的。使NetworkInterface,你能指定某个网卡来进行特定的网络活动。
举个例子。假设你有一台配有两个网卡的机器,此时你想要发送数据给服务器。你能这样创建一个socket:
Socket soc = new java.net.Socket();
soc.connect(new InetSocketAddress(address, port));
前面的章节我们发送数据,都是默认由系统来选择某个网络接口来与外界进行通信。然而,如果你想自己指定某个网卡来发送数据,那么你需要查询系统以获取合适的接口,然后得到此接口的IP地址。通过上面方法创建socket后并且绑定我们获得的IP地址,系统就能使用此网络接口了。
下面是代码实现:
NetworkInterface nif = NetworkInterface.getByName("bge0");
Enumeration<InetAddress> nifAddresses = nif.getInetAddresses();
Socket soc = new java.net.Socket();
soc.bind(new InetSocketAddress(nifAddresses.nextElement(), 0));
soc.connect(new InetSocketAddress(address, port));
你也能使用
NetworkInterface
来标识本地的网络接口在那个组播里。如:
NetworkInterface nif = NetworkInterface.getByName("bge0");
MulticastSocket ms = new MulticastSocket();
ms.joinGroup(new InetSocketAddress(hostname, port), nif);
NetworkInterface能被Java API用在许多其它方面,而不仅限于我们上面描述的两个例子。
2. 检索网络接口(Retrieving Network Interfaces)
NetworkInterface
类并没有public构造方法。因此,你不能使用new操作符来创建此类的实例,相反,可以使用static方法来获得(retrieve )系统网络接口的详细信息:getByInetAddress()
,getByName()
,getNetworkInterfaces()
。前面两个方法已经用过了,获取IP地址和接口名。第三个方法,返回系统的所有接口列表。
网络接口能够有组织的被继承。
NetworkInterface
类包含两个方法就跟接口的继承相关:getParent()
,getSubInterfaces()
。getParent方法返回接口的父NetworkInterface 。如果一个网络接口是子接口,那么getParent方法返回一个非空值(non-null)。getSubInterfaces()方法返回此网络接口的所有的子接口。
下面是一个程序例子,列出机器上的所有的网络接口名和子接口(如果存在的话)
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());
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());
}
}
}
官方给出的输出例子。
Display name: bge0
Name: bge0
Sub Interface Display name: bge0:3
Sub Interface Name: bge0:3
Sub Interface Display name: bge0:2
Sub Interface Name: bge0:2
Sub Interface Display name: bge0:1
Sub Interface Name: bge0:1
Display name: lo0
Name: lo0
然而,下面是我的电脑的输出结果,因为虚拟机的原因,输出的东西有点多。没有Sub Interface接口。
Display name: Software Loopback Interface 1
Name: lo
Display name: Microsoft Hosted Network Virtual Adapter
Name: wlan0
Display name: Microsoft ISATAP Adapter
Name: net0
Display name: Microsoft ISATAP Adapter #4
Name: net1
Display name: Microsoft ISATAP Adapter #2
Name: net2
Display name: VMware Virtual Ethernet Adapter for VMnet8
Name: eth0
Display name: Realtek PCIe FE Family Controller
Name: eth1
Display name: Intel(R) Dual Band Wireless-AC 3160
Name: wlan1
Display name: Microsoft ISATAP Adapter #3
Name: net3
Display name: WAN Miniport (SSTP)
Name: net4
Display name: WAN Miniport (IP)
Name: eth2
Display name: WAN Miniport (IKEv2)
Name: net5
Display name: VMware Virtual Ethernet Adapter for VMnet1
Name: eth3
Display name: WAN Miniport (PPPOE)
Name: ppp0
Display name: WAN Miniport (PPTP)
Name: net6
Display name: Microsoft Kernel Debug Network Adapter
Name: eth4
Display name: Microsoft Wi-Fi Direct Virtual Adapter
Name: wlan2
Display name: WAN Miniport (Network Monitor)
Name: eth5
Display name: Remote NDIS based Internet Sharing Device
Name: eth6
Display name: WAN Miniport (L2TP)
Name: net7
Display name: WAN Miniport (IPv6)
Name: eth7
Display name: Microsoft Teredo Tunneling Adapter
Name: net8
Display name: Realtek PCIe FE Family Controller-WFP Native MAC Layer LightWeight Filter-0000
Name: eth8
Display name: Realtek PCIe FE Family Controller-VirtualBox NDIS Light-Weight Filter-0000
Name: eth9
Display name: Realtek PCIe FE Family Controller-Liebao Wifi NAT Driver-0000
Name: eth10
Display name: Realtek PCIe FE Family Controller-QoS Packet Scheduler-0000
Name: eth11
Display name: Realtek PCIe FE Family Controller-WFP 802.3 MAC Layer LightWeight Filter-0000
Name: eth12
Display name: Intel(R) Dual Band Wireless-AC 3160-WFP Native MAC Layer LightWeight Filter-0000
Name: wlan3
Display name: Intel(R) Dual Band Wireless-AC 3160-Virtual WiFi Filter Driver-0000
Name: wlan4
Display name: Intel(R) Dual Band Wireless-AC 3160-Native WiFi Filter Driver-0000
Name: wlan5
Display name: Intel(R) Dual Band Wireless-AC 3160-VirtualBox NDIS Light-Weight Filter-0000
Name: wlan6
Display name: Intel(R) Dual Band Wireless-AC 3160-Liebao Wifi NAT Driver-0000
Name: wlan7
Display name: Intel(R) Dual Band Wireless-AC 3160-QoS Packet Scheduler-0000
Name: wlan8
Display name: Intel(R) Dual Band Wireless-AC 3160-WFP 802.3 MAC Layer LightWeight Filter-0000
Name: wlan9
Display name: Microsoft Hosted Network Virtual Adapter-WFP Native MAC Layer LightWeight Filter-0000
Name: wlan10
Display name: Microsoft Hosted Network Virtual Adapter-Native WiFi Filter Driver-0000
Name: wlan11
Display name: Microsoft Hosted Network Virtual Adapter-VirtualBox NDIS Light-Weight Filter-0000
Name: wlan12
Display name: Microsoft Hosted Network Virtual Adapter-Liebao Wifi NAT Driver-0000
Name: wlan13
Display name: Microsoft Hosted Network Virtual Adapter-QoS Packet Scheduler-0000
Name: wlan14
Display name: Microsoft Hosted Network Virtual Adapter-WFP 802.3 MAC Layer LightWeight Filter-0000
Name: wlan15
Display name: Microsoft Wi-Fi Direct Virtual Adapter-WFP Native MAC Layer LightWeight Filter-0000
Name: wlan16
Display name: Microsoft Wi-Fi Direct Virtual Adapter-Native WiFi Filter Driver-0000
Name: wlan17
Display name: Microsoft Wi-Fi Direct Virtual Adapter-VirtualBox NDIS Light-Weight Filter-0000
Name: wlan18
Display name: Microsoft Wi-Fi Direct Virtual Adapter-Liebao Wifi NAT Driver-0000
Name: wlan19
Display name: Microsoft Wi-Fi Direct Virtual Adapter-QoS Packet Scheduler-0000
Name: wlan20
Display name: Microsoft Wi-Fi Direct Virtual Adapter-WFP 802.3 MAC Layer LightWeight Filter-0000
Name: wlan21
3. 列出网络接口地址(Listing Network Interface Addresses)
你能从接口获取的最有用的信息之一就是IP地址了。你能通过NetworkInterface实例来获取IP地址。下面有两个方法。一种是通过
getInetAddresses()
方法返回InetAddress类型的枚举类
(Enumeration of InetAddress,Enumeration<NetworkInterface>
)。第二种方法是通过getInterfaceAddresses()
返回java.net.InterfaceAddress实例list
,当你不仅仅只是想获取接口的ip,还想获取其它信息的时候可以使用这种方法,例如:IPv4中的子网掩码(subnet mask),广播地址(broadcast address),IPv6中的网络前缀长度(network prefix length)。
下面是一个程序的例子,列出所有网络接口以及它的IP地址:
import java.io.*;
import java.net.*;
import java.util.*;
import static java.lang.System.out;
public class ListNets {
public static void main(String args[]) throws SocketException {
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets))
displayInterfaceInformation(netint);
}
static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {
out.printf("Display name: %s\n", netint.getDisplayName());
out.printf("Name: %s\n", netint.getName());
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
out.printf("InetAddress: %s\n", inetAddress);
}
out.printf("\n");
}
}
官方给出的一个输出例子
Display name: TCP Loopback interface
Name: lo
InetAddress: /127.0.0.1
Display name: Wireless Network Connection
Name: eth0
InetAddress: /192.0.2.0
4. 网络接口参数(信息)(Network Interface Parameters)
你能获得一个网络接口更多的网络参数,而不仅仅只是接口名,IP地址。
你能通过
isUP()
方法来查看一个接口是否正在运行。下面的方法可以获知网络接口的类型:
isLoopback()
用来查看一个接口是否是回环接口(loopback interface)isPointToPoint()
用来查看接口是否是点到点接口( point-to-point interface.)isVirtual()
查看接口是否是虚拟接口(virtual interface)
supportsMulticast()
方法可以查看接口是否支持多播。
getHardwareAddress()
方法能获取接口的物理地址,通常情况下叫做MAC地址
。
getMTU()
获取接口的最大传输单元(Maximum Transmission Unit (MTU),也就是单个数据包的最大字节数。
下面是代码例子:
import java.io.*;
import java.net.*;
import java.util.*;
import static java.lang.System.out;
public class ListNetsEx {
public static void main(String args[]) throws SocketException {
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets))
displayInterfaceInformation(netint);
}
static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {
out.printf("Display name: %s\n", netint.getDisplayName());
out.printf("Name: %s\n", netint.getName());
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
out.printf("InetAddress: %s\n", inetAddress);
}
out.printf("Up? %s\n", netint.isUp());
out.printf("Loopback? %s\n", netint.isLoopback());
out.printf("PointToPoint? %s\n", netint.isPointToPoint());
out.printf("Supports multicast? %s\n", netint.supportsMulticast());
out.printf("Virtual? %s\n", netint.isVirtual());
out.printf("Hardware address: %s\n",
Arrays.toString(netint.getHardwareAddress()));
out.printf("MTU: %s\n", netint.getMTU());
out.printf("\n");
}
}
官方给出的输出例子:
Display name: bge0
Name: bge0
InetAddress: /fe80:0:0:0:203:baff:fef2:e99d%2
InetAddress: /129.156.225.59
Up? true
Loopback? false
PointToPoint? false
Supports multicast? false
Virtual? false
Hardware address: [0, 3, 4, 5, 6, 7]
MTU: 1500
Display name: lo0
Name: lo0
InetAddress: /0:0:0:0:0:0:0:1%1
InetAddress: /127.0.0.1
Up? true
Loopback? true
PointToPoint? false
Supports multicast? false
Virtual? false
Hardware address: null
MTU: 8232