TCP(Transmission Control Protocol)传输控制协议,面向连接的传输协议,在传输层。
TCP协议特点
- 面向连接:通信之前必须建立连接,通信后断开连接
- 每一个TCP连接只能是点对点的(一对一)
- 提供的可靠的交付服务:通过TCP连接传输的数据,无差错,不丢失,不重复
- 提供全双工通信
- 面向字节流:TCP中的传输数据是以流的形式传输
- TCP的首部占20字节
TCP报文头
源端口
源端口占用16bit位,表示发送方主机进程占用的端口号,通过端口可以表时主机上的某一个应用
目的端口
目的端口占用16bit位,表示的是目的主机的端口号,网络通信连接接收方需要用IP+端口,IP在网络层,端口就在传输层记录, 端口号的个数 2^16 =65536
序号
序号占用32位,对发送的数据进行编号,接收方返回的确认序号就是下一个发送包的编号
确认号
确认号32位,确认号接收端发送给发送端的确认编号,表示该编号之前的数据都成功接收,接收端接收到该消息之后就可以继续发送后续的报文
报头长度(数据偏移)
占用了4个bit位,以32位(4字节)即字长为单位,报头的长度是可变的,最大是60个字节(占用4个bit位,2^4=15, 15 *4(字节) =60字节)
保留位
保留位占6位,必须全为0
标志位
标志位占6bit,存在6个标志,每个占用一个bit,如果有效则置为1,依次URG、ACK、PSH、RST、SYN、FIN
URG:该位为1表示TCP包的紧急指针有效,督促上层应用尽快的处理紧急处理
ACK:确认号有效
PSH:push操作,该标志位为1接收方应尽快将报文交给应用层
RST:(rest)连接复位,在通信过程找那个存在主机奔溃或其他原因早成连接错误,用该标志位来拒绝连接
SYN:是一个同步序号,通常是与ACK合用来建立连接,三次握手
FIN:需要端口连接时用到该标志位
窗口大小
占用16bit位,TCP中用来进行流量控制,通过窗口可以告知发送方窗口的大小,通过动态的控制发送窗口大小来控制发送到网络中包的大小,网络通畅时发送大的数据包,网络发送拥塞时发送小的数据包
检验和
占用16bit,通过对首部和数据进行校验来判断当前包是否正确
紧急指针
只有当URG标志置为1时才有效,紧急指针是一个正的偏移,和序号字段中的是相加表示紧急指针的最后的序号,TCP的紧急方式发送一条数据给接收端
三次握手
过程:
- 第一次握手:客户端发送请求到服务端,并且进入到SYN-SENT状态,等待服务端确认。(SYN = 1,seq(序号) = x)
- 第二次握手:服务端接收到连接请求,如果同意连接,向客户端发回确认报文段,服务端进入到SYN_RCVD状态。(SYN = 1,ACK = 1,seq = y,ack(确认号) = x+1)--->当收到确认后,表示 ack = x+1前(即序号x)的数据全部都接收到了。
- 第三次握手:客户端接收到服务端的确认报文,再向服务端发出确认报文,客户端和服务端都进入到ESTAB-LEISHED状态,可以进行双向通讯。(ACK = 1,seq = x+1,ack = y+1)
注:
TCP可以是两次握手嘛?
TCP的三次握手不能改成两次握手,是为了防止已经过期的连接重新连接上。
如果只有前两次握手的情况下:假如在网络拥塞的情况下,客户端向服务端发出了第一次握手请求,由于客户端么有接收到来自服务端的ack确定,在饱和机制的影响,便再次发出请求,但是在某种原因下比上次的请求先到达到服务端,然后服务端直接给客户端回复了ack请求,此时客户端是可以给服务端发送数据的,如果此时客户端给服务端发送一个很小的数据包,发送完很快就断开了连接,而此时第一次的连接请求到达到服务端(其实本次请求应该是无效的),而在基于两次握手的情况下服务器端无法判断该请求的有效性,从而再次建立连接,因为本次要发送的数据与前面已经发送的数据包一致,因此此次连接是无意义的,相当于白白建立了连接。(三次握手的情况下,由于是客户端发送的请求,它能够识别第二次握手是否是重复的请求,便不会给客户端回应ack进行第三次握手,连接就无法建立)。
四次挥手
过程:
- 第一次挥手 客户端向服务端发送断开连接报文段,客户端进入FIN-WAIT-1状态(FIN = 1,seq=u)
-
第二次挥手 服务端接收到客户端的请求报文后,确认客户端的消息,由服务端回复客户端一个ACK报文,服务端进入到CLOSE-WAIT状态(ACK=1,seq=v, ack=u+1),客户端接收到第二次挥手消息后进入到FIN-WAIT-2状态,这时客户端不能给服务端发送消息,但服务端可以继续给客户端发送消息(单通道通信)
- 第三次挥手 服务端向客户端发送断开报文段,服务端进入到LAST-ACK状态(FIN = 1,ACK = 1,seq = w,ack = u+1)
- 第四次挥手 客户端接收到服务端发送的请求报文后,向服务端发送一个确认消息,客户端进入到TIME-WAIT状态。在等待2MSL时间后才进入到CLOSED状态,服务端接收到客户端的消息后进入到CLOSED状态(ACK = 1,seq = u+1,ack = w+1)
注:
TCP可以是三次挥手嘛?
不可以,如果是三次挥手(由于第二次和第三次都是由服务端发出,如果这两次挥手统一看成是第二次挥手的情况),可能会造成数据的丢失,(第三次挥手到达要早于数据传输的情况),第二次与第三次挥手间会进行数据的传输。如果么有第四次挥手,便会进行超时重传;但是是存在三次挥手的可能,那就是客户端和服务端同时发起挥手。
第四次挥手后需要等待2MSL的原因:
为了保证发送的最后一个ACK到达服务端;防止已经失效的连接请求报文段出现在本次连接中。
TCP发送数据
TCP的包发送和接收存在两个缓冲区,一个是发送缓冲区,一个是接收缓冲区。
发送缓冲区:TCP传输层数据包有大小限制,如果包过大的话,拆分成多个TCP包,发送的数据包过小,等待多个应用层消息打包成一个TCP的数据包进行发送 TCP报文头至少是20个字节
接收缓冲区:数据是没有明确的边界,接收数据是没办法指定一个或者多个消息一起读,只能选择一次读取多大的数据流,而这个数据流中包含着某个消息包的一部分数据
TCP保证数据的安全性的原因
- 校验和:报文头的检验和用来保证当前传输包的完整性
- 序列号:报文头中的序列号是用来对TCP包进行编号,接收端通过编号可以对数据进行去重和排序
- 确认应答机制(ACK)
- 超时重传/快重传 当报文发出后在一定的时间内未收到接收方的确认,发送方就会进行重传(通常是在发出报文段后设定一个闹钟,到点了还没有收到应答则进行重传),未收到确认不一定就是发送的数据包丢了,还可能是确认的 ACK 丢了;
- 拥塞控制
缓存与滑动窗口:
消息由发送方产生,发送方会先将产生的数据放到发送缓冲区中,然后发送的时候会从发送缓冲区中去取。接着消息从发送方的用户空间传入内核空间借助网络传输介质完成传输,消息会发送到接收方的内核空间,接收方如果要想读取时需要将消息从内核空间拷贝到用户空间。接收方会将接收到的数据先放到接收缓冲区中,然后应用程序使用的时候会从接收缓冲区中去拿。
滑动窗口的作用是为了防止发送方发送过多的数据而接收方无法接收导致异常,所以 tcp 协议采用一种名叫滑动窗口的机制收发消息的两方既有自己的发送窗口也有自己的接收窗口,接收方会先通过 TCP 协议首部的窗口字段告知发送方自己接收窗口的大小,然后发送方会根据这个大小设置自己发送窗口的大小。
发送窗口:
发送窗口后沿的变化情况 2 种可能:
- 不动:没有收到确认 ACK。
- 前移:正常 ACK。
发送窗口前沿的变化情况 2 种可能:
- 不动:没有收到新的确认,对方通知的窗口大小不变;收到新的确认,但对方通知的窗口缩小。
- 前移:普遍情况。
接收窗口:
接收方的运动和发送方类似,当收到发送方发出的消息之后接收方给出确认一旦接收方的确认发出之后接收方的窗口就会向右移动。
网络拥塞:
在计算机网络中的链路容量(即带宽),交换结点中的缓存和处理机等,都是网络资源。在某段时间,若对网络中的某一资源的需求超过该资源所能提供的可用部分,网络的性能就要变坏,这种情况就叫拥塞。拥塞控制是一个全局性的过程; 流量控制是点对点通信量的控制 TCP 拥塞控制 4 个核心算法:慢开始(slow start)、拥塞避免(Congestion Avoidance)、快速重传(fast retransmit)、快速恢复(fast recovery)。拥塞窗口(cwnd,congestionwindow),其大小取决于网络的拥塞程度,并且动态地在变化。
慢开始算法的思路就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。为了防止cwnd(拥塞窗口) 增长过大引起网络拥塞,还需设置一个慢开始门限 ssthresh 状态变量。
- 当 cwnd < ssthresh 时,使用慢开始算法。
- 当 cwnd > ssthresh 时,改用拥塞避免算法。
- 当 cwnd = ssthresh 时,慢开始与拥塞避免算法任意。
拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间 RTT 就把发送发的拥塞窗口 cwnd 加 1,而不是加倍。无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞,就把慢开始门限设置为出现拥塞时的发送窗口大小的一半。然后把拥塞窗口设置为 1,执行慢开始算法。
拥塞控制的具体过程如下:
- TCP 连接初始化,将拥塞窗口设置为 1
- 执行慢开始算法,cwnd 按指数规律增长,直到 cwnd=ssthresh 时,开始执行拥塞避免算法,
- cwnd 按线性规律增长
- 当网络发生拥塞,把 ssthresh 值更新为拥塞前 ssthresh 值的一半,cwnd 重新设置为 1,按照步骤(2)执行
快重传和快恢复
快速重传(Fast retransmit)要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方),而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到 3 个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计数器时间到期。
快速恢复(Fast Recovery)
- 当发送方连续收到三个重复确认,就执行“乘法减小”算法,把慢开始门限 ssthresh 减半。这是为了预防网络发生拥塞。注意:接下去不执行慢开始算法(此时不是发生了拥塞)。
- 由于发送方现在认为网络很可能没有发生拥塞,因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口 cwnd 现在不设置为 1),而是把 cwnd 值设置为慢开始门限 ssthresh 减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。