We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UDP: User Datagram Protocol,用户数据报协议。
UDP是一个面向无连接的传输层协议。
UDP首部是固定的8字节,由四个字段组成,每个字段都是两个字节。
TCP: Transmission Control Protocol,传输控制协议。
TCP是一个面向连接的,可靠的,基于字节流的传输层协议。
TCP首部包括固定的20字节以及可选项,这里只介绍固定的20字节中的常用字段。
TCP三次握手的目的是确认通信双方的两样能力:发送能力和接收能力。
客户端:在吗?我要和你对话,这个x是我的数据初始序号seq。
服务端:我在,同意建立连接,这个y是我的数据初始序号seq,我希望下一次收到序号为x+1的数据。
客户端:收到,接下来要开始通信了,我希望下一次收到序号为y+1的数据。
总结: 第一次握手能让服务端确认客户端的发送能力 第二次握手能让客户端确认服务端的发送和接收能力 第三次握手能让服务端确认客户端的接收能力
根本原因:无法确认客户端的接收能力。
分析:假设两次握手就能建立连接。
现在客户端发了一个SYN为1的数据包,但由于网络原因这个数据包滞留在了网络中没有送达。客户端迟迟没有收到确认包,就误以为是丢包了,于是重传。这次的数据包送达,服务端返回确认,两次握手建立好了连接。
当连接关闭后,那个滞留的数据包又到达了服务端,由于现在是两次握手,服务端接收到之后就回复确认,默认建立连接,但此时的客户端已经断开了。
这就带来了连接资源的浪费
三次握手的目的是确认双方发送和接收的能力,当然再多次也可以,但是没有意义。
第三次握手的时候可以,前两次不可以。
如果第一次能携带数据,那么一旦有人想攻击服务器,就会在第一次握手时携带大量数据,服务端就要耗费大量时间和内存去处理这些数据,增大了服务器被攻击的风险。
至于第二次握手,此时服务端无法确认客户端是否具有接收能力,如果携带数据的话无法保证送达。
第三次客户端已经处于ESTABLISHED状态,并且能确认服务端发送和接收能力正常,所以可以携带数据。
客户端先发送一个请求断开数据包,其中FIN为1,序号seq为u,u是最后一次接收到的数据最后一个字节的序列号+1。
服务端收到该数据包后,返回一个确认数据包。其中ACK为1,确认号ack为u+1,序号seq为v,v由服务端发送给客户端最后一个包的确认号来决定
此时客户端就不能给服务端发信息了,只能接受,但是服务端还可以发。
当服务端没有可传的信息后,会再发送一个请求断开数据包,其中FIN为1,ACK为1,确认号ack为u+1,序号seq为w,这里的w和上面的v是一个意思,但由于这一步和上一步中间可能还在发数据,所以这个seq可能会变。
客户端接收到FIN=1的数据包之后,会返回一个确认数据包,其中ACK为1,seq=u+1,ack为w+1。发送完之后,客户段会等待两个MSL(Maximum Segment Lifetime,报文最大生存时间),如果这段时间内客户端没收到服务端重发的FIN数据包,那么挥手结束。
因为客户端最后一个ACK数据包可能在传输时丢失,然后服务端迟迟没收到确认包就会重传FIN数据包。
如果客户段不等待两个MSL,就不会收到这个重传的FIN数据包,也就不会再重发ACK数据包,服务器就会因为收不到ACK数据包无法正确关闭。
因为服务端在接收到FIN数据包后,往往不会立即返回FIN数据包,而是先返回一个ACK确认包,告知对方自己已收到,然后将所有信息都发送完毕后,才会发送FIN数据包。
这样将ACK数据包与FIN数据包分开发送,就导致了四次挥手。
如果将ACK数据包合并到FIN数据包里,缩减为三次挥手。由于FIN数据包要等到所有数据发送完毕,所以可能有会延时,从而导致客户端迟迟收不到确认,然后不断重发FIN数据包。
三次握手前,服务端状态由CLOSED变为LISTEN,会同时在内部创建两个队列:半连接队列和全连接队列
半连接队列:当客户端发送SYN数据包到服务端,服务端收到后回复ACK+SYN数据包后,就会将这个TCP连接推入半连接队列。
全连接队列:当三次握手完成时,就会将这个TCP连接推入全连接队列,等待被具体应用取走。
也称为SYN洪泛攻击,原理就是攻击者伪造大量不存在的IP地址,并向服务端疯狂发送SYN数据包请求连接。当服务端返回ACK数据包后,该攻击者不对其进行再确认。
对于服务端而言,这会导致两个危险的结果:
处理大量的SYN数据包并返回对应ACK数据包,会导致大量TCP连接处于半连接状态,从而占满整个半连接队列,无法处理正常请求。
由于是不存在的IP,服务端长时间收不到客户端的ACK确认,就会不断重发数据,直到耗尽服务端的资源。
顾名思义,TCP快速打开(TCP Fast Open,即TFO)就是为了解决每次都要三次握手才能建连的问题。
它利用SYN Cookie技术来实现。
首轮三次握手
后面的三次握手
注意: 客户端最后握手的 ACK 不一定要等到服务端的 HTTP 响应到达才发送,两个过程没有任何关系。
TFO的优势在于后面的握手,在拿到客户端的SYN Cookie并验证通过以后,服务端可以直接返回HTTP响应,充分利用了1个RTT的时间提前进行数据传输,积累起来还是一个比较大的优势。
双方在使用TCP进行通信时,很可能发送方的速率和接收方的速率是不相等的。如果发送方发送的速率过快,而接收方处理又需要时间,这时候接收方只能把处理不过来的数据放入接收缓存区里(失序的数据包也会放入接收缓存区里)。
如果接收缓存区满了,发送方还在一直发送数据,接收方只能把收到的数据包丢掉,这就会产生大量的丢包,浪费网络资源。
因此我们需要根据接收缓存区的大小,动态调整发送方的发送,这就是所谓的流量控制。
TCP通过滑动窗口的概念来实现流量控制,由于TCP是全双工的传输层协议,因此通信双方都各有两个滑动窗口。
当发送方停止发送数据后,该怎样才能知道自己可以继续发送数据?
当发送方收到接受窗口win = 0时,就停止停止发送数据包,并且同时开启一个定时器,每隔一段时间就发个测试报文去询问接收方,打听是否可以继续发送数据了,如果可以,接收方就告诉他此时接受窗口的大小;如果接受窗口大小还是为0,则发送方再次刷新启动定时器。
流量控制与接收方的接收窗口相关联,并没有考虑到整个网络环境的影响。
如果说当前网络特别差,特别拥塞,发送方发出去的数据包都被堵在路上了,迟迟没有到达接收方。发送方迟迟收不到回应,就会以为丢包了,然后进行重传。但这样的结果就是不但浪费了网络资源,还使得网络更加拥塞了,因此,我们需要拥塞控制。
对于拥塞控制来说,每条TCP连接都要维护两个状态:
拥塞控制包含以下几个算法:
拥塞窗口指的是目前自己还能传输的数据量大小,用来限制发送窗口。
发送窗口 = min(接收窗口,拥塞窗口)
发送窗口会取两者的较小值。而拥塞控制,就是来控制拥塞窗口的。
三次握手结束,刚进入传输阶段的时候,发送方并不知道当前的网络状况如何。如果一开始就快速大量的发送数据包,很可能会导致大量的丢包和网络拥塞。
所以,拥塞控制首先要做的就是采用一种保守算法来慢慢的适应整个网络,这个算法就叫做慢启动。
过程如下:
但也不会一直翻倍下去,当拥塞窗口大小到达一个阀值时,就不会涨那么快了,这个阀值就叫慢启动阀值。
到达慢启动阀值后,如何控制拥塞窗口大小呢?
那就是拥塞避免要做的事情了。
当到达慢启动阀值后,发送方每收到一个ACK确认数据包,拥塞窗口大小会增加1。
也就是说,以前一个RTT下来,拥塞窗口大小翻倍,现在只增加1而已。
当然,慢启动和拥塞避免是一起作用的,是一体的。
在TCP传输过程中,如果接收方发现数据包不是按序到达的,也就是发现了丢包,就会重复发送之前的ACK数据包。
比如第5个包丢了,即使6.7个包已到达,也会先存在缓存区里,然后接收方会一律返回第4个包的ACK确认包。
当发送方收到3个重复的ACK数据包时,会意识到丢包了,然后马上进行重传,不用等到一个RTO(重传超时时间)再进行重传。
当发送方收到3个重复的ACK数据包时,发现丢包,就会觉得当前的网络有点拥塞了,自己会进入快速恢复阶段。
在这个阶段,发送方发生以下改变:
以上就是TCP拥塞控制的经典算法: 慢启动、拥塞避免、快速重传和快速恢复。
TCP协议灵魂之问,巩固你的网路底层基础 前端需要了解的计算机网络知识 通俗易懂讲解TCP流量控制机制
The text was updated successfully, but these errors were encountered:
No branches or pull requests
UDP
UDP: User Datagram Protocol,用户数据报协议。
UDP是一个面向无连接的传输层协议。
UDP特点
UDP首部
UDP首部是固定的8字节,由四个字段组成,每个字段都是两个字节。
TCP
TCP: Transmission Control Protocol,传输控制协议。
TCP是一个面向连接的,可靠的,基于字节流的传输层协议。
TCP特点
TCP首部
TCP首部包括固定的20字节以及可选项,这里只介绍固定的20字节中的常用字段。
TCP三次握手
TCP三次握手的目的是确认通信双方的两样能力:发送能力和接收能力。
总结:
第一次握手能让服务端确认客户端的发送能力
第二次握手能让客户端确认服务端的发送和接收能力
第三次握手能让服务端确认客户端的接收能力
为什么不是两次握手?
根本原因:无法确认客户端的接收能力。
分析:假设两次握手就能建立连接。
现在客户端发了一个SYN为1的数据包,但由于网络原因这个数据包滞留在了网络中没有送达。客户端迟迟没有收到确认包,就误以为是丢包了,于是重传。这次的数据包送达,服务端返回确认,两次握手建立好了连接。
当连接关闭后,那个滞留的数据包又到达了服务端,由于现在是两次握手,服务端接收到之后就回复确认,默认建立连接,但此时的客户端已经断开了。
这就带来了连接资源的浪费
为什么不是四次握手?
三次握手的目的是确认双方发送和接收的能力,当然再多次也可以,但是没有意义。
三次握手过程中可以携带数据么?
第三次握手的时候可以,前两次不可以。
如果第一次能携带数据,那么一旦有人想攻击服务器,就会在第一次握手时携带大量数据,服务端就要耗费大量时间和内存去处理这些数据,增大了服务器被攻击的风险。
至于第二次握手,此时服务端无法确认客户端是否具有接收能力,如果携带数据的话无法保证送达。
第三次客户端已经处于ESTABLISHED状态,并且能确认服务端发送和接收能力正常,所以可以携带数据。
TCP四次挥手
客户端先发送一个请求断开数据包,其中FIN为1,序号seq为u,u是最后一次接收到的数据最后一个字节的序列号+1。
服务端收到该数据包后,返回一个确认数据包。其中ACK为1,确认号ack为u+1,序号seq为v,v由服务端发送给客户端最后一个包的确认号来决定
当服务端没有可传的信息后,会再发送一个请求断开数据包,其中FIN为1,ACK为1,确认号ack为u+1,序号seq为w,这里的w和上面的v是一个意思,但由于这一步和上一步中间可能还在发数据,所以这个seq可能会变。
客户端接收到FIN=1的数据包之后,会返回一个确认数据包,其中ACK为1,seq=u+1,ack为w+1。发送完之后,客户段会等待两个MSL(Maximum Segment Lifetime,报文最大生存时间),如果这段时间内客户端没收到服务端重发的FIN数据包,那么挥手结束。
为什么要等待两个MSL(报文最大生存时间)?
因为客户端最后一个ACK数据包可能在传输时丢失,然后服务端迟迟没收到确认包就会重传FIN数据包。
如果客户段不等待两个MSL,就不会收到这个重传的FIN数据包,也就不会再重发ACK数据包,服务器就会因为收不到ACK数据包无法正确关闭。
为什么不是三次挥手?
因为服务端在接收到FIN数据包后,往往不会立即返回FIN数据包,而是先返回一个ACK确认包,告知对方自己已收到,然后将所有信息都发送完毕后,才会发送FIN数据包。
这样将ACK数据包与FIN数据包分开发送,就导致了四次挥手。
如果将ACK数据包合并到FIN数据包里,缩减为三次挥手。由于FIN数据包要等到所有数据发送完毕,所以可能有会延时,从而导致客户端迟迟收不到确认,然后不断重发FIN数据包。
半连接队列和全连接队列
三次握手前,服务端状态由CLOSED变为LISTEN,会同时在内部创建两个队列:半连接队列和全连接队列
半连接队列:当客户端发送SYN数据包到服务端,服务端收到后回复ACK+SYN数据包后,就会将这个TCP连接推入半连接队列。
全连接队列:当三次握手完成时,就会将这个TCP连接推入全连接队列,等待被具体应用取走。
SYN Flood攻击
也称为SYN洪泛攻击,原理就是攻击者伪造大量不存在的IP地址,并向服务端疯狂发送SYN数据包请求连接。当服务端返回ACK数据包后,该攻击者不对其进行再确认。
对于服务端而言,这会导致两个危险的结果:
处理大量的SYN数据包并返回对应ACK数据包,会导致大量TCP连接处于半连接状态,从而占满整个半连接队列,无法处理正常请求。
由于是不存在的IP,服务端长时间收不到客户端的ACK确认,就会不断重发数据,直到耗尽服务端的资源。
如何应对SYN Flood攻击
TCP快速打开(TFO)
顾名思义,TCP快速打开(TCP Fast Open,即TFO)就是为了解决每次都要三次握手才能建连的问题。
它利用SYN Cookie技术来实现。
TFO的流程
首轮三次握手
后面的三次握手
注意: 客户端最后握手的 ACK 不一定要等到服务端的 HTTP 响应到达才发送,两个过程没有任何关系。
TFO的优势
TFO的优势在于后面的握手,在拿到客户端的SYN Cookie并验证通过以后,服务端可以直接返回HTTP响应,充分利用了1个RTT的时间提前进行数据传输,积累起来还是一个比较大的优势。
TCP流量控制
双方在使用TCP进行通信时,很可能发送方的速率和接收方的速率是不相等的。如果发送方发送的速率过快,而接收方处理又需要时间,这时候接收方只能把处理不过来的数据放入接收缓存区里(失序的数据包也会放入接收缓存区里)。
如果接收缓存区满了,发送方还在一直发送数据,接收方只能把收到的数据包丢掉,这就会产生大量的丢包,浪费网络资源。
因此我们需要根据接收缓存区的大小,动态调整发送方的发送,这就是所谓的流量控制。
滑动窗口
TCP通过滑动窗口的概念来实现流量控制,由于TCP是全双工的传输层协议,因此通信双方都各有两个滑动窗口。
流量控制具体过程
发送方何时再继续发送数据?
当发送方停止发送数据后,该怎样才能知道自己可以继续发送数据?
当发送方收到接受窗口win = 0时,就停止停止发送数据包,并且同时开启一个定时器,每隔一段时间就发个测试报文去询问接收方,打听是否可以继续发送数据了,如果可以,接收方就告诉他此时接受窗口的大小;如果接受窗口大小还是为0,则发送方再次刷新启动定时器。
TCP拥塞控制
流量控制与接收方的接收窗口相关联,并没有考虑到整个网络环境的影响。
如果说当前网络特别差,特别拥塞,发送方发出去的数据包都被堵在路上了,迟迟没有到达接收方。发送方迟迟收不到回应,就会以为丢包了,然后进行重传。但这样的结果就是不但浪费了网络资源,还使得网络更加拥塞了,因此,我们需要拥塞控制。
对于拥塞控制来说,每条TCP连接都要维护两个状态:
拥塞控制包含以下几个算法:
拥塞窗口
拥塞窗口指的是目前自己还能传输的数据量大小,用来限制发送窗口。
发送窗口会取两者的较小值。而拥塞控制,就是来控制拥塞窗口的。
慢启动
三次握手结束,刚进入传输阶段的时候,发送方并不知道当前的网络状况如何。如果一开始就快速大量的发送数据包,很可能会导致大量的丢包和网络拥塞。
所以,拥塞控制首先要做的就是采用一种保守算法来慢慢的适应整个网络,这个算法就叫做慢启动。
过程如下:
但也不会一直翻倍下去,当拥塞窗口大小到达一个阀值时,就不会涨那么快了,这个阀值就叫慢启动阀值。
到达慢启动阀值后,如何控制拥塞窗口大小呢?
那就是拥塞避免要做的事情了。
拥塞避免
当到达慢启动阀值后,发送方每收到一个ACK确认数据包,拥塞窗口大小会增加1。
也就是说,以前一个RTT下来,拥塞窗口大小翻倍,现在只增加1而已。
当然,慢启动和拥塞避免是一起作用的,是一体的。
快速重传
在TCP传输过程中,如果接收方发现数据包不是按序到达的,也就是发现了丢包,就会重复发送之前的ACK数据包。
比如第5个包丢了,即使6.7个包已到达,也会先存在缓存区里,然后接收方会一律返回第4个包的ACK确认包。
当发送方收到3个重复的ACK数据包时,会意识到丢包了,然后马上进行重传,不用等到一个RTO(重传超时时间)再进行重传。
快速恢复
当发送方收到3个重复的ACK数据包时,发现丢包,就会觉得当前的网络有点拥塞了,自己会进入快速恢复阶段。
在这个阶段,发送方发生以下改变:
以上就是TCP拥塞控制的经典算法: 慢启动、拥塞避免、快速重传和快速恢复。
参考
TCP协议灵魂之问,巩固你的网路底层基础
前端需要了解的计算机网络知识
通俗易懂讲解TCP流量控制机制
The text was updated successfully, but these errors were encountered: