传输层(Transport)的协议介绍
- TCP(Transport Control Protocol),传输控制协议
- TCP 是
面向连接的
、可靠的
、基于字节流
的传输层通信协议。面向连接
:一对一面向连接可靠的
:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端基于字节流
:消息没有边界,不论消息多大都可以进行传输。消息是有序的,当前一个消息还没收到的时候,即使先收到了后面的字节,也不会给应用层处理,同时丢弃重复的报文。思考:TCP连接如何保证消息的可靠性?
- TCP 是
- UDP(User Datagram Protocol),用户数据报协议
- 无连接的、减少了建立和释放的开销
- UDP尽最大能力交付、不保证可靠交付
- 不需要维护一些复杂的参数,首部只有8的字段(TCP首部至少20个字节)
TCP和UDP的差别
场景/名字 | TCP | UDP |
---|---|---|
连接性 | 面向连接 | 无连接 |
可靠性 | 可靠传输、不丢包 | 不可靠传输、尽最大努力交付、可能丢包 |
首部占用空间 | 大(20~64字节) | 小 (8字节) |
传输速率 | 慢 | 快 |
资源消耗 | 大 | 小 |
应用场景 | 浏览器、文件传输、邮件发送 | 音视频电话、直播 |
应用层协议 | HTTP、HTTPS、FTP、SMTP、DNS | DNS |
TCP首部格式
首部字段说明
端口号
:用来标示同一计算机的不同的应用进程源端口号
:源端口号和IP的作用是标示报文的返回地址目的端口号
:端口指明接收方计算机上的应用程序接口序号
(Sequence Number):占4
字节- 在传输过程中每一个字节都有一个编号
- 在建立连接后,序号代表:这一次传给对方的TCP数据部分的第一个字节的编号
- 序号是TCP可靠传输的关键部分。序号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节一个序号。e.g.一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。
用来解决乱序的问题
确认号
(Acknowledgment Number):占4
字节- 确认号,即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如请求建立连接时,SYN报文的ACK标志位为0。
用来解决不丢包的问题
数据偏移
4bits- 由于首部可能含有可选项内容,因此TCP报头的长度是不确定的,报头不包含任何任选字段则长度为20字节,4位首部长度字段所能表示的最大值为1111,转化为10进制为15,15*32/8 = 60,故报头最大长度为60字节。首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。
标志位
:(Flags)- URG(Urgent):
- 当URG=1时,紧急指针字段才有效,表明当前报文字段中有紧急数据,应优先传送
- ACK:(Acknowlwdgment):
- 当ACK=1时,确认号字段才有效。
- TCP规定,除了最初建立连接时的SYN包之外,其值必须设置为1
- PSH:
- push标志,为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
- SYN(Synchornization):
- 当SYN=1,ACK=0时,表明这是一个建立连接的请求,若对方同意建立连接则会回复SYN=1、ACK=1
- 会在其
序号
字段进行序列号初始值的设定
- RST(Reset):
- 当RST=1时,表明连接中出现了严重的差错,必须释放连接,然后再重新建立连接
- FIN(Finish)
- 当FIN=1时,表明数据已经发送完毕,要求释放连接
- URG(Urgent):
窗口
(Window)- 这个字段有流量控制功能,用以告诉对方下一次允许发送的数据大小(字节为单位)
校验和
:- 奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
紧急指针
- 只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
选项和填充
- 最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size),每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志为1的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。
数据部分
- TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。
TCP可靠传输说明
对前边的问题作为说明:TCP如何保证可靠传输?
-
停止等待ARQ协议
- ARQ(Automatic Request-reQuest),自动重传请求
- 超时重传
- 确认丢失
- 确认迟到
- 缺点:发送一段数据,就确认下,再发下一段,发送等待浪费时间
- ARQ(Automatic Request-reQuest),自动重传请求
-
连续ARQ协议+滑动窗口协议
- 过程如下
- 如果接收窗口最多能接收4个包,但是发送方只发了2个包,接收方如何确定后边还有两个包?
- 等待一点时间后没收到第三个包,就会返回确认收到的两个包给发送方
问题
:如果发送(1、2、3
、4、5)中的3
丢失了,TCP通过重传最后确认的分组后续分组未2,这样原先已经正确传输的分组也可能会重复发送(4、5),降低了TCP的性能。
- 过程如下
-
为了解决上述情况,发展处了
SACK
:(Selective acknowledgement)选择性确认
技术- 告知发送方那些数据丢失,哪些数据已经提前收到
- 使TCP只重新发送丢失的包(
3
),不用发送后续所有的分组(4、5)- SACK信息放在TCP首部的选项部分
-
在传输层就将数据拆分为多个段,不等到网络层再分片传递给数据链路层?
- 可靠传输是在传输层控制的
- 如果不在传输层分段,一旦发现丢失数据,整个传输层的数据都要重传
- 如果在传输层分段,一旦发现数据丢失 ,只需要重传丢失的那段即可
- 可靠传输是在传输层控制的
TCP流量控制
- 场景:如果接收方的缓存区满了,发送方还在疯狂的发送数据
- 接收方只能把收到的数据报丢弃,大量的丢包会极大的浪费网络资源,所以要进行流量控制
- 什么是流量控制?
- 让发送方的发送速率不要太快,让接收方来得及接收处理
- 原理:
- 通过确认报文中窗口字段来控制发送方的发送速率
- 发送方的发送窗口大小不能超过接收方给出的窗口大小
- 当发送方收到接收窗口的大小为0时,发送方就停止发送数据
流量控制是点对点通信的控制
TCP拥塞控制
- 拥塞控制
- 防止过多的数据注入到网络
- 避免网络中的路由器或链路过载
- 拥塞控制是一个全局性的过程
- 设计到所有的主机、路由器
- 以及与降低网络传输性能有关的所有因素,是大家共同的努力
拥塞控制的方法
- 慢开始(slow start,慢启动)
- 拥塞避免(congestion avoidance)
- 快速重传(fast retransmit)
- 快速回复(fast recovery)
TCP三次握手
-
状态解读
- CLOSED:client处于关闭状态
- LISTEN:server处于监听状态,等待client连接
- SYN-RCVD:表示server接受到了SYN报文,当收到client的ACK报文后,它会进入到ESTABLISHTED状态
- SYN-SENT:表示client已发送SYN报文,等待server的第2次握手
- ESTABLISHTED:表示连接已经建立
-
TCP三次握手文字总结
-
客户端和服务器都除以
CLOSED
状态,先是服务端主动监听某个端口,处于LISTEN
状态 -
第一个报文:SYN 报文
客户端会随机初始化
序号
(client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把SYN
标志位置为 1 ,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT
状态。 -
第二个报文 —— SYN + ACK 报文
服务端收到客户端的
SYN
报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于SYN-RCVD
状态。 -
第三个报文 —— ACK 报文
客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于
ESTABLISHED
状态。 -
服务器收到客户端的应答报文后,也进入
ESTABLISHED
状态。
-
从上面的过程可以发现,第三次握手是可以携带数据的,前两次握手是不可以携带数据的
。
一旦完成三次握手,双方都处于 ESTABLISHED 状态
,此致连接就已建立完成,客户端和服务端就可以相互发送数据了。
TCP为什么选择三次握手,而不是两次、四次
-
原因大纲
- 三次握手才能阻止历史重读连接的初始化(主要原因)
- 三次握手才可以同步双发的初始序号
- 三次握手避免资源浪费
-
避免历史连接
:防止旧的重复连接初始化造成混乱- 造成的原因以及现象:
- 网络原因,会导致新的SYN报文在建立连接的时候,旧的SYN报文也到达目的主机, 如果是两次握手,会导致连接混乱。
- 详细说明
- 一个旧的
SYN报文
比最新的SYN报文
早到达了服务器; - 此时服务器会返回一个SYN+ACK报文给客户端;
- 客户端会根据自身的上下文,判断这是一个历史连接(序号过期或超时),此时客户端会发送
RST
报文给服务器,终止这一次连接!
- 一个旧的
总结
: 服务器不能判断出 当前连接请求是否是历史连接,如果只两次握手会造成错乱,客户端则可以判断出当前连接是否是历史连接,所以必须要有第三次握手终止历史连接。
- 造成的原因以及现象:
-
同步双方初始序列号
- TCP通信双方都必须维护一个
序列号
,序列号是可靠传输的一个关键因素 - 作用:
- 接收方可以去除重复的数据
- 接收方可以根据数据报的序号按序接收
- 可以标示发送出去的数据包,哪些是已经被对方收到的。
客户端发送携带初始序列号
的SYN
报文时,服务端则回复一个ACK
应答报文,表示客户端的SYN
报文已被服务端成功接收,此时服务端也会发送初始序列号
给客户端,依然需要客户端给回一个应答回应。只有三次握手才能保证双方的初始序列号都被可靠的同步
- TCP通信双方都必须维护一个
-
避免资源浪费
- 如果只有两次握手时,当
客户端的SYN
请求连接在网络中阻塞
时,客户端没有收到服务端的ACK报文
,就会重发SYN
,由于没有第三次握手,服务器不清楚客户端是否收到了自己发送的建立连接的ACK确认信号
,所以每次收到一个SYN报文就先主动建立一个连接,如果客户端重发了多次的SYN报文
,服务器就会建立多个冗余的无效连接,造成不必要的资源浪费
.
- 如果只有两次握手时,当
TCP 建立连接时,通过三次握手能防止历史连接的建立
,能减少双方不必要的资源开销
,能帮助双方同步初始化序列号
。序列号能够保证数据包不重复、不丢弃和按序传输
不采用四次握手的原因
:三次握手已经最少可靠的建立连接,所以不需要使用更多的通信次数。
TCP四次挥手
- 文字总结四次挥手:
以客户端主动关闭连接为例 —— TCP 四次挥手
- 客户端打算关闭连接,此时会发送一个
TCP
首部FIN
标志为1的报文,即FIN报文
,接着客户端进入FIN_WAIT_1
状态。 - 服务端收到该报文时,就向客户端发送ACK应答报文,接着服务端进入
FIN_WAIT_1
状态。 - 客户端收到服务端的
ACK
应答报文后,之后进入FIN_WAIT_2
状态。 - 等待服务端处理完数据后,也向客户端发送
FIN
报文,之后服务端进入LAST_ACK
状态。 - 客户端收到服务端的
FIN
报文后,回一个ACK
应答报文,之后进入TIME_WAIT
状态 - 服务器收到了
ACK
应答报文后,就进入了CLOSE
状态,至此服务端已经完成连接的关闭。 - 客户端在经过
2MSL
一段时间后,自动进入CLOSE
状态,至此客户端也完成连接的关闭。
- 客户端打算关闭连接,此时会发送一个
每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。
注意:主动关闭连接的,才有 TIME_WAIT 状态
。
MSL
:(Maximum Segment Lifetime)最大分段生存期
- MSL是TCP报文在Internet上的最长生存时间
- 每个具体的TCP实现都必须选择一个确定的MSL值 (RFC 112)建议2分钟
- 可以防止本次连接中产生的数据报误传到下一次连接中(因为本次连接中的数据报都会在2MSL时间消失l)
- 需要等待2MSL的原因:
- 如果客户端发送ACK后马上释放了,然后又因为网络原因,服务端没有收到客户端的ACK,服务端就会重发FIN
- 客户端没有任何响应,服务器那边会干等,甚至多次重发FIN,浪费资源
- 客户端有个新的应用程序刚好分配了同一个端口号,新的应用程序收到FIN后马上开始执行断开操作,本来它可能是跟服务端简历连接的。
TCP为什么选择四次挥手
- TCP为什么选择四次挥手
- 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
- 服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和FIN 一般都会分开发送,从而比三次握手导致多了一次。