1. 什么是TCP协议?
TCP
协议的全称是传输控制协议 (Transmission Control Protocol
)是面向连接、可靠的传输层协议:传输数据前,必须先建立连接;- 每一条
TCP
连接基于发送方和接收方的是点对点连接; TCP
协议是一种面向字节流的传输层协议:应用层传递给传输层的报文是字节流形式,TCP
协议会把字节流组织成大小不等的报文段;TCP
具备“可靠性传输”、“流量控制”、“拥塞控制”等功能;
可靠性传输
当使用TCP
协议在网络中传输的数据比较大时(比如:视频、音频流等),会要求把数据分成报文段进行传输。每个报文段就是一个数据包,TCP
协议会依次发送,按序接收。但是,在传输的过程中,因为网络的缘故,数据包可能丢包,TCP
协议会通过确认应答、超时重发等机制来实现可靠传输。
流量控制
TCP
协议具备流量控制的功能:当发送方数据发送速度过快,接收方无法及时处理,就会通过确认报文,告诉发送方减缓发送数据的速度。
拥塞控制
TCP
协议具备拥塞控制的功能:当网络中传输的数据包数量过多,就会导致网络的拥堵。TCP
协议就会通过通过慢开始、拥塞避免、快重传、快恢复来进行拥塞控制,避免产生网络拥塞。
2. TCP协议报文段格式
- 在传输层,
TCP
报文段包括:TCP首部 + TCP数据部分; - 在网络层,
IP
报文段包括:IP首部 + IP数据部分(TCP报文段);
3. TCP首部格式
TCP
首部长度范围是20
字节 - 60
字节,其中固定首部占 20
个字节, 长度可变的选项部分最多占40
个字节。
20
个字节的固定首部,组成包括:源端口、目的端口、序号、确认号、数据偏移、保留、控制位、窗口、检验和、紧急指针。
3.1. 源端口和目的端口(4
个字节)
- 源端口:表示发送方的发送端口(占用
2
个字节=16
位) - 目的端口:表示接收方的接收端口(占用
2
个字节=16
位)
3.2. 序号(4
个字节)
TCP
连接中传送的数据流中的每一个字节都拥有自己的序号。
序号字段中的值,指的是本报文段所发送的数据报文第一个字节序号,代表每次数据发送的位置。每发送一次数据,就累加一次该数据字节数的大小。
- 例如:序号为
301
,表示第一个字节的编号为301
,如果携带的数据长度为100
字节,那么下一个报文段的序号应为401
。
序号列不会用0
或1
开始,而是在建立连接时,由计算机生成的随机数作为其初始值,通过SYN
标志位传递给接收端主机。
3.3. 确认号(4个字节)
确认号是指接收方向发送方一个确认报文段,通过该报文中的确认号,告诉发送方下一个要发送的报文段数据中第一个字节的序号。
- 例如:
B
(接收方) 正确收到A
(发送方) 发送来的一个报文段,序号为501
,携带的数据长度为200
字节。因此B
(接收方) 期望下一个报文段的序号为701
,B
发送给A
的确认报文段中确认号就为701
。
3.4. 数据偏移 (4位)
数据偏移代表数据部分距离报文首部的偏移量,表示TCP
所传输的数据部分应该从TCP
包的哪个位置开始计算,也可以理解为TCP
首部的长度。“数据偏移”的计算单位是 32
位(4
字节)。
- 例如:数据偏移设置为
0101 = 5
,5 x 4 = 20
个字节,代表报文段首部距离数据部分的偏移长度是20
字节;最大1111
表示15 x 4= 60
个字节,即表示TCP
首部最大长度为60
个字节,因此“选项”部分最多40
个字节。
3.5. 保留(占 6 位)
保留为今后使用,一般设置为 0。
3.6. 控制位(占6位)
用于传输过程中,传递控制标志位,用来说明本报文段的性质。
- 紧急
URG
:当URG = 1
时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。 即URG=1
的数据包不用排队直接优先传输。 - 确认
ACK
:ACK
是对已接受数据的确认。TCP
规定:ACK
默认为0
,在连接建立后,所有传送的报文段都必须把ACK
设置为1
。当ACK=1
时,确认号字段才有效,否则无效。 - 同步
SYN
:在连接建立时使用,表示这是一个连接请求或连接接受报文。当SYN=1,ACK=0
时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中SYN=1,ACK=1
。 - 推送
PSH
(Push
) :当两个应用进程进行TCP
通信时,其中一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP
就可以使用推送(push
)操作。这时,发送方TCP
把PSH
置1
,并立即创建一个报文段发送出去。接收方收到PSH = 1
的报文段,就尽快地发送反馈报文段,而不再等到整个缓存都填满后再发送。 - 复位 RST (
ReSet
) : 当RST = 1
时,表明TCP
连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。另外,通过将RST
设置1
还用来拒绝一个非法的报文段或拒绝打开一个连接。 - 终止 FIN (
FINis
) : 用来释放一个连接。FIN = 1
表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
3.7. 窗口 (2个字节)
窗口代表接收窗口,接收方通过报文段首部的接收窗口值,告知发送方:从本报文段首部中的确认号算起,允许对方发送的数据量(单位是字节),用于限制发送方发送数据量。
之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
- 例如:接收方发送了一个确认报文段,其确认号是
701
,窗口字段是1000
。这就是告诉对方:“从701
号字节算起,我的接收缓存空间还可接收1000
个字节数据(字节序号是701 ~ 1700
),你下次给我发送数据时,必须考虑到这一点。”
3.8. 检验和(占 2
个字节)
检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在 TCP
报文段的前面加上 12
字节的伪首部。
3.9. 紧急指针(占 2
个字节):
紧急指针用于指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
4. TCP协议三次握手:建立连接
注意区分ACK
和ack
:
ACK
是控制位字段中的一个标志位,占1
位;(控制位字段共计长度8
位)ack
是确认号字段,占4
字节;
- 第一次握手:
- 客户端先向服务器发送一个同步数据包(报文段)。
- 数据包的
TCP
首部内容:同步SYN=1,确认ACK=0,序号seq=x - 根据
TCP
首部内容,表示这是一个请求建立连接的数据包,其中seq=x
为所传送数据的第一个字节的序号。
- 第二次握手:
- 服务器收到客户端发送的第一个数据包后,根据
SYN=1
与ACK=0
,判断出为主动建立连接的数据包。 - 若服务器同意连接,则服务器发送一个数据包进行回应。
- 数据包的TCP首部内容:同步SYN=1,确认ACK=1,序号seq=y,确认号ack=x+1
- 确认
ACK=1
,代表服务器同意连接; - 序号
seq=y
的值由服务器指定,表示服务器发送数据时的第一个数据字节的序号; - 确认号
ack=x+1
,表示已经收到客户端发送的x
个字节数据,并告诉客户端下次应从数据的第x+1
个字节开始发送;
- 确认
- 服务器收到客户端发送的第一个数据包后,根据
- 第三次握手:
- 客户端收到服务器的确认之后,再给服务器发送一个数据包。
- 数据包的TCP首部内容:同步SYN=0,确认ACK=1,序号seq=x+1,确认号ack=y+1
SYN=0
,表示双方已同意建立连接;- 确认号
ack=y+1
,表示收到服务器发送y
字节数据,并告诉服务器下次应从数据的第y+1
个字节开始发送。 - 确认
ACK=1
,表示收到服务器的确认数据包; - 序号
seq=x+1
,表示发出的数据包就是数据的第x+1
个字节;
常见问题01:三次握手的原因
在建立TCP
连接过程中的前两次握手:①客户端向服务器发出建立连接的请求、② 服务器向客户端确认这个请求,足以证明客户端与服务器之间的网络是畅通的。
如果没有最后一个数据包确认(第三次握手),假设一个特殊场景:客户端先发出一个建立连接的请求数据包,由于网络原因,客户端在设定的超时时间内,还未收到服务器的确认数据包。于是发出第二个建立连接的请求数据包,这次网路通畅,数据包很快到达服务器,服务器的确认数据包也很快就到达客户端。于是客户端与服务器开始传输数据。但是客户端第一次发出的建立连接的请求数据包到达服务器,服务器以为是再次建立连接,所以又发出一个确认数据包。由于客户端已经收到了一个确认数据包,所以会忽略服务器发来的第二个确认数据包,但是服务器发出确认数据包之后就要一直等待客户端的回复,而此时的客户端永远也不会回复服务器。由此服务器无效等待,造成资源浪费。如果过于频繁会导致服务器停止响应。
所以,三次握手的主要作用是为了避免重复连接,防止旧的重复连接引起连接混乱问题。
另外,通过三次握手,可以得到一个确认的可靠初始化序列号seq
,用于进行可靠性传输。而如果只有2
次握手,则无法初始化序列号seq
。
综上所述,TCP
协议最少需要通过3
次握手建立连接。当然, TCP
连接也通过4
次握手或5
次握手建立连接,实现 TCP
连接的稳定性,但3
次握手是最节省资源的连接方式。
常见问题02:三次握手建立TCP连接过程的各个状态
- 客户端发出请求建立连接的数据包之后进入
SYN-SENT
状态,表示发送了请求建立连接的同步数据包。 - 服务器收到客户端发出的请求建立连接的数据包之后,结束
LISTEN
状态,进入SYN-RCVD
状态并向A发出确认数据包。 - 客户端收到确认数据包之后,结束
SYN-SENT
状态,进入ESTABLISHED
状态,并向服务器发送确认数据包。 - 服务器收到客户端的确认数据包之后,结束
SYN-RCVD
状态,进入ESTABLISHED
状态。 - 客户端与B都进入
ESTABLISHED
状态之后,开始传输数据,由此完成三次握手。
查看当前计算机的TCP
连接状态
netstat -n
5. TCP协议四次挥手:释放连接
- 第一次挥手
- 首先客户端向服务器发送连接释放的请求报文(数据包),并停止发送数据
- 在连接释放报文(数据包)的TCP首部中:终止FIN=1,确认ACK = 0
- 终止FIN=1,意味着客户端要主动释放客户端—>服务器的TCP连接;序号位seq为u,u值由客户端指定。随后等待B的确认。
- 第二次挥手:
- 服务器收到连接释放的报文之后,给客户端发送确认报文。从客户端到服务器这个方向上的连接就释放了,TCP连接处于半关闭状态。此时客户端无法发送数据给服务器,但是服务器还可以发送数据给客户端,客户端仍可以接收。
- 在服务器发送给客户端确认报文的TCP首部中:终止FIN=0,确认ACK=1,序号位seq=v,确认号ack=u+1
- 确认ACK=1表示收到了客户端发送的数据包,同意客户端释放连接;
- 第三次挥手:
- 若服务器已经没有向客户端发送的数据了,其应用进程就通知TCP释放连接,并向客户端发送确认报文。
- 在确认报文的TCP首部中:确认ACK=1,终止FIN=1
- 确认ACK=1,表示服务器已经把需要发给客户端的数据发完了;
- 终止FIN=1,表示服务器要释放服务器—>客户端的TCP连接;
- 此后服务器不再向客户端发送数据,但能接收数据。
- 第四次挥手:
- 客户端收到服务器的连接释放报文段后,向服务器发出确认报文。
- 在确认报文的TCP首部中:确认ACK=1,终止FIN = 0
- 确认ACK=1,表示收到服务器的确认报文,并同意服务器释放连接;
6. 连接管理
TCP
提供面向连接的通信传输。面向连接是指在数据通信开始之前,先做好通信两端之间的准备工作。
TCP
会在数据通信之前,通过TCP
首部发送一个SYN
包作为建立连接的请求并等待确认应答。如果对方主机发来确认应答,则认为可以进行数据通信。如果对方主机的确认应答未能到达,则不会进行数据通信。此外,在通信结束时,会通过发送FIN
包进行断开连接的处理。
7. 确认应答
在TCP
协议中,当发送端的数据到达接收主机时,接收端主机会返回一个已收到消息的通知,这个消息叫做确认应答(ACK
)。
TCP
通过肯定的确认应答(ACK
)实现可靠的数据传输。当发送端将数据发出去之后会等待接收端的确认应答。如果有确认应答,说明数据已经成功到达接收端。反之,则数据丢失的可能性很大。
8. 重传机制
8.1. 重传超时
重传超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔。如果超过了这个时间仍未收到确认应答,发送端将进行超时重传。
在Unix
以及Windows
系统中,超时都以0.5
秒为单位进行控制。因为超时重发都是0.5
秒的整数倍。不过,由于最初的数据包还不知道往返时间RTT
,所以其重发超时一般设置为6秒左右。
数据被重发之后如果还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会以2
倍、4
倍的指数函数延长。
当然,数据也不会被无限、反复地重发。达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对方主机发生了一次,强制关闭连接。
8.2. 超时重传
超时重传是TCP
协议重传机制的一种。在重发超时的时间间隔内,没有等到确认应答,发送端就可以认为数据包已经丢失,就会重新发送该数据。所以,即使产生了丢包,仍然能够保证数据能够到达接收端,实现可靠性传输。
TCP会在两种情况下发生超时重传:
8.3. 快速重传
TCP
协议重传机制的第二种方式是快速重传(Fast Retransmit
)机制,它不以时间为驱动,而是以数据驱动重传。
快速重传的工作方式是当收到三个相同的 ACK
报文时,会在重传超时过期之前,重传丢失的报文段。但是它存在的问题是重传的时候,是重传之前的一个,还是重传所有。例如:在上图中,是重传 Seq2
呢?还是重传 Seq2
、Seq3
、Seq4
、Seq5
呢?因为发送端并不清楚这连续的三个 Ack2 是谁传回来的。
为了解决不知道该重传哪些 TCP 报文,于是就有 SACK
方法。
8.4. SACK 方法
实现TCP
协议重传机制的第三种方式叫SACK
( Selective Acknowledgment
选择性确认)。
这种方式需要在 TCP
首部「选项」字段里加一个 SACK
的东西,它可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。
9. 滑动窗口
概述
滑动窗口是TCP
协议用于实现流量控制的一种机制。
发送方和接收方分别维护各自的缓冲区,这个缓冲区就是窗口。发送方的窗口大小由接收方的TCP
首部的窗口字段决定。
发送方将窗口内容分为:已发送并确认,已发送未确认,未发送未超出接收方窗口范围,未发送但超出接收方窗口范围。随着接收方的确认,发送方将不断在窗口内向前滑动。
接收方将窗口内容分为:接受已确认,未收到但可以接受。接收方读取窗口内容,并不断确认通知发送方,窗口向前滑动。接收方通过改变窗口大小,可以控制发送方的速率,从而实现流量控制。
实现机制
TCP
首部格式中有个窗口的字段代表滑动窗口的大小,用于接收方通知发送方自己有多少缓冲区可以接收数据,发送方可以根据接收方的处理能力来发送数据,不会导致接收方处理不过来。所以,通常窗口的大小是由接收方的决定的。发送方发送的数据大小不能超过接收方的窗口大小,否则接收方就无法正常接收到数据。
发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向前滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向前滑动接收窗口。
- 假设发送窗口是
5
,也就是发送方一次性能发5
个数据包。当发送方收到数据包1的接收确认后表示接收方接收了数据包1,之后发送窗口向前滑动一个数据包,在发送窗口中删除数据包1的缓存。 - 即如果发送了
5
个数据包后没有收到确认信息就会停止继续发送数据包。
作用
TCP
在传输数据的时候,如果数据比较大,通常会拆分成一段一段的进行发送。每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送下一个。但是,为了能够提高传输的效率,不可能一段一段的进行发送,等一段收到确认了在去发送下一段,这样效率是比较低的。这样的传输方式有一个缺点:数据包的往返时间越长,通信的效率就越低。
为解决这个问题,TCP 引入了窗口这个概念。可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。窗口的实现实际上是操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。即使在往返时间较长的情况下,它也不会降低网络通信的效率。
TCP
协议通过滑动窗口的机制解决了流量控制和乱序重排。
窗口滑动过程
- 客户端向服务端发送请求数据报文。
- 服务端收到请求报文后,发送确认报文和
80
字节的数据,于是可用窗口Usable
减少为120
字节,同时SND.NXT
指针也向右偏移80
字节后,指向321
,这意味着下次发送数据的时候,序列号是321
。 - 客户端收到
80
字节数据后,于是接收窗口往右移动80
字节,RCV.NXT
也就指向321
,这意味着客户端期望的下一个报文的序列号是321
,接着发送确认报文给服务端。 - 服务端再次发送了
120
字节数据,于是可用窗口耗尽为0
,服务端无法在继续发送数据。 - 客户端收到
120
字节的数据后,于是接收窗口往右移动120
字节,RCV.NXT
也就指向441
,接着发送确认报文给服务端。 - 服务端收到对
80
字节数据的确认报文后,SND.UNA
指针往右偏移后指向321
,于是可用窗口Usable
增大到 80。 - 服务端收到对
120
字节数据的确认报文后,SND.UNA
指针往右偏移后指向441
,于是可用窗口Usable
增大到200
。 - 服务端可以继续发送了,于是发送了
160
字节的数据后,SND.NXT
指向601
,于是可用窗口Usable
减少到40
。 - 客户端收到
160
字节后,接收窗口往右移动了160
字节,RCV.NXT
也就是指向了601
,接着发送确认报文给服务端。 - 服务端收到对
160
字节数据的确认报文后,发送窗口往右移动了160
字节,于是SND.UNA
指针偏移了160
后指向601
,可用窗口Usable
也就增大至了200
。
10. 流量控制
简单来讲:流量控制是为了控制发送方发送速率,保证接收方来得及接收。
TCP
连接的每一方都有固定大小的缓冲空间,TCP
的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失,从而实现流量控制。
TCP
使用的流量控制协议是可变大小的滑动窗口协议。 (即TCP 利用滑动窗口实现流量控制)
接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
11. 拥塞控制
11.1. 拥塞控制与流量控制的区别
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞。拥塞控制就是为了防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器,以及与降低网络传输性能有关的所有因素。相反,流量控制往往是点对点通信量的控制,是个端到端的问题。流量控制所要做到的就是抑制发送端发送数据的速率,以便使接收端来得及接收。
所以,如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
11.2. 拥塞控制的四个算法
- TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复
- 发送方需要维护一个叫做拥塞窗口(
cwnd
)的状态变量,注意拥塞窗口与发送方窗口的区别:拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。
11.2.1. 慢开始
慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。
发送最初执行慢开始,令 cwnd = 1
,发送方只能发送 1
个报文段;当收到确认后,将 cwnd
加倍,因此之后发送方能够发送的报文段数量为:2
、4
、8
...
11.2.2. 拥塞避免
注意:慢开始每个轮次都将 cwnd
加倍,这样会让 cwnd
增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh
,当 cwnd >= ssthresh
时,进入拥塞避免,每个轮次只将 cwnd
加 1,降低拥塞窗口的增长速度。如果出现了超时,则令 ssthresh = cwnd / 2
,然后开始执行快恢复。
11.2.3. 快重传
- 在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段。
例如:如发送数据包M1
~M5
,丢失了M3
。接收方接连收到不连续的数据包M2
、M4
,就已经发现丢失了M3
,可采用快重传方式。
11.2.4. 快恢复
- 当发送端收到连续三个重复的确认时,就执行“乘法减小”算法,把慢开始门限
ssthresh
减半。 - 由于发送方现在认为网络很可能没有发生拥塞,因此现在不执行慢开始算法,即拥塞窗口
cwnd
现在不设置为 1 。而是将cwnd
当前值减半作为新的慢开始门限ssthresh
值,并让cwnd
的值等于这个新的慢开始门限ssthresh
值。随后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。 这便是快恢复算法。
13. TCP粘包
在网络传输过程中,使用TCP
协议和UDP
协议进行数据发送时,UDP
是基于报文传输的,发送几次Write()
,接收端就会用几次Read()
,每次读取一个报文,报文间不合并,多余缓冲区的报文会丢弃。而TCP
是基于数据流传输的,Write()
和Read()
的次数不固定,报文间会以随机的方式合并,这就需要在接收时处理粘包问题。
13.1. 产生原因
粘包往往发生在以下两种情况中:
所以,粘包主要产生的原因是:TCP
是面向流的的传输协议,发送端可以一次发送不定长度的数据,而接收端也可以一次提取不定长度的数据,这种传输方式是无保护数据边界的,所以粘包问题本身其实是一种“数据的无边界性”问题。
13.2. 解决办法
为了避免粘包,我们在程序中,一般可以采取以下三种措施:
- 快恢复是配套着快重传使用的,快恢复是相对于慢开始算法而言的。使用快恢复算法时,
cwnd
从较大值开始,通过拥塞避免算法逐渐线性增大,经过较短时间便能恢复比较快的传输速度;使用慢开始算法时,cwnd
从1
开始,需要较常时间才能达到较快的速度。 -
12. TCP协议如何保证可靠性传输?
TCP协议有哪些特点?
- 校验和:
TCP
将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。 - 序列号:
TCP
传输时将每个字节的数据都进行了编号,用于确认应答。 - 确认应答:
TCP
通过肯定的确认应答(ACK
)实现可靠的数据传输。当发送端将数据发出去之后会等待接收端的确认应答。如果有确认应答,说明数据已经成功到达接收端。反之,则数据丢失的可能性很大。 - 超时重发:当
TCP
发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。 - 高速重发:在出现报文丢失的情况下,同一个序号的确认应答将会被接收端重复不断地返回。而发送端如果连续3次收到同一个确认应答,就会将其所对应的数据进行重发。
- 连接管理:
TCP
提供面向有连接的通信传输。面向有连接是指在数据通信开始之前,先做好通信两端之间的准备工作。 - 流量控制:
TCP
连接的每一方都有固定大小的缓冲空间,TCP
的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制) - 窗口控制:
TCP
通过设置一个窗口大小值,配合“滑动窗口”机制,实现并行式处理,确认应答不再是以每个数据包,而是以更大的单位进行确认,提高效率。 - 拥塞控制:当网络拥塞时,减少数据的发送。
- ARQ协议:为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
- 发送端需要等待缓冲区
flush
时发送数据,造成发送时粘包; - 接收端未及时接收缓冲区的数据,多包一起接收,造成接收时粘包;
- 发送端粘包,可以在程序中不等缓冲区满就立即发送数据(默认情况是等缓冲区满后再发送)。这种方法会降低通信的传输效率。
- 接收端粘包,可以在程序中通过优化程序逻辑、提高进程优先级等措施,使其及时接收数据。这种方法,你可以发现,有时候也是无法优化的,实现起来会比较难。
- 自定义包结构,每条数据都要实现约定好格式(开始符、结束符)。
- 发送长度,发送每条数据时,将数据的长度一并发送,例如规定数据的前
4
位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开始和结束位置。