序列号seq
占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生,给字节编上序号后,就给每一个报文段指派一个序号,序列号seq就是这个报文段中的第一个字节的数据编号。
用来解决网络包乱序(reordering)问题。确认号ack
占4个字节,期待收到对方下一个报文段的第一个数据字节的序号,序列号表示报文段携带数据的第一个字节的编号,而确认号指的是期望接受到下一个字节的编号,因此挡墙报文段最后一个字节的编号+1即是确认号。
用于确认收到,用来解决不丢包的问题。确认ACK
占1个比特位,仅当ACK=1,确认号字段才有效。ACK=0,确认号无效。同步SYN
连接建立时用于同步序号。当SYN=1,ACK=0表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使用SYN=1,ACK=1.因此,SYN=1表示这是一个连接请求,或连接接收报文,SYN这个标志位只有在TCP建立连接才会被置为1,握手完成后SYN标志位被置为0.终止FIN
用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。窗口大小
这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
用于解决流控的。
三次握手
step1:客户端发送SYN标志位为1,Sequence Number为x的连接请求报文段,然后客户端进入SYN_SEND状态,等待服务器的确认响应;
step2:服务器收到客户端的连接请求,对这个SYN报文段进行确认,然后发送Acknowledgment Number为x+1(Sequence Number+1),SYN标志位和ACK标志位均为1,Sequence Number为y的报文段(即SYN+ACK报文段)给客户端,此时服务器进入SYN_RECV状态;
step3:客户端收到服务器的SYN+ACK报文段,确认ACK后,发送ACK = 为y+1,SYN标志位为0,ACK标志位为1的报文段,发送完成后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手,客户端和服务器端成功地建立连接,可以开始传输数据了。
三次握手原因:
建立三次握手主要是因为A发送了再一次的确认,那么A为什么会再确认一次呢,主要是为了防止已失效的连接请求报文段又突然传送给B,从而产生了错误。
所谓“已失效的连接请求报文”是这样产生的,正常情况下,A发出连接请求,但是因为连接报文请求丢失而未收到确认,于是A再重传一次连接请求,后来收到了请求,并收到了确认,建立了连接,数据传输完毕后,就释放链接,A共发送了两次连接请求报文段,其中第一个丢失,第二个到达了B,没有“已失效的连接请求报文段”,但是还有异常情况下,A发送的请求报文连接段并没有丢失,而是在某个网络节点滞留较长时间,以致延误到请求释放后的某个时间到达B,本来是一个早已失效的报文段,但是B收到了此失效连接请求报文段后,就误以为A又重新发送的连接请求报文段,并发送确认报文段给A,同意建立连接,如果没有三次握手,那么B发送确认后,连接就建立了,而此时A没有发送建立连接的请求报文段,于是不理会B的确认,也不会给B发送数据,而B却一直等待A发送数据,因此B的许多资源就浪费了,采用三次握手的方式就可以防止这种事情发生,例如刚刚,A不理会B,就不会给B发送确认,B收不到A的确认,就知道A不要求建立连接,就不会白白浪费资源。
四次挥手
- 发送方和接收方都需要Fin和Ack。只不过,有一方是被动的
四次挥手原因
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
等待2MSL
TCP的TIME_WAIT需要等待2MSL,当TCP的一端发起主动关闭,三次挥手完成后发送第四次挥手的ACK包后就进入这个状态,等待2MSL时间主要目的是:防止最后一个ACK包对方没有收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可以继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。
TCP如何保证可靠传输
- TCP要保证所有的数据包都可以到达,所以,必需要有重传机制
- 超时重传机制
设长了,重发就慢,丢了老半天才重发,没有效率,性能差;
设短了,会导致可能并没有丢就重发。于是重发的就快,会增加网络拥塞,导致更多的超时,更多的超时导致更多的重发。 - 快速重传机制 不用等timeout了再重传
- STACK区
TCP的流量控制与滑动窗口
TCP必需要知道网络实际的数据处理带宽或是数据处理速度,这样才不会引起网络拥塞,导致丢包
上图中分成了四个部分,分别是:(其中那个黑模型就是滑动窗口)
- 1已收到ack确认的数据。
- 2发还没收到ack的。
- 3在窗口中还没有发出的(接收方还有空间)。
- 4窗口以外的数据(接收方没空间)
下面我们来看一个接受端控制发送端的图示:
TCP的拥塞控制与拥塞窗口
拥塞控制主要是四个算法:
- 慢启动
1)连接建好的开始先初始化cwnd = 1,表明可以传一个MSS大小的数据。
2)每当收到一个ACK,cwnd++; 呈线性上升
3)每当过了一个RTT,cwnd = cwnd*2; 呈指数让升
4)还有一个ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”
- 拥塞避免
当cwnd >= ssthresh
1)收到一个ACK时,cwnd = cwnd + 1/cwnd
2)当每过一个RTT时,cwnd = cwnd + 1
- 拥塞发生
1)等到RTO超时,重传数据包。TCP认为这种情况太糟糕,反应也很强烈。
sshthresh = cwnd /2
cwnd 重置为 1
进入慢启动过程
2)Fast Retransmit快速重传算法,也就是在收到3个duplicate ACK时就开启重传,而不用等到RTO超时。
TCP Tahoe的实现和RTO超时一样。
TCP Reno的实现是:
cwnd = cwnd /2
sshthresh = cwnd
进入快速恢复算法
- 快速恢复
1)cwnd = sshthresh + 3 * MSS (3的意思是确认有3个数据包被收到了)
2)重传Duplicated ACKs指定的数据包
3)如果再收到 duplicated Acks,那么cwnd = cwnd +1
4)如果收到了新的Ack,那么,cwnd = sshthresh ,然后就进入了拥塞避免的算法了。