一、计算机网络体系结构
计算机网络体系结构分为3种:OSI体系结构、TCP / IP四层体系结构、TCP / IP五层体系结构:
三种体系结构只是对网络结构进行抽象划分的方式不同,主要思想和层次结构是一致的。其中,OSI七层协议体系偏理论知识,TCP / IP体系结构偏TCP/IP协议簇比较常用。TCP / IP四层体系结构中的"网络接入层"对应着TCP / IP五层体系结构中的"数据链路层"和"物理层"。
1.1 协议层
- 应用层:为用于通信的应用程序和用于消息传输的底层网络提供接口。
- 表示层:为在应用进程之间传送的信息提供表示方法的服务,它只关心信息发出的语法和语义。
- 会话层:利用传输层提供的服务,使应用建立和维持会话,并能使会话获得同步。
- 传输层:为源主机和目标主机之间提供透明的数据传输,使高层服务用户在相互通信时不必关心通信子网实现的细节。
- 网络层:管理网络中的数据通信,将数据设法从源端经过若干个中间节点传送到目的端,具体功能包括寻址和路由选择、连接的建立、保持和终止等。
- 数据链路层:定义了在同一局域网内部点到点的单个链路上如何传输数据,通过MAC寻址把数据传输到目的节点。
- 物理层:为设备之间的数据通信提供传输媒体及互连设备。当采用复用技术时,一条物理链路上可以有多条数据链路。
其中,应用层常见的协议有HTTP、DNS等,TCP / IP体系结构中比较重要的是传输层(常见的协议有TCP、UDP)、网络层(常见的协议有IP、ARP等)。
1.2 封装过程
在发送方发送数据时,每经过一个协议层,会在数据前/后拼接该协议层的信息(比如网络层会拼接IP首部,IP首部包含了源IP地址和目的IP地址等):
1.3 解封过程
对应地在接收方收到数据时,每经过一个协议层,会将数据中对应的协议信息取出来,直到应用层获得应用数据:
二、网络分析工具
结合网络分析工具,可以更好地理解网络请求流程,常用的网络分析工具有以下几种。
2.1 Charles
Charles可用来分析PC、移动设备上的HTTP、HTTPS网络请求(类似的还有Fiddler、proxyman等)。例如可以在Timing
下看到HTTPS网络请求的几个主要阶段如下:
Charles的抓包原理是中间人攻击(Man-in-the-middle attack,缩写:MITM),即客户端与charles、charles与服务端分别建立独立连接,charles对于客户端是server,对于服务端是client(使用charles前需要在手机上安装charles证书,就是为了可以在客户端与charles间建立连接)。
2.2 ChromeDevTools
ChromeDevTools是Chrome浏览器提供的开发工具,可用来分析Chrome浏览器发送的HTTP/HTTPS请求,以及Android设备WebView发送的HTTP/HTTPS请求的网络信息(适用范围有限,不支持对非WebView的请求进行抓包)。
2.2.1 ChromeDevTools
在Chrome浏览器中点击设置
- 更多工具
- 开发者工具
进入ChromeDevTools,然后输入www.baidu.com
,即可在network
一列下看到请求时的网络信息如下所示:
可以看到,在单个HTTPS请求的过程经历了三大阶段,详细可参考官方文档:
资源调度 - Resource Scheduling
:排队等待浏览器空闲时调度;建立连接 - Connection Start
:主要经历了’DNS查找(DNS Lookup)'、‘初始连接(Intial connection)’、‘SSL’ 等过程,其中初始连接包括了TCP握手、SSL协商;请求/响应 - Request/Response
:连接建立后,先由客户端发送请求数据,然后服务端返回响应内容。
2.2.2 Android设备
在Chrome浏览器输入chrome://inspect/#devices
即可看到Android设备当前已经打开的WebView页面:
在点击inpect
后,在WebView内点击搜索框,即可看到点击时的网络信息如下所示(与2.2.1小节类似,暂不详细介绍):
2.3 WireShark
WireShark是一个功能强大的网络包分析软件,支持Windows、MacOS平台。如下图所示,可以看到详细的网络包过程(DNS、TCP等):
WireShark暂不支持Android平台,对于Android设备可尝试以下方法:
- 在PC端开热点,手机连接热点,然后在WireShark抓取对应热点的网络进行分析;
- 结合tcpdump命令在Android设备上抓包并导出文件,然后在WireShark上进行分析;
- 结合pcap应用在Android设备上抓包并导出文件,然后在WireShark上进行分析。
2.3.1 tcpdump
tcpdump是一个开源命令行工具,常用来拦截和分析TCP/CP数据包,并且支持通过and、or、not等语句过滤特定的网络层、协议、主机等,帮助开发者分析网络请求。tcpdump支持将抓取结果保存为PCAP文件,PCAP文件是常用的数据报存储格式。WireShark可以将一段时间的网络数据保存为PCAP文件,也可以打开PCAP文件。运行tcpdump需要手机root权限,使用方式如下:
# 把网络数据报导出到bc_network_file.pcap文件
>adb shell tcpdump -nnvXSs -w bc_network_file.pcap
如果Android设备没有tcpdump,可从androidtcpdump上下载。
2.3.2 PCAP抓包应用
对于Android,还可使用PCAPdroid应用(或其它类似功能APP)抓包并将结果保存为PCAP文件。PCAPdroid应用截图如下所示:
可以看到,在使用的过程中,"连接"一列记录着网络使用情况:
在将PCAP文件导出并用WireShark打开后,可以看到网络数据包的传输情况如下图所示(记录着DNS查询、TCP握手、TLS等过程):
三、应用层
如第一章所示,应用层常见的协议有HTTP、HTTPS、DNS等。日常开发中在浏览器中访问或者Android开发中使用HttpsURLConnection访问" https://www.baidu.com" 时,都是使用了应用层的HTTPS协议。在真正发送HTTPS请求数据前,一般会由浏览器或者HttpsURLConnection先进行一次DNS请求,DNS请求是为了获得域名所对应的IP地址。
// HttpURLConnection默认使用系统的DNS服务进行域名解析
InetAddress ip2= InetAddress.getByName("www.baidu.com");
3.1 DNS
域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用UDP端口53。例如 “www.baidu.com” 是百度的域名便于人们记忆&使用,而 “http://110.242.68.4” 是域名对应的IP地址(同样可以直接访问,但相比域名不方便记忆)。
3.1.1 域名服务器
域名服务器就是装有域名系统的主机。每个域名从后往前依次是顶级域名、二级域名、三级域名…等,例如 “www.baidu.com” 的顶级域名是com、二级域名是baidu、三级域名是www。对应地,有根域名服务器、顶级域名服务器、辅助域名服务器等分别存放着顶级域名、二级域名等。
3.1.2 DNS解析过程
以下是请求 “www.baidu.com” 时的DNS解析过程(暂不考虑DNS缓存的情况),先从网络服务提供商ISP提供的DNS服务解析出域名所对应的IP地址后,再向该IP地址发送HTTP请求:
3.1.3 DNS缓存
结合2.3小节的WireShark来看DNS网络包如下所示,序号2是client发送DNS请求,序号3是server返回DNS结果:
上图可以看到,应用层的DNS协议在传输层采用UDP协议、网络层采用IP协议,并拼接了UDP首部、IP首部等信息。另外从下图的DNS返回结果可以看到 “Time to live” 是20min,客户端可以选择将DNS保存在本地缓存中,这样在TTL有效期内,再次访问相同域名时可以先从本地DNS缓存中查询,省去了请求DNS服务的过程(DNS缓存一般由操作系统、浏览器、ISP等完成,Chrome浏览器的DNS缓存见:chrome://net-internals/#dns )。
3.1.4 HTTPDNS
HTTPDNS是对DNS解析的另一种实现方式。不同于传统的使用DNS协议来完成域名解析,HTTPDNS采用HTTP协议完成域名解析。这种方式常用来作为DNS优化手段,绕开运行商的localDNS,来避免运营商DNS劫持或运营商DNS故障等问题。例如以下是百度HTTPDNS的原理:
3.2 HTTP
HTTP(Hyper Text Transfer Protocol),即超文本传输协议。HTTP是一个基于TCP/IP 通信协议来传递数据(HTML 文件、图片文件、查询结果等)的应用层协议。
以"Android网络开发(一、Socket通信&HTTP通信)"中HttpURLConnection访问 “http:www.baidu.com” 为例,用WireShark抓包结果如下图所示,可以看到HttpURLConnection首先通过DNS请求获得域名对应的IP地址(参考3.1.2小节),然后通过TCP三次握手建立连接,最后发送HTTP数据包进行通信:
3.2.1 HTTP请求
HTTP请求由4部分内容组成:
HTTP请求组成 | 内容 |
---|---|
请求方法(Request Method) | GET、POST、HEAD、PUT、DELETE等 |
请求地址(Request URL) | 即要请求的服务端URL地址,如 “www.baidu.com” |
请求头(Request Headers) | 服务器需要的附加信息,比较常用的有Connection、Cookie、User-Agent、Referer、Content-Type、Accept-encoding等 |
请求体(Request Body) | 请求体一般是POST请求方式所携带的数据,Content-Type即表示请求体的类型(txt、json、form、protobuf等);对于GET请求方式请求体为空 |
例如WireShark可以看到例子中的HTTP请求组成内容如下(GET请求):
3.2.1 HTTP响应
HTTP响应由3部分内容组成:
HTTP响应组成 | 内容 |
---|---|
响应状态码(Response Status Code) | 表示服务器的响应状态,如 200表示请求成功,404表示页面未找到,500表示服务器错误。 |
响应头(Response Headers) | 服务器对请求的应答信息,如 Content-Type、Content-Encoding、Set-Cookie、Server 等 |
响应体(Response Body) | 响应的正文数据;响应头的Content-Type表示响应体的类型,例如HTML网页的Content-Type是"text/html"、json数据的Content-Type是"application/json"等 |
例如WireShark可以看到例子中的HTTP响应内容如下:
3.2.3 连接复用
HTTP持久性连接(也称为 HTTP keep-alive或 HTTP 连接复用)是一种概念,允许单个 TCP 连接发送和接收多个 HTTP 请求/响应,而不是为每个请求/响应对打开新连接。在HTTP/1.0中默认不会启用Keep-Alive,客户端请求必须带着Connection:Keep-Alive头部来建立持久性连接。HTTP/1.1中默认就是持久连接,客户端可以在请求头添加Connection:close来关闭持久连接。不过可能存在服务端无法处理持久性连接的情况。
例如,如果用"Android网络开发(二、okhttp&retrofit)"中okhttp的方式连续访问两次baidu,结果如下(可以看到第二次HTTP请求前没有TCP三次握手建立连接的过程):
但如果用"Android网络开发(一、Socket通信&HTTP通信)"中HttpURLConnection的方式访问,则可以在请求结束后就看到TCP连接释放的过程(Android 8.1设备,其他版本Android设备可能不一样),如下图所示:
3.2.4 HTTP各版本区别
- HTTP / 1.0:默认不支持持久性连接,每个HTTP请求之前都需要建立连接,结束之后关闭连接;
- HTTP / 1.1:默认支持持久性连接,不过存在队头阻塞的问题(共用同一个TCP连接的HTTP请求需要按顺序处理,如果队头的HTTP连接未传输完则其之后的HTTP连接会一直等待);
- HTTP / 2.0:引入帧/流id解决了HTTP层的队头阻塞问题,不过没有解决TCP层的队头阻塞问题(TCP队头阻塞一般发生在包丢失的情况,相比HTTP的队头阻塞出现概率小很多);支持头部压缩算法HPACK(客户端和服务端各自维护一份索引表);
- HTTP / 3.0:传输层协议由TCP改为QUIC协议(QUIC协议中也有帧/流id的概念且支持加密,所以HTTP3中就没有了HTTP2中的帧/流等概念),解决了TCP的队头阻塞问题;
3.3 HTTPS
HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer)是在HTTP下加入SSL层,理论上SSL/TLS协议位于网络体系结构中的传输层。
常用的TLS协议的基本过程如下:
- 客户端发送ClientHello,消息中包含客户端的TLS版本、客户端随机数、可用的加密算法、压缩算法等;
- 服务端返回ServerHello,消息中包含服务端的TLS 版本、服务端所选择的加密和压缩算法、服务端公开证书(由CA机构签发,证书中包含公钥、域名范围等信息,用于客户端验证身份);
- 客户端验证服务端证书是否可信,如果可信则生成一串伪随机数(后面用来生成对称密钥),并使用服务器的公钥进行加密,然后发送给服务端;
- 服务端使用自己的私钥解密上一步客户端发送的伪随机数,然后使用这串随机数生成自己的对称主密钥;
- 客户端发送Finished,使用对称密钥加密这次通讯的一个hash值;
- 服务端根据对称密钥解密hash值,如果相对应,则向客户端发送一个Finished,安全连接建立结束;
- 在后面的通信中,双方使用对称密钥进行加密解密。
对应地,用WireShark可以看到HTTPS请求的流程如下(实际流程根据协议版本、客户端/服务端具体实现方式等有所差异):
四、传输层
4.1 TCP
TCP协议通过校验和、序列号与确认应答、超时重传、连接管理、流量控制、拥塞控制等机制来保证可靠传输。
4.1.2 三次握手
当客户端需要建立TCP连接时,通过"三次握手"的方式建立TCP连接。"三次握手"就是指这个过程客户端和服务器总共发送3个包:
- 第一次握手(SYN=1, seq=x):客户端发送SYN包(包含SYN标志位为1、服务器的端口、客户端初始序号x)。发送完毕后,客户端进入
SYN_SEND
状态。 - 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)):服务器返回确认包(ACK)应答包(SYN标志位和 ACK标志位均为1,同时将确认序号ACKnum=x+1,以及服务端的序列号y)。发送完毕后,服务器端进入
SYN_RCVD
状态。 - 第三次握手(ACK=1,ACKnum=y+1)):客户端再次发送确认包(ACK),ACK 标志位为1,确认序列号为ACKnum=y+1。发送完毕后,客户端进入
ESTABLISHED
状态,当服务器端接收到这个包时,也进入ESTABLISHED
状态,TCP 握手结束。
从WireShark中同样可以看到TCP"三次握手"的过程:
4.1.2 四次挥手
在TCP连接使用完毕后,通过"四次挥手"的方式关闭TCP连接。"四次握手"就是指这个过程客户端和服务器总共发送4个包:
- 第一次挥手(FIN=1,seq=x):客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。发送完毕后,客户端进入
FIN_WAIT_1
状态。 - 第二次挥手(ACK=1,ACKnum=x+1):服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。发送完毕后,服务器端进入
CLOSE_WAIT
状态,客户端接收到这个确认包之后,进入FIN_WAIT_2
状态,等待服务器端关闭连接。 - 第三次挥手(FIN=1,seq=y):服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。发送完毕后,服务器端进入
LAST_ACK
状态,等待来自客户端的最后一个ACK。 - 第四次挥手(ACK=1,ACKnum=y+1):客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入
TIME_WAIT
状态,等待可能出现的要求重传的 ACK 包。服务器端接收到这个确认包之后,关闭连接,进入CLOSED
状态。客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入CLOSED
状态。
虽然四次挥手是规范的关闭方式,但是实际场景下,因为客户端/服务端的具体实现方式不同等原因,并不一定能完整地执行完四次挥手。例如客户端关闭方式(如粗暴关闭时的RST报文等)、TCP延迟确认机制(服务端的ACK+FIN合并为一个报文)、TCP连接keep-alive超时等情况,都会看到连接关闭的过程不同于规范的四次挥手,如下图两个例子(暂不深入分析):
4.2 UDP
UDP是一个简单的传输层协议,应用层的DNS协议在传输层就采用了UDP协议。UDP和TCP区别主要有:
- UDP不保证可靠传输。而TCP通过校验和、序列号与确认应答、超时重传、连接管理、流量控制、拥塞控制等机制保证可靠传输。
- UDP是无连接的,而TCP需要先经过三次握手建立连接。
- UDP支持多播和广播。
The End
欢迎关注我,一起解锁更多技能:BC的掘金主页~💐 BC的CSDN主页~💐💐
wireshark文档:https://www.wireshark.org/docs/wsug_html_chunked/
协议栈参考文档:https://www.cnblogs.com/mrlayfolk/p/11965347.html
tcpdump参考文档:https://cizixs.com/2015/03/12/tcpdump-introduction/
Chorme网络分析工具:https://developer.chrome.com/docs/devtools/network/?utm_source=devtools&utm_campaign=2019Q1
PCAPdroid应用下载:https://f-droid.org/packages/com.emanuelef.remote_capture/
百度HTTPDNS:https://juejin.cn/post/6844904032318832647
计算机网络参考文档:https://github.com/HIT-Alibaba/interview