1.TCP简述
TCP也叫传输控制协议
是一种面向连接的可靠传输协议
面向连接:指的是数据传输之前,收发双方需要先建立一条逻辑通路
无面向连接:指的是数据可以自由传输,无需建立逻辑通路
TCP是在不可靠的IP层之上,实现可靠的数据传输能力。数据有序,无丢失,不重复
TCP的的可靠性主要体现在四个方面
确认,重传,排序,流控
TCP提供全双工通信 --- 除了TCP还有UDP的数据防止出现丢失使用缓存
^发送缓存
*存放发送应用程序传输给发送方TCP准备发送的数据
*存放TCP已发送但是尚未收到确认的数据
^接收缓存
*不按序到达的数据
*按序到达,但未被应用程序接收的数据
TCP是面向字节流的
2.TCP头部报文段
TCP首部信息,最短20字节
*序列号:可以理解为字节流的编号。每发送一个字节的数据,序列号+1
*确认序列号:是收到的报文的序列号+收到的数据部分字节大小
确认机制:每收到一个发送方发出的数据,都需要回复一个确认报文
1.表明接收方期望收到发送方发送的下一个字节的序号。
2.代表接收方已经收到了确认序列号之前的所有字节数据
累计确认 --- 查看信息的时候有多少信息就确认多少信息不会一个一个回复
*数据偏移:TCP报文段的数据起始距离TCP报文段的起始处的距离。其本质是在描述TCP首部大小
*保留:占6bit ,为一个保留位,只起占据作用
*窗口:每次发送或接收数据的最大容量,但每次发送可以分为多次且连续发送
*紧急指针:与控制位中的URG字段共同使用,当URG=1,紧急指针有效 --- 优先处理数据
紧急数据会被TCP放置在数据部分的最前方,即从第0个字节开始,而紧急指针是为了表明紧急数据的结束位置 --- 例如:紧急指针为70,则紧急数据位置为0字节到69字节
*选项字段:最大报文段长度MSS:窗口扩大因子:时间戳:选择确认机制。安全摘要选项
标志位:
*紧急位URG:报文段中包含紧急数据,是最高优先级的数据,应尽快传输,不再缓存队列中排队
*确认位ACK:当确认位置为1,则确认序列号有意义,在连接连接以后所有传输的报文段都必须把ACK置为1
*推送位PSH:接收方应尽快将数据交付给应用程序,不再等待缓存填满再向上提交 ---与紧急位不同的是紧急位只将紧急的数据提交,而推送位直接全部提交
*复位RST:表明TCP连接中出现错误,必须释放连接,然后重新建立连接
*同步位SYN:表明这是一个连接请求报文
*终止位FIN:表明发送方数据已完全发送,要求释放连接
3.TCP的可靠性
3.1确认机制
TCP的确认机制分为
1.累计确认
TCP的确认是累计确认机制,正确接收失序的报文段是不会被接收方逐个确认的。因此,发送方在重传的时候,需要将冗余ACK报文及之后的报文段都重新发送一遍 ---导致资源浪费
2.选择确认机制
TCP在可选项字段中,添加了一个变量。该变量中携带的就是自己已经收到的数据信息。
而变量里没有的就是没收到的数据信息,此时客户端只要发送变量里没有的即可
选择确认机制,不是所有运行TCP协议的设备都支持的。该机制会TCP三次握手的前两次SYN报文中进行协商
3.2重传机制
1.超时重传
当超过一定时间未收到确认报文,则触发重传机制
RTT/RTO
超时重传的判断时间依据RTT(往返时间)参数来判断。RTO被称为超时重传时间
---RTT---指的是发送端将数据发出后,到他接收到对端反馈的确认报文之间你的这段时间
RTO取值应该略大于RTT,但是也不能太大。RTT并非是固定数值,他是动态变化的数值
超时间隔加倍机制。当连续多次未收到确认报文,设备会认为是网络拥塞过大,将重传时间加倍,因为如果按照原本的重传时间发送报文,很可能造成网络拥塞的加剧
2.快速重传
在TCP中,发送方可以通过接收方的反馈,在超时时间到达前,意识到数据包丢失的现象,并进行重传。这种情况一般出现在接收端收到一个失序报文的情况下,并且当接收方意识到自己所期望的报文段丢失,服务端不能调取失序报文,并且不能确认这些报文信息,因为TCP不能发送否定确认包,没办法告诉对端自身哪个数据包没有收到。
因此解决方法就是在RTO时间到之前,采用冗余ACK的方式来完成缺失报文的通告,让对方意思到数据包丢失,从而进行重传
3.3排序机制
为了排序,传输的数据可能是乱传输的数据大小不一,就需要分段,分片,最后才进行排序
如图为一个数据帧的图解,图中划分了MTU与MSS的部分有助于理解排序的时候乱序了怎么分的过程
最大字节数由MSS控制。该参数是需要在TCP连接握手的过程中,通过前两次SYN报文段来进行参数协商。
如果双方的MSS数值不同,则选择数值较小的作为传输标准
MSS受到MTU限制
MTU:最大传输单元,指的是数据链路层在封装成帧时允许携带的最大数据量,在以太网当中,MTU数值为1500字节
MSS:数据段中携带的数据字节数
MSS===MTU - IP首部 - TCP首部
分片:这个操作是由网络层的IP协议来执行
分段:这个操作是由传输层的TCP协议来执行
分片与分段都用于控制MTU或MSS的可携带数据量限制
在最后
通过序列号字段,保证分段的有序性。将根据序列号的大小,将乱序的报文段进行重组
3.4流控机制
1.TCP的流量控制机制
窗口
流量控制说到底还是是属于TCP的传输效率问题
TCP头部中的"窗口值"是TCP实现流控的核心参数,窗口的大小,其实体现的就是接收缓存区的大小。
TCP要求发送方依据对方的接收窗口(rwnd)来控制数据的发送量。最初,TCP的接口窗口===接收缓存区大小。接口窗口会随着时间的增长而动态变化,也称为滑动窗口
在面向连接三次握手开始时客户端与服务端会协商好窗口值的大小,以便数据一次性转发的大小
窗口关闭
窗口的大小是接收端根据自己的缓存空间的剩余量来决定的一个动态变化的数值,那么这个剩余量有归0的可能性。也就代表此时接收方所有缓存空间均已占用并且没能及时处理里面的资源
所以,当接收方反馈窗口值为0时,那其实就是在通知发送方,别再发送数据,处理不过来
该机制存在风险:接收方通过确认ACK报文来通知发送方自己的窗口大小。理论上,如果接收方将 自己的缓存里的数据清空后,将反馈一个窗口值非0的报文来通知对端,可以继续发送数据了。但是如果 这个非0的ACK报文在重传过程中丢失。----会引发风险,因为确认报文丢失不会触发重传机制。所以,客 户端依然处于窗口关闭状态,不会发送数据,在等待服务器的响应。而服务器也在等待客户端发送数 据。此时,两者进入到死锁状态。
解决方式:客户端周期性发送窗口探测报文,该报文只包含TCP首部信息。通过触发TCP确认机制, 来让服务端发送确认报文,从而告知客户端,此时的窗口大小。打破死锁现象
窗口扩大因子
TCP选项字段中的窗口扩大因子,可以解决首部中窗口值过小的问题。因为首部中窗口值大小仅为 16bit,最大值为65536。
窗口扩大因子占据3字节大小。取值仅为0-14。是用来将TCP的窗口的值左移的位数,使得原本的窗 口值加倍。
如果在面向连接三次握手开始同步位中窗口大小不够可以在此时通过窗口因子扩大窗口
2.TCP的拥塞控制机制
网络中避免不了有一时的波动会造成网络拥塞等等情况
中间链路的处理能力--->拥塞控制机制
网络中对资源需求量超过了资源的可用量情况,被称为拥塞
如果出现了拥塞情况,--->分组丢失。重传--->网络的拥塞情况加剧
流量控制是为了让接收方能够来得及接收,而拥塞控制是为了降低整个网络的堵塞程度
TCP如何判断此时网络环境出现拥塞
TCP将连接中出现的丢包行为,视为拥塞的表现
1. 一种是数据包确认超时
2.收到来自接收方发送的三个冗余ACK报文
TCP如何来控制数据的发送量
拥塞窗口--->跟接收窗口一样,都可以对发送的字节数大小进行限制
发送方,发出未收到确认的报文的字节数,必须小于或等于拥塞窗口和接收窗口的最小值
拥塞窗口的数值是依靠TCP拥塞控制算法得出。TCP是在保证能够支持的最大传输效率的情况下,来保证没有拥塞发生。被称为自计时 --->通过收到的确认报文来增加拥塞窗口
拥塞控制算法 --->慢启动,拥塞避免,快速恢复
慢启动--->通常在开始传输数据时,拥塞窗口会被设置的很小。一般等于一个MSS数值。即一次只能发送一个数据报文段
^每收到一个新的ACK确认报文,就会增加一倍MSS的大小
^TCP会设定一个慢启动门限来评判。评判是是否要停止慢启动的机制
*当拥塞窗口<门限,继续使用慢启动算法
*当拥塞窗口>门限,此时将慢启动算法切换为拥塞避免算法
*当拥塞窗口 = 门限,两者均可使用
拥塞避免
^在一个RTT时间线内,拥塞窗口只增加一个MSS
^拥塞避免算法,不是说直接避免拥塞,而是通过降低窗口的增大速率而使得网络不容易出现拥塞
快速恢复
^如果网络中没有发生拥塞,那么拥塞窗口就会无时无刻的增长下去
^如果出现了拥塞,那么这个增长必须停止
假设,最开始传输数据时,慢启动门限为16
1.通过慢启动算法,逐步增加窗口大小
2.当窗口大小>=门限值,则切换为避免拥塞算法
3.当网络中出现拥塞情况后,因为确认报文超市而判断的拥塞
3.1 此时将慢启动门限值设定为上次门限值一半,此时为8
3.2 将窗口大小设定为1
4.如果拥塞是因为三次冗余ACK而判断的拥塞 --->快恢复
4.1 将慢启动门限值设定为上一次门限值的一半
4.2 将窗口大小设定为此时的门限值,直接开始使用拥塞避免算法进行扩大窗口
5.此时重新启动慢启动算法,重复之前过程
延迟确认应答机制
收到数据以后不立即返回确认报文,而是延迟一段时间
*在没有收到2*MSS的数据为止,不做确认应答。
*其他情况,最大延迟0.5秒发送确认应当
捎带应答
TCP的确认应答和回执数据可以通过一个数据包进行发送
延迟确认机制和捎带应答一般共同使用
4.TCP的面向连接,连接管理
连接管理包含以下
连接建立,数据传输,连接释放
其中包含三次握手与四次挥手的过程
4 1.三次握手
1.1状态机
客户端
SYN_SENT:客户端发送SYN报文段请求建立连接
ESTABLISHED:在收到服务端发来的SYN请求报文以及确认报文后就建立客户端到服务端的连接
服务端
LISTEN:一开始时LISTEN状态,等待客户端的SYN请求
SYN_RCVD:当服务端接收到客户端发来的SYN请求后服务端变为接收状态并发送SYN请求,此时的状态也称为半连接队列
ESTABLISHED:当客户端收到SYN报文并且回复确认报文且服务端收到后建立连接
1.2初始序列号ISN
问题:1.初始序列号是什么产生的?2.为什么是随机值,而不是固定值?
1.初始序列号--->ISN:初始序列号是通过源地址,目的地址,源端口,目的端口和一个随机因子通过哈希算法计算得出的。后续又加入了时间因子
2.出于安全性考虑,如果被知道了初始序列号,那么很容易可以构造出一个在对方窗口内的序列号。从而伪造出TCP报文,实现RCP会话劫持。
拓展:TCP序号绕回问题
*重复序号:当序号绕回后,之前已经使用过的序号可能再次出现,导致接收方错误的将重复的报文段当作新的报文段处理。从而丢弃正常的报文
*延迟确认:因为延迟确认是收到一定数量的数据后才发送,而序号绕回会导致延迟确认的触发时间延后,从而降低数据传输的效率
解决思路:使用时间戳选项来增加序号的有效范围
1.3是否可以使用“两次握手报文”建立连接
采用三次握手形式,不是因为两次握手无法建立连接,而是为了防止已经失效的连接请求报文突然又传送到TCP服务端,从而导致服务端回复信息,建立连接,凭空消耗资源
第一次握手可以证明的是客户端的发送能力正常
第二次握手证明客户端的接收能力正常,且服务端的发送能力正常
如果不进行第三次握手则无法证明客户端的接收能力是否正常
1.4三次握手如何阻止历史连接
*当客户端发送连接建立请求报文后,因为网络阻塞,导致客户端重新发送一个连接建立请求报文,这两个报文的序列号不同(因为为初始序列号)。
*当网络阻塞减小时,可能旧的报文先到达服务端,从而导致服务端回复SYN+ACK报文。此时服务端处于同步已接收状态(SYN-RCVD),但是此时对于客户端而言,服务端回复的报文时错误的报文,因为其确认序列号与客户端将要发送的报文的序列号不匹配,则客户端发送RST报文,断开连接。
*当连接断开,服务端恢复到侦听状态,此时客户端发送的第二个连接请求报文到达。之后,正常建立TCP连接。
*如果是两次握手,那么服务端在收到旧的SYN报文后,会直接进入到连接已建立状态。在该状态意味着已经可以发送数据,可能会存在数据传输。但是又因为此时的连接对于客户端而言是错误的,所以此时服务端传输的数据客户端不会接收。
1.5如果已经建立了连接,但是客户端突然故障,怎么办?
*TCP设计了一个保活计时器
*如果客户端出现故障,服务端不能一直等待下去,因为会白白浪费资源
服务端没收到一次客户端的请求后都会复位保活计时器,当保活计时器为0时,服务端主动发送探测报文。并每隔75s发送一次。如果连续十次报文都没有接收到对端回复,则服务端认为客户端出现故障,关闭连接
4.2.四次挥手
2.1状态机
四次挥手客户端与服务端的状态机
客户端
FIN_WAIT1:客户端的第一个状态---发送FIN标志位
FIN_WAIT2:客户端的第二个状态---在接受完服务端的确认报文段后,等待服务端发送完数据的状态,如果服务端已发送完数据即可等服务端发送FIN标志位的报文段进入TIME_WAIT
TIME_WAIT:客户端的倒数第二个状态---在等待2MSL时间以后,客户端切换状态,进入关闭状态。MSL时最长报文段寿命。默认建议时间为2分钟
CLOSE:当等待完2MSL后客户端都没有收到来自服务端的FIN重发报文段即可关闭
服务端
CLOSE_WAIT:服务端的第一个状态---在收到客户端发送的FIN后处于半关闭状态,客户端到服务端的连接释放断开,服务端给客户端发送确认FIN的报文,有数据就携带数据,无数据则发送第三次挥手报文段
LAST_ACK:服务端的倒数第二个状态,在服务端发送完数据后此时就发送FIN报文
CLOSE:当服务端收到FIN的确认报文后即可关闭
2.2为什么不能是三次挥手
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。此时如果服务端还有数据未发送完只能先发送一个带有数据的ACK报文,知道数据发送完毕,才发送FIN报文,因此不能是三次挥手
2.3四次挥手释放连接时,等待2MSL的意义?
MSL,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
4.3《TCP/IP详解 卷1》TCP变迁图
以下为一张TCP状态变迁图,很具有代表性,有助于大家理解三次握手和四次挥手的状态变化