JDK8 网络Net包研究(一)
网络基础
1)国际标准化组织的OSI[开放式系统互联模型]七层模型
2)TCP/IP协议[组]四层模型
3)TCP/IP协议组:一组包括TCP协议和IP协议,UDP协议、ICMP协议和其他一些协议的协议组。
网络层:
IP协议->网络互连协议 用途:将多个包在网络中联系起来,传输数据包(不可靠传输),最基本功能就是寻址和分段功能,不提供端到端,路由到路由的确认,不提供重发和流量控制。是计算机网络能狗相互通信的基本规则。出错则像ICMP报告,ICMP在IP模块中实现
ICMP协议, 用途:面向无连接协议,用于传输错误报告控制信息(控制信息是指网络不通畅,主机是否到达,路由是否可用的这些网络本身的消息,不涉及用户传输的数据)
ARP协议->地址解析协议 用途:根据IP地址获取物理地址的协议(即MAC地址)。在同一子网内通过ARP协议可以实现数据包的互相传递。不在一个子网内则无法获得MAC地址,只有通过网关去处理。
RARP协议->反转地址协议 用途:和ARP协议相反,将主机的物理地址转换成IP地址。
BOOTP协议->引导程序协议 用途:用于无盘工作站的局域网中,可以无盘工作站从一个中心服务器上获得IP地址。
传输层:
TCP协议->传输控制协议 用途:主要用于网间传输的协议,分割处理报文并把结果包传到IP层,并接收处理IP曾传到的数据包。
UDP协议->用户数据协议 用途:主要用于需要在计算器之间传输数据的应用,将网络数据流浪压缩成数据包。
应用层:
NET协议->网络地址转换协议 用途:实现内网IP地址和公网地址之间的相互转换。将大量的内网IP转换成一个或者少量的公网IP
FTP协议->文件传输协议 用途:通过FTP协议在FTP客户端访问FTP服务端,默认使用20和21端口,20用于传输数据,21用于传输控制信息。
HTTP协议->超文本传输协议 用途:是用于从WWW服务器传输超文本到本地浏览器的传输协议。是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。
TELNET协议 用途:是Internet远程登陆服务的标准协议和主要方式,为用户提供了在本地计算机上完成远程主机工作的能力。
SMTP协议->简单邮件传输协议 用途:控制邮件传输的规则,以及邮件的中转方式。
DNS协议 用途:定义域名规则,将域名和IP相互映射
InetAddress部分
InetAddress类用于封装一个数据式的网络IP地址和域名。
public class InetAddress{
#获取InetAddress对象的5个成员方法:
public static InetAddress getByAddress(String host, byte[] addr)
public static InetAddress getByName(String host)
public static InetAddress[] getAllByName(String host)
public static InetAddress getByAddress(byte[] addr)
public static InetAddress getByAddress(byte[] addr)
#获取主机名等地址信息的6个成员方法:
public String getHostName()
public byte[] getAddress()
public String getHostAddress()
public boolean isMulticastAddress()
public boolean isLoopbackAddress()
public String getCanonicalHostName()
#定义static class InetAddressHolder内部类
static class InetAddressHolder{......}
#InetAddress Constructor
final transient InetAddressHolder holder;
InetAddress() {
holder = new InetAddressHolder();
}
#将网络库加载到运行时,并执行初始化
static transient boolean preferIPv6Address = false;//IPv4Address
static {
preferIPv6Address = java.security.AccessController.doPrivileged(
new GetBooleanAction("java.net.preferIPv6Addresses")).booleanValue();
AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() { System.loadLibrary("net"); return null; }
});
init();//native method
}
#deserialized InetAddress object with Inet4Address
private Object readResolve() throws ObjectStreamException {
return new Inet4Address(holder().getHostName(),holder().getAddress());
}
#定义InetAddress[]和InetAddressImpl,InetAddressImpl接口被Inet4AddressImpl、Inet6AddressImpl实现
static InetAddress[] unknown_array; // put THIS in cache
static InetAddressImpl impl;
private static List<NameService> nameServices = null;#存储the name service provider
#创建InetAddressImpl、NameService
static {
// create the impl,见InetAddressImplFactory
impl = InetAddressImplFactory.create();
// get name service if provided and requested
String provider = null;;
String propPrefix = "sun.net.spi.nameservice.provider.";
int n = 1;
nameServices = new ArrayList<NameService>();
provider = AccessController.doPrivileged(
new GetPropertyAction(propPrefix + n));
while (provider != null) {
NameService ns = createNSProvider(provider);
if (ns != null)
nameServices.add(ns);
n++;
provider = AccessController.doPrivileged(
new GetPropertyAction(propPrefix + n));
}
// if not designate any name services provider,
// create a default one
if (nameServices.size() == 0) {
NameService ns = createNSProvider("default");
nameServices.add(ns);
}
}
#内部类工厂模式
class InetAddressImplFactory {
static InetAddressImpl create() {
return InetAddress.loadImpl(isIPv6Supported() ? "Inet6AddressImpl" : "Inet4AddressImpl");
}
static native boolean isIPv6Supported();
}
#装入并实例化一个底层的impl类
static InetAddressImpl loadImpl(String implName) {
Object impl = null;
......
if (impl == null) {
try {
impl = Class.forName(implName).newInstance();
} catch (Exception e) {
throw new Error("System property impl.prefix incorrect");}
}
return (InetAddressImpl) impl;
}
URL部分
统一资源定位符,用来标识互联网上的资源,采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。
#构造函数
public URL(String spec)
public URL(URL context, String spec)
public URL(String protocol, String host, String file)
public URL(String protocol, String host, int port, String file)
#重要成员方法
public final InputStream openStream()
public URLConnection openConnection()
socket部分
Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,连接的一端称为一个socket。Socket类代表流套按字连接两端中的任意一端,可以服务器或客户端两端使用。
类设计关系图
1 Socket类
#定义Socket抽象类接口
SocketImpl impl;
#构造Socket(1个默认构造函数,3个带参构造函数,2个做费构造函数)
#默认构造函数,创建无连接Socket
public Socket()
#Creates a stream socket and connects it to the specified port number on the named host
public Socket(String host, int port) {
this(host != null ? new InetSocketAddress(host, port) :
new InetSocketAddress(InetAddress.getByName(null), port),(SocketAddress) null, true);
}
#Creates a stream socket and connects it to the specified port number at the specified IP address
public Socket(InetAddress address, int port) {
this(address != null ? new InetSocketAddress(address, port) : null,(SocketAddress) null, true);
}
#Creates a socket and connects it to the specified remote host on the specified remote port. The Socket will also bind() to the local address and port supplied
public Socket(String host, int port, InetAddress localAddr, int localPort) {
this(host != null ? new InetSocketAddress(host, port) :
new InetSocketAddress(InetAddress.getByName(null), port),
new InetSocketAddress(localAddr, localPort), true);
}
#以上各构造函数中调用的this函数定义即为如下Socket方法
private Socket(SocketAddress address, SocketAddress localAddr, boolean stream) {
setImpl();
// backward compatibility
try {
createImpl(stream);
if (localAddr != null)
bind(localAddr);
connect(address);
...
}
2 InetSocketAddress类
提供了一个用于套接字绑定、连接或返回值的不可变对象,主要包括Socket Address对象信息,即主机名-hostname String、IP地址-addr InetAddress,端口-port int三个属性。
public class InetSocketAddress extends SocketAddress{...}
3 Socket分析
Socket客户端Socket类分析
说明:以 public Socket(String host, int port)为入口点
3.1)初始化InetSocketAddress对象,并递归调用this方法
public Socket(String host, int port) {
this(host != null ? new InetSocketAddress(host, port) :
new InetSocketAddress(InetAddress.getByName(null), port),
(SocketAddress) null, true);
}
3.2)this方法,参数stream = true
private Socket(SocketAddress address, SocketAddress localAddr,boolean stream) throws IOException {
setImpl();//设置默认的抽象类SocketImpl接口对象
// backward compatibility
if (address == null) throw new NullPointerException();
try {
//Creates the socket implementation,stream:true TCP socket,false:UDP,最终代码调用跟踪到native int socket0方法
createImpl(stream);
if (localAddr != null)
//Binds this socket to the specified local IP address and port number,最终代码调用跟踪到native void bind0方法
bind(localAddr);
connect(address);
....
}
3.3)connect(address), 跟踪核心过程方法->
/**
* Connects this socket to the server with a specified timeout value.
* @param endpoint the {@code SocketAddress}
* @param timeout the timeout value to be used in milliseconds.
*/
public void connect(SocketAddress endpoint, int timeout) {
...
InetSocketAddress epoint = (InetSocketAddress) endpoint;
InetAddress addr = epoint.getAddress ();
int port = epoint.getPort();
checkAddress(addr, "connect");
...
if (epoint.isUnresolved())
impl.connect(addr.getHostName(), port);
else
impl.connect(addr, port);
...
}
3.4)impl.connect(addr, port), 跟踪核心过程方法->
synchronized void doConnect(InetAddress address, int port, int timeout) {
synchronized (fdLock) {
if (!closePending && (socket == null || !socket.isBound())) {
NetHooks.beforeTcpConnect(fd, address, port);
}
}
try {
acquireFD();
//与Socket服务器InetSocketAddress[address,port]建立连接
socketConnect(address, port, timeout);
....
}
3.5)socketConnect(address, port, timeout), 跟踪核心过程方法->
socketConnect最终分支为两个实现:DualStackPlainSocketImpl实现类的static native int connect0(int fd, InetAddress remote, int remotePort) 方法 或TwoStacksPlainSocketImpl实现类的native void socketConnect(InetAddress address, int port, int timeout)
3.6)在建立连接完后,客户端可向服务器端发送信息(OutputStream os = socket.getOutputStream();字节输出流), 跟踪核心过程方法->
public OutputStream getOutputStream() throws IOException {
......
OutputStream os = null;
try {
os = AccessController.doPrivileged(
new PrivilegedExceptionAction<OutputStream>() {
public OutputStream run() throws IOException {
return impl.getOutputStream();
}
});
....
return os;}
impl.getOutputStream(), 跟踪核心过程方法->
//Gets an OutputStream for this socket.
protected synchronized OutputStream getOutputStream() {
synchronized (fdLock) {
if (isClosedOrPending()) throw new IOException("Socket Closed");
if (shut_wr) throw new IOException("Socket output is shutdown");
if (socketOutputStream == null)
//Creates a new SocketOutputStream. Can only be called by a Socket. This method needs to hang on to the owner Socket
socketOutputStream = new SocketOutputStream(this);
}
return socketOutputStream;
}
3.7)在建立连接完后,客户端接收向服务器端发送的信息(InputStream is=socket
.getInputStream()获取输入流), 设计思想同getOutputStream()完全一致。
3.8)Closes this socket
public void close() throws IOException {
synchronized(closeLock) {
if (isClosed())
return;
if (created)
impl.close();
closed = true;
}
}
Socket服务端ServerSocket类分析
#构造ServerSocket(1个默认构造函数,2个带参构造函数)
public ServerSocket()
public ServerSocket(int port) //创建Socket服务端
3.1)创建Socket服务端, 跟踪核心过程方法->
public ServerSocket(int port, int backlog, InetAddress bindAddr) {
setImpl();同客户端设置SocketImpl一致
...
try {
//初始化InetSocketAddress,并bind
bind(new InetSocketAddress(bindAddr, port), backlog);
} ...}
Bind方法, 跟踪核心过程方法->
Public void bind(SocketAddress endpoint, int backlog){
......
InetSocketAddress epoint = (InetSocketAddress) endpoint;
try {
......
//Socket绑定对端点并监听
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
......
}
深入bind方法,最终至static native void bind0(int fd, InetAddress localAddress, int localport,boolean exclBind) 或native void socketBind(InetAddress address, int port, boolean exclBind)
深入listen方法,最终至static native void listen0(int fd, int backlog) 或 native void socketListen(int count)
3.2)监听[public Socket accept()],等待客户端的连接, 跟踪核心过程方法->
public Socket accept() throws IOException {
.....
//创建可被接收,监听的Socket(客户端)对象
Socket s = new Socket((SocketImpl) null);
implAccept(s);//监听Socket
return s;
}
3.3)数据通信:调用Socket类的getInputStream()接收客户端数据,且调用getOutputStream()向客户端回复信息
3.4)Closes this socket
public void close() throws IOException {
synchronized(closeLock) {
if (isClosed())
return;
if (created)
impl.close();
closed = true;
}
}
UDP部分-暂不研究
上一篇: 两道算法题-打家劫舍-逆波兰表达式
下一篇: jdk8的配置
推荐阅读
-
.Net Core 3.0后台使用httpclient请求网络网页和图片_使用Core3.0做一个简单的代理服务器
-
JDK8 网络Net包研究(一)
-
有一个开源的项目Cindy,现在不知道为什么没有更新了,作者放弃了吗 HPCVSJava网络协议.net
-
用ASP.NET Core2重写了一款网络考试培训的免费软件
-
发现新大陆:一个最简单的破解SSL加密网络数据包的方法
-
粘包处理现象及其解决方案——基于NewLife.Net网络库的管道式帧长粘包处理方法
-
ASP.NET网络编程学习第一步:清晰概念
-
一个.Net网络验证程序的破解
-
Flex与.NET互操作(一):基于Socket的网络连接
-
php闭包语法研究一