可靠、有连接、首部消耗大、全双工通信、面向字节流
TCP提供可靠的有连接服务
因为有连接,所以TCP仅支持一对一通信
传送单元称为报文段
TCP格式
源/目的端口号:各占2B
序列号:4B,本次报文段的开始字节序号
确认号:4B,已经接收到前面的所有字节,期待收到的下一个报文段的起始字节序号
数据偏移:1B,以4B为单位,标识整个报文段中,数据部分的起始位置
保留位:6bit
控制-URG:1bit,表示该报文段需要尽快处理,与紧急指针配合使用
控制-ACK:1bit,确认号有效标识,仅在请求建立连接报文为0,其余所有报文均为1
控制-PSH:1bit,Push标志为1时,接收方尽快交付应用层,无需等待接收缓存填满
控制-RST:1bit,Reset标志为1时,标识TCP连接出错,需先释放在重新连接
控制-SYN:1bit,SYN=1,ACK=0时,为请求建立连接报文,SYN=1,ACK=1时,为连接接受报文
控制-FIN:1bit,当某一当要释放连接时,发送FIN=1报文,标识本方数据已发送完,请求释放连接
窗口大小:2B,用于拥塞控制,指出现在还允许发送多少数据(动态改变)
校验和:2B,数据报校验和计算
紧急指针:2B,在本报文段中多少字节数据是紧急的,从数据的第一个字节开始算
选项+填充:选项最初只规定了一种MSS,最大报文段长度,总长度可变,不超过40B,必须为4B的整数倍
TCP连接
连接建立
- 服务端持续监听端口
- 客户端发送请求建立连接报文,其中SYN=1,ACK(标志)=0,seq=x,此时可以不可携带数据
- 服务端返回连接接受报文,并分配本次连接所需的缓存、变量等资源,其中SYN=1,ACK(标志,此后均为1)=1,ack(序号)=x+1,seq=y,仍然不可携带数据
- 客户端返回确认的确认,并分配本次连接所需的缓存、变量等资源,此时SYN=0,ack=y+1,seq=x+1,正式建立连接,可以携带数据
- 传送数据
连接释放
- 客户端和服务端均可主动断开连接,设客户端发起关闭请求,FIN=1,seq=u,ack=v,说明自己不再会发送更多数据。
- 服务端(等待关闭状态)仍然可以正常发送数据,当发送最后一个报文段时,服务端将FIN置为1,seq=w,ack=u+1
- 客户端返回对该报文段的确ack=w+1,seq=u+1,当服务端收到时服务端关闭,此时客户端TCP连接可能还未释放,等待2MSL(最长报文寿命)后再关闭(尽量确保这次握手被收到)
TCP可靠传输
可靠目标
数据正确到达
实现方式
确认、重传、序号
序号
对于报文段中的每一个字节,都对应TCP的一个序号,起始序号一般随机取
:::info
客户端起始序号在发送请求连接报文处取,请求连接报文虽然不携带数据,但是会消耗一个序号
服务端起始序号在返回连接接受报文处取,不携带数据,但是消耗一个序号
:::
在一次TCP连接中,多个报文段序号共用
确认
对于发送方发送的数据,当接收方在确认时,会携带ack确认号,表明确认号之前的所有字节均已接收到。
重传
超时:当发送的报文段超过设置的时间(略大于加权平均RTT时间)没有收到确认,就会进行重传
冗余ACK:接收方多次对同一个报文段进行确认时,对报文段进行重传
例如当发送方发送1,2,3,4,5号报文段之后,2号报文段丢失了,此时接收方接收到1,3,4,5,则只能对报文段1进行确认,表明期望接收报文段2,当收到3,4,5,这些失序报文段时,就一个冗余ACK,再次表明期望接收报文段2,当发送方三次收到对1号报文段的确认,期望接收2号报文段时,就认为2号报文段丢失,进行重传
TCP流量控制/拥塞控制
流量控制与拥塞控制的区别
流量控制目的在于匹配两主机之间的数据传输速率
拥塞控制目的在于使得整体网络负载量不超负荷
流量控制
基于滑动窗口机制进行流量控制。
TCP报文段中包含接收窗口,表明自身还可接收多少字节数据,如rwnd=400,表明还可接收多少数据。
同时发送方对当前网络拥塞状况进行估计,确定一个拥塞窗口cwnd。
发送窗口根据rwnd(接收窗口)与cwnd(拥塞窗口)动态取min值
拥塞控制
慢开始算法
初始时,取cwnd=1,即一个MSS
每收到一个对新报文的确认(经过一个RTT),cwnd2,试探性的注入流量
其增长是指数趋势的,当cwnd增大到一定的ssthresh阈值的时候,改用拥塞避免算法
拥塞避免算法
每收到一个对新报文的确认,cwnd+1,逐步增加网络流量
*乘法减小
在执行这些算法的时候,就有可能出现拥塞,当发送方判断网络出现拥塞(未按时收到确认),将ssthresh的值更改为拥塞窗口的一半(乘法减小)。并重新从cwnd=1(慢开始)执行拥塞控制
快重传和快恢复
快重传,利用重传机制中的冗余ACK,当发送方连续收到三个重复ACK时就直接重传而不等待重传计时器。
快恢复,当收到三个冗余ACK之后,执行乘法减小,将ssthresh改为cwnd/2,但是不从cwnd=1执行慢开始,而将cwnd=cwnd/2处开始,执行拥塞避免算法。