目录
TCP/IP 协议族
TCP/IP 是由一系列协议组成的网络分层模型。
TCP/IP 四层结构模型
TCP/IP 协议族按层次从上到下依次分为:应用层、传输层、网络层、数据链路层。
- 应用层(Application Layer) 决定了向用户提供应用服务时通信的活动。包括 FTP(文件传输协议) 、DNS (域名系统)、HTTP协议 等。
- 传输层(Transport Layer) 负责两台计算机之间的数据传输。包括:TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Data Protocol,用户数据报协议)。
- 网络层(Internet Layer) 用来处理在网络上流动的数据包。该层规定了数据包的传输路线。包括 IP 协议。
- 数据链路层(Link Layer) 用来处理连接网络的硬件部分。包括:控制操作系统、硬件的设备驱动、NIC(Network Interface Card,网络适配器,即网卡),及光纤等物理可见部分。硬件上的范畴均在链路层的作用范围之内。
IP (Internet Protocol) VS IP地址
“IP” 和 “IP地址” 是两个概念。
- IP(Internet Protocol):网际协议位于网络层。“IP” 是一种协议的名称。IP 协议的作用是把各种数据包传送给对方,而要确保确实传送到对方那里,则需要满足各类条件。其中两个重要的条件是 IP 地址和 MAC (Media Access Control Address)地址。
- IP 地址:指明了结点被分配到的地址,MAC 地址是指网卡所属的固定地址。IP 地址可以和 MAC 地址进行配对。IP 地址可变换,但 MAC 地址基本上不会变更。
TCP/IP 为什么要分层
要想把数据通过网络从一个设备发送到另一个设备,该数据传输会经过 n 个网络节点。
因为网络是不稳定的,中间任何一个节点异常就会导致数据传输失败。
如果需要重传数据,并且数据量比较大,整个数据重传就会造成资源浪费。于是就需要把数据分块,这样如果某块数据传输失败,只需要重传这个数据块就可以了,节省了不必要的时间和资源浪费。
如果不需要重传数据,一次性传输的数据量较大时,一旦失败整个数据就丢失了;而如果把数据分块进行传输,数据丢失的量就会减少,增加了传输成功的数据量。
我们要发送网络数据的场景有很多,如浏览网页、普通的接口请求、发送邮件等等,由于场景不同所以通信协议也不尽相同,这就是应用层定义了各种通信协议。
所有应用层协议的一个共同点就是都需要对数据进行分块传输,如果每个协议都去实现分块传输的逻辑,就比较麻烦也会造成逻辑冗余,于是就将分块的逻辑单独抽离,这就是传输层。
因为传输层有 TCP(面向连接)和 UDP(非面向连接)两种协议,它们都需要将数据分块后,确定传输路线,于是就把确定传输路线的逻辑单独抽离,这就是网络层,该层规定了数据包的传输路线。
最后,网络层将数据传给数据链路层,该层用来处理连接网络的硬件部分。
这样,将数据的发送的四个阶段分别交给相应的层来处理,每个层只负责自己的工作。
如果我们把以上四层模型用 UML 类图表示它们之间的关系及分层结构,大概是下面的样子。
感悟
作为一个合格的工程师,具备功能分层与分模块解耦的意识是必不可少的。
如果真正用代码实现的话,还可以使用上责任链模式,将数据一层层传递与处理。Okhttp 使用责任链的设计模式跟 TCP/IP 的分层设计有异曲同工之妙啊!!!
TCP 连接
TCP 是有状态的(不需要每次发送数据都告诉对方自己是谁),HTTP 是无状态的。
什么是建立连接?
通信双⽅建⽴确认「可以通信」,不会将对⽅的消息丢弃,即为「建⽴连接」。
TCP 建立连接三次握手
- 目标:为了准确无误地把数据送达目标处。
- 方法:TCP 协议采用三次握手策略。
- 介绍:TCP 将数据包发送之后,一定会向对方确认是否成功送达。握手过程中使用了 TCP 的标志(flag)—— SYN(synchronize)和 ACK (acknowledgement)。
- 过程:发送端首先发送一个带有 SYN 标志的数据包给对方请求发送消息;接收端收到后,回传一个带有 SYN/ACK 标志的数据包表示已经成功接收到消息并请求发送消息;发送端收到带有 SYN/ACK 的数据包后再发送一个带有 ACK 标志的数据包,代表“握手”结束。
- 第一次握手:客户端发送 SYN(syn = j) 包到服务器,并进入 SYN_SEND 状态,等待服务器确认。
- 第二次握手:服务端收到 SYN 包,必须确认客户端的 SYN (ack = j + 1),同时自己也发送一个 SYN 包(syn = k),即 SYN + ACK 包,此时服务端进入 SYN_RECV 状态。
- 第三次握手:客户端收到服务器的 SYN + ACK 包,向服务器发送确认包 ACK(ack = k + 1),此包发送完毕,客户端和服务器端进入 ESTABLISHED 状态,完成三次握手。
其实这和两个人的聊天场景非常相似:
A: 在吗?(SYN)
B: 我在呢,你还在吗?(SYN/ACK)
A: 我还在,我们开始聊天把。(ACK)握手成功
- 异常处理:如果在握手过程中某个阶段莫名中断,TCP 协议会再次以相同的顺序重新发送数据包。
还是和聊天场景一样
A:在吗?(SYN)
……n 分钟过去了,B 还是没有回应,握手失败
A: 在吗?(SYN)
B: 在呢,你还在吗?(SYN/ACK)
…… 又过了 n 分钟,A 可能因为各种原因没收到,或没及时查看 B 的回复,握手失败,此时 B 认为 A 不需要和自己聊天了,去忙自己的事情了
A: 在吗?(SYN)
B: 在呢,你还在吗?(SYN/ACK)
A: 我还在,我们开始聊天把。(ACK)握手成功
TCP 关闭连接四次挥手
中断链接可以是 Client 端,也可以是 Server 端。
假设 Client 端发起中断连接请求:
- Client 发送 FIN 报文,意思是说”我 Client 端没有数据要发给你了,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。”
- Server 端接到 FIN 报文后,先发送 ACK,告诉 Client 端,”你的请求我收到了,但是我还没准备好,请你继续等我的消息”。这个时候 Client 端就进入FIN_WAIT 状态,继续等待 Server 端的FIN 报文。
- 当 Server 端确定数据已发送完成,则向 Client 端发送 FIN 报文,告诉 Client 端,”好了,我这边数据发完了,准备好关闭连接了”。
- Client 端收到 FIN 报文后,就知道可以关闭连接了,但是他还是不相信网络,怕 Server 端不知道要关闭,所以发送 ACK 后进入TIME_WAIT 状态,如果 Server 端没有收到 ACK 则可以重传。Server 端收到 ACK 后,就知道可以断开连接了。Client 端等待了 2MSL 后依然没有收到回复,则证明 Server 端已正常关闭,那好,我 Client 端也可以关闭连接了。Ok,TCP 连接就这样关闭了!
Socket 套接字很难理解,但是看了下图可能会有助于理解,更多解释点击查看。
长连接
HTTP 连接
Http 连接最显著的特点是客户端每次发送请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
1)在 HTTP 1.0 中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。
2)在 HTTP 1.1 中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。
由于 HTTP 在每次请求结束后都会主动释放连接,因此 HTTP 连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。
通常的做法是即使不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”;若客户端长时间无法收到服务器的回复,则认为网络已经断开。
为什么要有长连接
因为移动⽹络并不在 Internet 中,⽽是在运营商的内⽹,并不具有真正的公⽹ IP,因此当某个 TCP 连接在⼀段时间不通信之后,⽹关会出于⽹络性能考虑⽽关闭这条 TCP 连接和公⽹的连接通道,导致这个TCP 端⼝不再能收到外部通信消息,即 TCP 连接被动关闭。假如:服务端一段时间后需要向客户端主动发送消息(推送),那么客户端就收不到了。因此需要长连接来解决这个问题。
⻓连接的实现⽅式
⼼跳。
即在⼀定间隔时间内,使⽤ TCP 连接发送超短⽆意义消息来让⽹关不能将⾃⼰定义为「空闲连接」,从⽽防⽌⽹关将⾃⼰的连接关闭。