网络协议底层原理(七):传输层
一、传输层
-
传输层
位于五层模型中的第二层,接受应用层
传递过来的数据包,拼装上传输层首部,然后一起打包传递给网络层
,如下图所示:
数据传输的过程
-
-
- 我们知道
网络层
提供了把数据包从一台主机传输到另一台主机的能力,那我们为什么还需要传输层
呢?
- 是因为
网络层
提供的是尽力而为的服务
,也就说网络层提供的服务并不可靠,可能会丢包,也可能重复,甚至传输中断(例如路由器可能崩溃或者传输线路中断时),所以传输层
必须足够健壮
来解决网络层不可靠,不稳定的问题,比如说传输层可检测到包丢失、损坏、乱序等差错情况,并采取相应措施;或者当数据传输过程中网络连接中断,传输层可与远程传输实体建立一新的网络连接,在中断处继续数据的传输。
- 我们知道
- 那么传输层是如何实现这些能力的呢,其实是靠传输层首部存放的数据来保证的,传输层采用的协议不同,传输层的首部格式也不相同
- 传输层有两个常见的协议:
TCP 和 UDP
,TCP全称是Transmission Control Protocol
,意思是传输控制协议;UDP全程是User Datagram Protocol
,意思是用户数据报协议,区别如下所示:
TCP和UDP的区别
- 传输层有两个常见的协议:
- TCP传输数据的时候会先三次握手建立链接,然后传输数据,然后四次挥手释放链接;而UDP传输数据是一股脑的发出去,不管对方收到没有收到,只是尽最大努力交付,可能会丢包,所以说UDP是无连接的;
二、UDP的数据格式
-
UDP是无连接的
,减少了建立和释放连接的开销,而且UDP是尽最大能力交付
,不保证可靠交付,因此不需要维护一些复杂的参数,所以UDP首部只有8个字节
(TCP的首部至少20个字节),如下图所示:
UDP的数据格式
-
- UDP由于不用保证可靠传输,所以UDP的首部是比较简单的,包括:
源端口号、目标端口号、UDP长度、UDP校验和
这四个字段,如下所示:
采用UDP协议的传输层.png
- UDP由于不用保证可靠传输,所以UDP的首部是比较简单的,包括:
-
补充知识:传输层的首部包含了端口号,也就说传输层会把数据包传递给某个端口,如下所示就是不同协议采用的默认端口号,不同的应用层协议所采用的传输层协议及端口号也不同
左边:应用层协议 ; 右边:对应的传输层协议及端口号
-
三、TCP的数据格式
- TCP由于是
可靠传输
,所以TCP的首部
比较复杂,如下所示,传输层
把TCP首部+数据部分
打包发给网络层
,
TCP的首部格式
- TCP由于是
-
- 我们来一一讲解
TCP首部
所有字段的含义:
-
源端口号:也就是发送方的端口号
-
目的端口:也就是接受方的端口号
-
序号(Sequence Number)
:占4字节
,我们知道在传输过程的每一个字节都会有一个编号,在建立连接后,序号代表:这一次传给对方的TCP数据部分
的第一个字节的编号
-
确认号(Acknowledgment Number)
:占4字节
,在建立连接后,确认号代表:期望
对方下一次传过来的TCP数据部分
的第一个字节的编号
-
窗口(Window)
:占2字节
, 这个字段有流量控制功能,用以告知对方下一次允许发送的数据大小(字节为单位) -
标志位
:一共有六个标志位,不同标志位的含义不相同,如下所示:-
URG(Urgent)
:当URG=1
时,紧急指针字段才有效。表明当前报文段中有紧急数据,应优先尽快传送 -
ACK(Acknowledgment)
: 当ACK=1
时,确认号
字段才有效 -
RST(Reset)
:当RST=1
时,表明连接中出现严重差错,必须释放连接,然后再重新建立连接 -
SYN(Synchronization)
: 当SYN=1、ACK=0
时,表明这是一个建立连接的请求,若对方同意建立连接,则回复SYN=1、ACK=1
-
FIN(Finish)
:当FIN=1
时,表明数据已经发送完毕,要求释放连接
-
- 我们来一一讲解
-
- 序号、确认号的作用
-
(1).
序号Seq
就是:当前这个包的第一个字节在总包中的位置,例如Seq=1
就代表是第一个字节,Seq = 1420
就代表是第1420个字节 -
(2).
确认号Ack
就是:确认收到了Ack-1
个字节,你下次的序号
应该从确认号
开始,例如:确认号ACK = 1461
就代表我收到了你发送的前1460个字节,你下次从第1461个字节开始发,也就是下次的序号Seq
是1461
的意思 -
(3). 序号会在建立连接的时候生成一个随机值,以后发送的包里都会以
这个随机值
为基准,进行增加,所以我们研究的时候一般看相对值就可以了;(例如:建立链接的时候会生成随机序号:123456,那么后续的序号都会加上这个基准值,增加被模仿的难度)
-
- 传输层
TCP协议
可以实现:可靠传输、流量控制、拥塞控制
等能力,这些能力都是靠TCP头部的这些字段来实现的,如下所示,是这些能力的含义,后面我们会详细讲述:TCP协议是如何利用TCP头部的这些字段,实现这些能力的
-
可靠传输
:由于网络拥塞和错误,数据包可能在传输过程中丢失。TCP协议会通过校验和
等方式,检查数据是否损坏,并向发送者确认是否收到,没收到的话会进行重传 -
流量控制
:有时必须控制两个节点之间的数据传输速率以阻止快速的发送者传输超出接收缓冲器所能承受的数据,造成缓冲区溢出。这也可以通过减少缓冲区不足来提高效率 -
拥塞控制
:拥塞控制可以控制进入到电信网络的流量,最大程度减少网络拥堵
- 传输层
四、TCP的可靠传输
- 刚开始的时候,TCP的
可靠传输
是通过停止等待ARQ协议
来实现的,如下图所示,这个协议很简单,就是每发一次数据包,就要求接受方回复一个确认,然后才发下一个数据包,如果一定时间内没有收到确认,就重发数据包,直到收到确认为止
image.png
- 刚开始的时候,TCP的
- 由于
停止等待ARQ协议
是:发送一个包,等对方确认,然后再发,传输效率太低了,所以后面就做了改进,变成了连续ARQ协议+滑动窗口协议
,这个协议是这样子的:假如窗口是4组,那么发送方会一次性会发送4组数据包,然后接受方只需要回复一次确认
就好了,然后发送方再发送后面的4组数据包,依次类推,如下图所示
image.png
- 由于
-
- 为什么叫做
滑动窗口协议
呢?我们对照上图,来看一下连续ARQ协议+滑动窗口协议
在实际传输中的实现,就知道了:
-
首先,由
接受方
来确认窗口大小
,假设窗口大小是4组,然后发送方
发送一个窗口的数据,也就是把M1~M4四个分组
发送出去; -
然后
接受方
确认,当发送方
收到确认以后,窗口下滑,然后传送M5~M8的四个分组
的数据,依次类推,这就是整个连续ARQ协议+滑动窗口协议
的主体流程 -
了解整个流程以后,是不是觉得叫做窗口很形象易懂呢
- 为什么叫做
- 在TCP通信过程中,如果发送序列中间的某个数据包丢失(比如1、2、3、4、5中的3丢失了) ,TCP会通过重传
最后确认分组的后续分组
(最后确认的是2,会重传3、4、5),这样原先已经正确传输的分组也可能重复发送(比如4、5),降低了TCP性能,为改善上述情况,发展出了SACK(Selective acknowledgment,选择性确认)技术
,这个技术会告诉发送方
哪些数据丢失,哪些数据已经提前收到,使TCP
只重新发送丢失的包(比如3),不用发送后续所有的分组(比如4、5)
- 在TCP通信过程中,如果发送序列中间的某个数据包丢失(比如1、2、3、4、5中的3丢失了) ,TCP会通过重传
-
- 为什么选择在
传输层
就将数据“大卸八块”分成多个段,而不是等到网络层
再分片传递给数据链路层
?
-
因为可以提高重传的性能,需要明确的是: 可靠传输是在传输层进行控制的
-
✓ 如果在
传输层
不分段,一旦出现数据丢失,整个传输层的数据都得重传 -
✓ 如果在
传输层
分了段,一旦出现数据丢失,只需要重传丢失的那些段即可
- 为什么选择在
-
- 可靠传输:一旦发现丢包了,就重传,重传有两种:
-
(1). 超时重传,有个定时器,超过时间还没收到确认,就认为你没收到,就重新发送
-
(2). 快重传,连续收到三个重复确认,就给你重传下一个序号的包
五、TCP的流量控制
-
- 为什么要进行流量控制?
- 如果接收方的
缓存区
满了,发送方还在疯狂着发送数据,接收方只能把收到的数据包丢掉,大量的丢包会极大着浪费网络资源,所以要进行流量控制
- 什么是流量控制? 让发送方的
发送速率
不要太快,让接收方来得及接收处理
- 什么是流量控制? 让发送方的
-
- 流程控制的
原理
是:
-
通过确认报文中
窗口字段
来控制发送方的发送速率 -
发送方的
发送窗口大小
不能超过接收方给出窗口大小
-
当发送方收到接收窗口的大小为0时,发送方就会停止发送数据
- 流程控制的
六、TCP的拥塞控制
- 拥塞控制:防止
过多的数据
注入到网络
中,避免网络中的路由器或链路
过载
- 拥塞控制:防止
-
拥塞控制
是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素,是网络上所有的设备大家共同努力的结果
-
-
3.
image.png拥塞控制
具体实现如下,如下图所示
-
- 我们来对照上图,一一讲解一下整个过程:
-
(1). 获取
拥塞窗口
的过程是:拥塞窗口从很小的值开始【指数增长】
,当拥塞窗口达到阈值
后,拥塞窗口变成【线性增长】
,一旦发现丢包
(也就是收到三次重复确认),拥塞窗口的阈值
就减半
,然后拥塞窗口变成变成很小的值,又开始新一轮的指数增长,重复这个过程 -
(2). 慢开始:拥塞窗口从很小的值开始指数增长
-
(3). 拥塞避免:就是拥塞窗口达到阈值后,拥塞窗口线性增长,缓存增大以防止网络过早出现拥塞
-
(4). 快重传:一旦发现某个包丢了,接收方就发送三次重复确认,发送方就会把丢掉的包给再次重传,就不用等超时重传了
-
(5). 快恢复:当拥塞窗口线性增长时,如果发生了丢包,那么拥塞窗口的阈值减半,然后拥塞窗口的数值直接从阈值开始线性增长,不会从很小的值再次慢开始了
七、TCP的连接管理之三次握手
- TCP发送数据之前,会先通过
三次握手
建立连接,然后才会发送数据,三次握手的过程中,双方会交换TCP首部数据
- TCP发送数据之前,会先通过
- 三次握手的
TCP的数据部分
的长度都是0,只会交换TCP的首部
,也就是双方会交换TCP首部
所带的信息,例如序号、确认号、标志位
等信息;还会交换MSS
、是否支持SACK
、Window scale(窗口缩放系数)
等数据,这些数据都放在了TCP首部
的选项
部分中(12字节)
- 三次握手的
-
三次握手
的过程如下图所示:
image.png
-
- 我们来结合上图,详细说一下整个三次握手的过程:
- 首先,客户端处于
CLOSE关闭状态
,服务器处于LISTEN监听状态
,这是基础条件,这样双方才能通信
- 首先,客户端处于
- 然后,客户端发起
连接请求
,其TCP首部
的SYN = 1,AKC = 0,seq = x
,发送以后,客户端就处于SYN-SENT同步已发送
状态
- 然后,客户端发起
- 然后,服务器收到请求以后,发送TCP回复,其
TCP首部
的SYN = 1,AKC = 1,seq = y,ack = x + 1
,然后服务器处于SYN-RCVD同步已接受
状态
- 然后,服务器收到请求以后,发送TCP回复,其
-
4.然后,客户端收到以后,就会发送
AKC = 1,seq = x + 1,ack = y + 1
,然后处于ESTABLISHED连接已经建立状态
- 服务器收到以后,就会处于
ESTABLISHED连接已经建立状态
,这样双方就可以传输数据了
- 服务器收到以后,就会处于
八、TCP的连接管理之四次挥手
- TCP是全双工的,是双向通道,客户端和服务器端都可以先主动发起关闭,谁先谁后无所谓,所以关闭的时候要把两个通道都关闭了
-
2.
image.pngTCP/IP协议栈
在设计上,允许任何一方先发起断开请求,下图是演示的是客户端主动要求断开的过程,任何一方想断开连接,都需要经历
四次挥手`,如下图所示:
- 我们看着上图,理解一下整个挥手的历程:
-
FIN-WAIT-1
: 表示想主动关闭连接,向对方发送了FIN报文
,此时进入到FIN-WAIT-1状态
-
CLOSE-WAIT
: 表示在等待关闭,当对方发送FIN
给自己,自己会回应一个ACK报文
给对方,此时则进入到CLOSE-WAIT状态
,在此状态下,需要考虑自己是否还有数据要发送给对方,如果没有,发送FIN报文
给对方 -
FIN-WAIT-2
: 只要对方发送ACK确认
后,主动方就会处于FIN-WAIT-2状态
,然后等待对方发送FIN报文
-
CLOSING
: 一种比较罕见的例外状态-
表示你发送
FIN报文
后,并没有收到对方的ACK报文
,反而却也收到了对方的FIN报文
-
如果双方几乎在同时准备关闭连接的话,那么就出现了双方同时发送FIN报文的情况,也即会出现
CLOSING状态
-
表示双方都正在关闭连接
-
-
LAST-ACK
: 被动关闭一方在发送FIN报文
后,最后等待对方的ACK报文
,当收到ACK报文
后,即可进入CLOSED状态
了 -
TIME-WAIT
: 表示收到了对方的FIN报文
,并发送出了ACK报文
,就等2MSL
后即可进入CLOSED状态
了- 如果
FIN-WAIT-1状态
下,收到了对方同时带FIN标志和ACK标志
的报文时 - 可以直接进入到
TIME-WAIT状态
,而无须经过FIN-WAIT-2状态
- 如果
-
CLOSED
: 关闭状态 -
由于有些状态的时间比较短暂,所以很难用
netstat命令
看到,比如SYN-RCVD、FIN-WAIT-1
等
九、常见疑问
1. 为什么建立连接的时候,要进行3次握手? 2次不行么?
-
为了防止服务器一直等待,浪费资源
-
TCP建立链接是这样的:客户端发送
想要建立链接的请求
,服务器发送”确认收到“
,然后客户端发送”确认了服务器的确认“
,然后链接才能建立; -
多追加一个对确认的确认,就是为了防止客户端发送的第一个
”想要建立链接请求“
是由于某种原因误发的(例如网络延迟等),如果由于客户端误发就建立了链接,那么就是对服务器资源的极大浪费了
2. 为什么释放连接的时候,要进行4次挥手?
-
因为:TCP是全双工的,是双向通道,客户端和服务器端都可以先主动发起关闭,谁先谁后无所谓,所以需要把两个通道都关闭了
-
客户端发起关闭的流程是这样的:客户端发送
”我没有数据要发了想要结束“
,服务器说”确认收到“
,这就关闭一个数据通道; -
服务器发起关闭的流程是:服务器说
”我没有数据要发了想要结束“
,客户端说”收到了“
,关闭另一个通道; -
这样才能把
TCP的双向通道
全都关闭,所以挥手要进行4次