一、概述
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
1. Java网络编程概述
- Java是Internet上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。
- Java提供网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本机安装系统中里,由JVM进行控制。并且Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
- java.net 包中有专门的类和接口,它们提供低层次的通信细节。可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节
2. 网络基础
- 计算机网络:
- 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息共享硬件、软件、数据信息等资源。
- 网络编程的目的:直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。
- 实现网络通信需要解决的两个问题:
- 问题一:如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
- 问题二:找到主机后如何可靠高效地进行数据传输
二、网络通讯要素
-
IP和端口号(解决问题一)
-
网络通信协议:TCP/IP协议(应用层、传输层、网络层、物理+数据链路层) (解决问题二)
网络通信协议
说明:
- OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广
- TCP/IP参考模型(TCP/IP协议):事实上的国际标准
通信过程
在网络体系结构中网络通信的建立必须是在通信双方的对等层进行,不能交错。 在整个数据传输过程中,数据在发送端时经过各层时都要附加上相应层的协议头和协议尾(仅数据链路层需要封装协议尾)部分,也就是要对数据进行协议封装,以标识对应层所用的通信协议。
1. 通讯要素一:IP和端口号
1.1 IP地址
-
唯一的标识 Internet 上的计算机(通信实体)
-
在Java中使用
InetAddress类
代表IP -
本地回送地址(hostAddress):127.0.0.1 ==> 对应着主机名(hostName):localhost
-
IP地址分类方式1:
IPv4
和IPv6
; 万维网 和 局域网- IPV4: 32 位(4个字节组成),4个0~255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。以点分十进制表示,如192.168.0.1
- IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开。文本格式为 xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx,其中每个 x 都是十六进制数,表示 4 位。可省略前导零。如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
-
IP地址分类方式2:
公网地址 (万维网使用)
和私有地址(局域网使用)
。192.168.开头的就是私有地址,范围即为192.168.0.0~192.168.255.255,专门为组织机构内部使用。 -
特点:不易记忆。所以需要用到域名。
-
域名: 通过域名解析服务器将域名解析为IP地址,如:百度网 www.baidu.com
-
域名解析:域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。如下图:
1.2 端口号
用于标识正在计算机上运行的进程(程序)。
-
要求:不同的进程有不同的端口号
-
范围:被规定为一个 16 位的整数, 0~65535。
-
分类:
-
公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,TeInet占用端口23)。
-
注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。
-
动态私有端口:49152~65535。
-
-
端口号与IP地址的组合得出一个网络套接字:Socket。
1.3 InetAddress类
JDK中提供的一个与IP地址相关的类,此类的一个对象就代表着一个具体的IP地址。(用于封装一个IP地址)
1.3.1 实例化
-
getByName(String host) :在给定主机名的情况下确定主机的 IP 地址。
- 根据域名获取:如果参数为null,获得的是本机的IP地址
- 根据ip获取
-
getLocalHost():返回本地主机。
1.3.2 常用方法
- getHostName():获取IP 地址的主机名。
- getHostAddress():返回 IP 地址字符串
public class InetAddressTest {
public static void main(String[] args) {
try {
/**getByName()**/
//File file = new File("hello.txt");
InetAddress inet1 = InetAddress.getByName("192.168.11.28");
System.out.println(inet1);// /192.168.11.28
InetAddress inet2 = InetAddress.getByName("www.baidu.com");
System.out.println(inet2);// www.baidu.com/14.215.177.38
InetAddress inet3 = InetAddress.getByName(null);
System.out.println(inet3);// localhost/127.0.0.1
InetAddress inet4 = InetAddress.getByName("127.0.0.1");
System.out.println(inet4);// /127.0.0.1
//获取本地ip
InetAddress inet4 = InetAddress.getLocalHost();
System.out.println(inet4);// 如:DESKTOP-UOQFA0D/192.168.52.1
//getHostName()
System.out.println(inet2.getHostName());//www.baidu.com
//getHostAddress()
System.out.println(inet2.getHostAddress());//14.215.177.38
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
2. 通信要素二:网络通信协议
计算机与网络设备要相互通信,双方就必须基于相同的方法。比如,如何探测到通信目标、由哪一边先发起通信、使用哪种语言进行通信、怎样结束通信等规则都需要事先确定。不同的硬件、操作系统之间的通信,所有的这一切都需要一种规则。而我们就把这种规则称为协议(protocol)
。
网络通信协议:计算机网络中实现通信必须要有一些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。
而计算机网络通信设计内容很多,太复杂,如指定源地址和目的地址,加密解密,压缩/解压缩,差错控制,流量控制,路由控制等。如何实现如此复杂的网络协议呢?(通信协议分层的思想)
通信协议分层的思想:在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式就是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系
。各层互不影响,利于系统的开发和拓展。
2.1分层模型
2.2 TCP/IP协议簇
-
TCP/IP协议簇
是Internet的基础,也是当今最流行的组网形式。TCP/IP
是一组协议的代名词,是互联网相关的各类协议簇的总称。其中包括:SLIP协议、PPP协议、IP协议、ICMP协议、ARP协议、TCP协议、UDP协议、FTP协议、DNS协议、SMTP协议等。 -
TCP/IP以其两个主要协议:
TCP协议 (传输控制协议)
和IP协议 (网路互联协议)
而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。 -
TCP/IP协议
并不完全符合OSI的七层参考模型。而从更加实用和高效的角度出发,采用了4层的层级结构,即物理链路层、网络层、传输层和应用层
。- 链路层:负责封装和解封装IP报文,发送和接受ARP/RARP报文等。
- 网络层:负责路由以及把分组报文发送给目标网络或主机。
- 传输层:负责对报文进行分组和重组,并以TCP或UDP协议格式封装报文。
- 应用层:负责向用户提供应用程序,比如HTTP、FTP、Telnet、DNS、SMTP等。
-
TCP/IP 中有两个具有代表性的传输层协议,分别是 TCP 和 UDP。
2.3 TCP和UDP的区别
TCP协议:
TCP是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称TCP / IP。
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用 “三次握手” 方式,点对点通信,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端。
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
UDP协议:
UDP是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内
- 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
- 可以广播发送
- 发送数据结束时无需释放资源,开销小,速度快
总结:
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
- TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务。
- 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
- 对数据准确性要求高,速度可以相对较慢的,可以选用TCP
2.4 TCP三次握手和四次挥手
2.4.1 TCP报文格式
-
序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。
-
确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
-
确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效
-
同步SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。
-
终止FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接
说明:ACK、SYN和FIN这些
大写的单词表示标志位
,其值要么是1,要么是0,而ack、seq小写的单词表示序号。
字段 | 含义 |
---|---|
URG | 紧急指针是否有效。为1,表示某一位需要被优先处理 |
ACK | 确认号是否有效,一般置为1。 |
PSH | 提示接收端应用程序立即从TCP缓冲区把数据读走。 |
RST | 对方要求重新建立连接,复位。 |
SYN | 请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设置为1 |
FIN | 希望断开连接。 |
2.4.2 TCP状态转移解释
状态 | 描述 |
---|---|
CLOSED | 阻塞或关闭状态,表示主机当前没有正在传输或者建立的链接 |
LISTEN | 监听状态,表示服务器做好准备,等待建立传输链接 |
SYN RECV | 收到第一次的传输请求,还未进行确认 |
SYN SENT | 发送完第一个SYN报文,等待收到确认 |
ESTABLISHED | 链接正常建立之后进入数据传输阶段 |
FIN WAIT1 | 主动发送第一个FIN报文之后进入该状态 |
FIN WAIT2 | 已经收到第一个FIN的确认信号,等待对方发送关闭请求 |
TIMED WAIT | 完成双向链接关闭,等待分组消失 |
CLOSING | 双方同时关闭请求,等待对方确认时 |
CLOSE WAIT | 收到对方的关闭请求并进行确认进入该状态 |
LAST ACK | 等待最后一次确认关闭的报文 |
2.4.3 TCP三次握手
三次握手,就是TCP建立连接的过程。这个连接必须是一方主动打开,一方被动打开。
(1)为什么要有“三次握手” ?
前两次握手是在建立连接,是必须要的。
【通俗解释】:
首先我们假设 A和B 是本次进行通信的双方。 而发一次信息就代表着一次握手。
-
一次握手: A 给 B 发微信语音聊天,在吗?能听到我讲话吗?
-
第二次握手:B 收到了 A 发来的微信语音通话,然后对A说:嗯,人在的,我能听见你说的话,你能听得见我说话吗?
-
第三次握手: A收到了B的信息,然后说可以的,我要给你发信息啦!
然后就开始愉快的聊天了。
在三次握手之后,A和B都能确定这么一件事: 我说的话,你能听到; 你说的话,我也能听到。这样,就可以开始正常通信了。
-
第一次握手:Client什么都不能确认;Server确认了对方发送正常
-
第二次握手