绪论:
承接上文,上文写到Tcp协议的结构以及对tcp协议的性能优化的滑动窗口,本章我们将继续了解Tcp协议的可靠性和高效性的具体展示。后面我将继续完善网络协议栈的网络层协议敬请期待!
话不多说安全带系好,发车啦(建议电脑观看)。
OSI定制的七层网络协议栈:
Tcp协议可靠性和高效性:
1. 再次对tcp序号的理解:
发送的数据本质是从发送缓冲区中来的,而发送缓冲区本质就是个字符类的数组,所以tcp的序号本质其实就是缓冲区数组的下标!
也就有一下几点需要注意的:
- 序号表示的并不是数据的起始位置,而是终点位置
- 返回来的确认序号表示的则是下一次从那个序号开始,而不是表示为下次要发的序号
- 接收、发送缓冲区:char类型的数组
我们看到的数组数据的插入和删除也就是所谓的面向字节流(流在缓冲区中是不断的进出进出的类似于流动的概念)
注:
- tcp是不管报文的分割的,他只进行将tcp报文的报头和有效载荷(数据)的分割,将数据存进对应的缓冲区中(留给应用层使用)
- 在不同的tcp连接中他们tcp报文的序号是能一致的,但因为每对tcp他们的源端口和目的端口是不一样的连接都要有自己的发送和接收缓冲区,所以并不会影响
2. 超时重传
先通过图片大概了解其过程,后面通过文字描述后就会更加清晰的认识
上图在A->B过程中报文丢失。
上图是B主机返回的应答丢失
上面都是超时重传的机制发送的情况:
当A主机发送报文给B主机,当一段时间内未收到返回的应答报文,那么主机A就会再次发送报文数据给B主机。
因为有了超时重传机制,所以也会一下问题:
主机B可能会接受到同一个报文(某个报文在某处堵塞了会,导致主机A又重传,而那个报文阻塞后发送到了B主机),所以主机B还需要能够识别出那些包是重复的包并去重(此时就可以通过查看序号是否重复)
也表明:
发送方一旦把数据发出去,一段时间内已经发送的数据是不能被移除的,要被暂时保存起来(于滑动窗口有关)。
网络的状态是变化的,超时时间设置太久会影响效率,超时时间太短过于频繁的重传(去重次数增加),所以超时时间也是变化的(根据网络的状况)
超时时间的设置:
在Linux中(BSD Unix和Windows也是如此),超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍。
- 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
- 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
- 累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接.
3. 连接管理
图中SYN_SENT(#define SYN_SENT 1)、SYN_RCVD、ESTABUSHED其实就是宏,将这几个宏对应的值填进下方结构体status中就完成了握手,三次握手是仅传递的是报头(不带数据)。
OS管理链接(先描述再组织)的本质就是结构体:
struct links
{
string src_ip;
string dst_ip;
int srcport/dstport;
uint64_t timestamp;
int status;
int urgdatatptr;//
struct links* next;
};
所谓的链接就是双方维护的数据结构
并且需要理解:建立维护 连接 是有成本的(时间 + 空间(创建结构体))
4. SYN洪水问题:
Server被发送大量SYN建立连接请求(建立连接是有成本的),但并不为了真正的连接。这些假链接就会导致真链接在传输过程中被大量假链接阻挡,从而导致三次握手完成不了,也就使其无法上网。
为什么要三次握手:
- 以最小成本印证全双工(全双工:既能接收数据又能发送数据;C、S都能验证你能接收和发送数据;第一连接能证明:Server能收数据、第二次连接能证明:Client能收 发数据,第三次连接才能证明S能发数据(发出报文并且收到答应ACK才能证明能发送数据,而只要能接受到数据就表明能接受数据)),一次两次都无法完成。
- 奇数次握手,能保证客户端优先把链接建立好,然后服务器才建立
- 4次握手 + 捎带应答 = 三次握手
四次挥手:
通过四次挥手进行连接的断开
他本质上来说也是能写成3次挥手的,但是因为在第二次挥手中,ACK和FIN一般不会同时发送(可以理解成断开连接是需要双方同意 确认的,所以需要分开来发送)(通俗的把三次握手看成渣男(发来就直接同意),把四次挥手看成结婚(需要双方同意))
断开连接需要 C -> S 和 S -> C(断开的本质是断开c 、 s的读写描述符也就是关闭打开文件,通过函数shutdown())
上图若不 close(断开连接)就会一直在 close_wait状态(而这个状态会持续较长时间),而文件描述符就没有被关闭,也就表明了连接还存在,就会持续的占用系统资源(维护的连接结构体)从而导致服务器越来越卡!(在网络应用中)
注:
查看一些配置信息(ip信息):ifconfig
在一台主机上,因为Tcp是全双工的所有连接一次就会有两个连接分别是S->C、C->S
5. 报文的最大存活时间(MLS)
TIME_WAIT(不认识的TIME_WAIT可以看看这篇blog)让报文消散原理:将TIME_WAIT时间设置比MLS长即可
TIME_WAIT存在的时间是:2MLS,这样就能一定保证阻塞的数据,再超时重传后不会再次发来(MLS时间就消散了,2MLS肯定没了)
(MLS是报文的最大存活时间,不同系统设定的时间是不一致的,其中centos7中MSL是60s)
查看MLS:
cat /proc/sys/net/ipv4/tcp_fin_timeout
6. 快(速)重传:
当发送方连续收到的ACK是同样的确认序号时,会立即将对应的报文进行补发(因为当发送方连续收到的ACK是同样的确认序号时,是不对的,本应该是收到每个发送数据对应的确认序号(序号+1),对此表示着有报文的丢失(因为正常的确认序号之前的数据都是收到的,所以丢失的报文就是发回来的确认序号后面的那个报文数据,下图返回的是1001(表示1000之前的数据是接收到的,而后面的丢失了)所以丢失的就是1001~2000的这段数据报文))
发送方,发送的数据发送出去,一段时间内,已经发送的数据不能被移除,会被暂时保存起来,这些暂时保存起来的数据都是在发送缓冲区的滑动窗口,只有收到对应的应答时,才会通过窗口滑动,删除指定的报文(被覆盖)
在当ACK丢了时:
- 最前面的ACK丢了时(1001),后面的ACK只要正常发送(2001),默认表示前面的数据也是被接收到了的(ACK答应报文)
- 而若是中间或者最后的报文丢了时,同样的转换成把他当成最前的ACK丢失,先看后面的是否有成功的(因为窗口是不断往右扫描的,当扫描到中间/最后时,它又变成了最前,这样就能套用1的方法)
7. 快(速)重传 VS 超时重传
快重传的前提连续收到三个以上的序号报文
快重传 和 超时重传他们是相互配合的:
超时重传是兜底的,快重传是提高效率的重传策略,两者相互配合
滑动窗口里面有很多可以直接发送的数据,为什么要分成多个数据段发送,不直接发一个就行了?
- TCP协议在传输数据时数据报文的最大消息长度(MSS)限制
- 避免设备处理不过来而导致的数据丢失或网络拥塞(数据从主机传送到另一个主机往往要经过路由器、网关等设备,这些设备对数据的处理能力有限。)
- 提高传输效率:并发多个发送多个数据段。
- 流量控制:接收方可以通过滑动窗口的大小来控制发送方的发送速度,从而避免网络拥塞(窗口)
- 差错控制:滑动窗口协议具有自动重传的功能
8. 拥塞控制:
若出现了大面积丢包,发送方就会判定是否是网络出现了问题(少量丢包采用重传是非常合理的,若大面积丢包则不能重传,就再不适合重传了,因为此时网络已经非常拥塞,再重传会损坏到网络甚至导致网络瘫痪(因为网络不止一个主机多台主机都再向该网络发送数据就可能会导致网络瘫痪))
所以tcp还考虑了网络的健康状态,即若出现大面积丢包,判断网络出现拥塞,拥塞避免算法。
TCP慢启动(拥塞算法)
先发送少量的数据,先摸清楚网络状况, 再决定按照多大的速度传输数据
若状态不好则先发送少量的数据,然后拥塞窗口然后再以2 ^ n 指数级的增长,前期慢 中后期快
拥塞窗口
拥塞窗口是发送数据的数值,当发送数据量超过这个拥塞窗口的值时,很大概率会网络拥塞。单次发送数据量的多少由滑动窗口决定,所以滑动窗口的大小就应该:
- 滑动窗口大小 = min(拥塞窗口大小,对方的窗口大小)
- win_start = ack+seq;
- win_end = min(拥塞窗口大小,对方的窗口大小)
拥塞控制算法:慢启动 机制
防止滑动窗口一下发送大量数据到网络中,而本来网络状态就是非常拥堵的,就会导致网络状态雪上加霜。
具体如下图(拥塞窗口的增长情况)
采取的方法:
- TCP引入 慢启动 机制, 先发少量的数据, 探探路,每次收到一个ACK应答, 拥塞窗口加1;摸清当前的网络拥堵状态记录,设置拥塞窗口从1开始进行慢启动方式(只是初始慢,增长时并不慢), 再决定按照多大的速度传输数据:
- 每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口
- 使用一个拥塞窗口的阈值(记为ssthresh值):当拥塞窗口增长到一定程度时到达ssthresh,由指数增长变成线性增长。
- 在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1
- 网络拥塞:
少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为 - 拥塞窗口必须一直在变化(探测),因为网络状态是需要一直被探测出来的
9. 延迟应答
作用:
通过当发送来一个报文后等待一段时间再发送的方法,让接收主机把发送来的数据给取走,从而扩大了窗口的大小,使后面再发送的数据能更大,提高了传输的效率。
其中:窗口越大, 网络吞吐量就越大, 传输效率就越高。
Tcp协议的目标就是在保证网络不拥塞的情况下尽量提高传输效率;
延迟应答一般有两种方法(也表明并不是所有的包都会延迟应答的):
- 数量限制: 每隔N个包就延迟应答一次(如上图:一般N取2)
- 时间限制: 超过最大延迟时间(200ms)就延迟应答一次(比如:当等待了200ms后应答一次(这样也能避免超时重传))
延迟应答使用的情况:
假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K; 但实际上可能处理端处理的速度很快, 10ms之内就500K数据从缓冲区消费掉了;在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;
10. TCP异常情况的解决方案(心跳机制)
- 进程终止:底层连接自动正常关闭(连接由OS管理,OS自动四次挥手)
- 机器重启:提示用户是否先关闭进程(然后再回到1情况)
- 机器掉电/网络断开
1. 对于长时间的直接掉电/网络断开,通过服务器的心跳机制解决
2. 对于短时间的掉电/网络断开(网线拔了又快速的插上),此时服务器的心跳机制还没启动所以服务器就认为是正常连接的,对此当服务器给用户再次发送response包时,用户就会返回带有标志位RST的报文,表示连接错误了需要重新连接(因为对用户来说还没进行三次握手能,服务器就直接发送了报文过来)
11. 滑动窗口
滑动窗口blog分开来写了可以看看这篇博客
本章完。预知后事如何,暂听下回分解。
如果有任何问题欢迎讨论哈!
如果觉得这篇文章对你有所帮助的话点点赞吧!
持续更新大量计算机网络细致内容,早关注不迷路。