关于TCP协议的总结

关于TCP协议的总结_第1张图片

昨天下班在地铁上看到一篇关于TCP总结的博文,觉得非常好,这里借鉴过来,由于原文里有一些关于TCP协议部分晦涩难懂的部分,这里就不照搬过来了,只摘抄一些大家熟知的部分,例如三次握手,滑动窗口等。原文地址:朱小厮的博客(想体验原版还是推荐大家直接看谢希仁编著的计算机网络教材)

三次握手

关于TCP协议的总结_第2张图片

几个名词:
SYN:处于TCP连接建立过程
ACK:确认序号标志,为1时表示确认号有效,为0时表示报文中不含确认信息,忽略该字段。

连接过程
1. TCP服务器进程打开,准备接受客户进程的连接请求,此时服务器进入了LISTEN(监听)状态
2. 客户端向服务器发出连接请求报文,这时报文首部SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
3. TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1(确认号),自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。
4. 当服务器收到客户端的确认后也进入ESTABLISHED状态,双方可以开始通信。

关于建连接时SYN超时。如果server端接到了clien发的SYN后回了SYN-ACK后client掉线了,server端没有收到client回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。于是,server端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,TCP才会把断开这个连接。
解决方案:调整三个TCP参数可供选择,第一个是:tcp_synack_retries 可以用他来减少重试次数;第二个是:tcp_max_syn_backlog,可以增大SYN连接数;第三个是:tcp_abort_on_overflow 处理不过来干脆就直接拒绝连接了。

三次握手主要目的是:
1. 防止超时导致脏连接。如果使用的是两次握手建立连接,假设客户端发送了第一个请求连接并且没有丢失,只是因为在网络中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。
2. (Stackoverflow上给出的解答)要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的初始化的Sequence Number。这个号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序
Alice ---> Bob SYNchronize with my Initial Sequence Number of X
Alice <--- Bob    I received your syn, I ACKnowledge that I am ready for [X+1]
Alice <--- Bob    SYNchronize with my Initial Sequence Number of Y
Alice ---> Bob    I received your syn, I ACKnowledge that I am ready for [Y+1]
这样2人都知道对方的序号并发出了确认,因为第2和第3步可以放在一起,所以只需要3次通信

四次挥手

关于TCP协议的总结_第3张图片

几个名词:
FIN:发送端已完成数据传输,请求释放连接。
TIME_WAIT:主动要求关闭的机器表示收到了对方的FIN报文,并发送出了ACK报文,进入TIME_WAIT状态,等2MSL后即可进入到CLOSED状态。如果FIN_WAIT_1状态下,同时收到待FIN标识和ACK标识的报文时,可以直接进入TIME_WAIT状

态,而无需经过FIN_WAIT_2状态。
CLOSE_WAIT:被动关闭的机器收到对方请求关闭连接的FIN报文,在第一次ACK应答后,马上进入CLOSE_WAIT状态。这种状态其实标识在等待关闭,并且通知应用发送剩余数据,处理现场信息,关闭相关资源。

释放过程
1.数据传输完毕,客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2.服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3.客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文。
4.服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5.客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,才进入CLOSED状态。
6.服务器只要收到了客户端发出的确认,立即进入CLOSED状态

为什么客户端最后还要等待2MSL(为什么需要TIME_WAIT状态)?(最坏情况下,未收到4步的ACK,3步的FIN需要重发,去向ACK【第四步】最大存活时间(MSL) + 来向FIN【第三步】的最大存活时间(MSL))
MSL(Maximum Segment Lifetime,TCP允许不同的实现可以设置不同的MSL值)。第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失。站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。如果客户端收到服务端的FIN+ACK报文后,发送一个ACK给服务端之后就“自私”地立马进入CLOSED状态,可能会导致服务端无法确认收到最后的ACK指令,也就无法进入CLOSED状态。第二,防止失效请求。防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。防止在该段时间内创建两个具有相同IP和端口的连接

大量TIME_WAIT的影响?
在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。主动正常关闭TCP连接,都会出现TIMEWAIT。在业务处理+传输数据的时间 远远小于 TIMEWAIT超时的时间的情况下,持续的到达一定量的高并发短连接,会使服务器因端口资源不足而拒绝为一部分客户服务。可以通过负载均衡来变相的解决该问题。
查询TCP各个状态的连接数?netstat -ant|awk'/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}'
如何尽量处理TIME_WAIT过多?开启TIME-WAIT重用,表示TIME-WAIT状态的socket可以新的TCP连接;开启TIME-WAIT快速回收;加大用于向外连接的端口范围;减少系统同时保持TIME-WAIT的数量

调优
在TIME_WAIT状态无法真正释放句柄资源,在此期间,Socket中使用的本地端口在默认情况下不能再被使用。该限制对于客户端机器来说是无所谓的,但对于高并发服务器来说,会极大地限制有效连接的创建数量,称为性能瓶颈。所以建议将高并发服务器TIME_WAIT超时时间调小。RFC793中规定MSL为2分钟。但是在当前的高速网络中,2分钟的等待时间会造成资源的极大浪费,在高并发服务器上通常会使用更小的值。通过变更/etc/sysctl.conf文件来修改该默认值net.ipv4.tcp_fin_timout=30(建议小于30s)。修改完之后执行 /sbin/sysctl -p 让参数生效。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

滑动窗口(流控与重传)

关于TCP协议的总结_第4张图片
关于TCP协议的总结_第5张图片
关于TCP协议的总结_第6张图片

Ack是要按顺序的。必须要等到5的Ack收到,才会把6-11的Ack发送过去。这样就保证了滑动窗口的一个顺序。若5号ACK一直未确认,则会进行超时重传

关于TCP协议的总结_第7张图片

滑动窗口技术通过动态改变窗口大小来调节两台主机间的数据传输。每个TCP/IP主机支持全双工数据传输,因此TCP有两个滑动窗口:一个用于接收数据,另一个用于发送数据。TCP使用肯定确认技术,其确认号指的是下一个所期待的字节。滑动窗口协议,是TCP使用的一种流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。 只有在接收窗口向前滑动时(与此同时也发送了确认),发送窗口才有可能向前滑动。收发两端的窗口按照以上规律不断地向前滑动,因此这种协议又称为滑动窗口协议。

流量控制:端到端,接收端的应用层处理速度决定和网速无关,由接收端返回的rwnd控制
cwnd:发送端窗口( congestion window )
rwnd:接收端窗口(receiver window)

拥塞控制

发送端主动控制cwnd,有慢启动(从cwnd初始为1开始启动,指数启动),拥塞避免(到达ssthresh后,为了避免拥塞开始尝试线性增长),快重传(接收方每收到一个报文段都要回复一个当前最大连续位置的确认,当后面的序号先到达,如接收方接收到了1、 3、 4,而2没有收到,就会立即向发送方重复发送三次ACK=2的确认请求重传。发送方连续收到3个相同序号的ACK,就重传该数据包,而不用等待超时,并TCP马上把拥塞窗口 cwnd 减小到1),快恢复(直接从ssthresh线性增长)。

如果网络上的延时突然增加,那么TCP对这个事作出的应对只有重传数据,但是重传会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包。对此TCP的设计理念是:当拥塞发生的时候,要做自我牺牲。就像交通阻塞一样,每个车都应该把路让出来,而不要再去抢路了。

慢启动
只有在TCP连接建立和网络出现超时时才使用。每经过一个传输轮次,cwnd 就加倍。一个传输轮次所经历的时间其实就是往返时间RTT。慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大cwnd。
为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量。慢开始门限ssthresh的用法如下:
当 cwnd < ssthresh 时,使用上述的慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法。

拥塞避免算法:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

关于TCP协议的总结_第8张图片

无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

当TCP连接进行初始化时,把拥塞窗口cwnd置为1。在执行慢开始算法时,拥塞窗口cwnd随着传输轮次按指数规律增长。当拥塞窗口cwnd增长到慢开始门限值ssthresh时(即当cwnd=16时),就改为执行拥塞避免算法,拥塞窗口按线性规律增长。

强调:“拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。“拥塞避免”是说在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。

如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。这时,TCP马上把拥塞窗口 cwnd 减小到1,并执行慢开始算法,同时把慢开始门限值ssthresh减半。这是不使用快重传的情况。快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。

关于TCP协议的总结_第9张图片

接收方收到了M1和M2后都分别发出了确认。现在假定接收方没有收到M3但接着收到了M4。显然,接收方不能确认M4,因为M4是收到的失序报文段。根据可靠传输原理,接收方可以什么都不做,也可以在适当时机发送一次对M2的确认。但按照快重传算法的规定,接收方应及时发送对M2的重复确认,这样做可以让发送方及早知道报文段M3没有到达接收方。发送方接着发送了M5和M6。接收方收到这两个报文后,也还要再次发出对M2的重复确认。这样,发送方共收到了接收方的四个对M2的确认,其中后三个都是重复确认。快重传算法还规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必继续等待M3设置的重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。

关于TCP协议的总结_第10张图片
TCP Reno 版本在快重传之后采用快恢复算法而不是采用慢开始算法

与快重传配合使用的还有快恢复算法,其过程有以下两个要点:
1. 当发送方连续收到三个重复确认,就执行“乘法减小”算法,把慢启动门限ssthresh减半。这是为了预防网络发生拥塞。请注意:接下去不执行慢开始算法。
2. 由于发送方现在认为网络很可能没有发生拥塞,因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。

发送方窗口的上限值 = Min [ rwnd, cwnd ]
当rwnd < cwnd 时,是接收方的接收能力限制发送方窗口的最大值。
当cwnd < rwnd 时,则是网络的拥塞限制发送方窗口的最大值。

差错控制
TCP使用差错控制来提供可靠性。差错控制包括以下的一些机制:检测和重传受到损伤的报文段、重传丢失的报文段、保存失序到达的报文段直至缺失的报文到期,以及检测和丢弃重复的报文段。TCP通过三个简单的工具来完成其差错控制:检验和确认以及超时

其他

TCP与UDP区别:

TCP:面向连接;面向字节流;可靠交付;全双工通信;只支持一对一;
UDP:无连接不保证可靠;面向报文;无拥塞控制,适合多媒体传输;支持一对多,多对多等;首部开销小

backlog(linux内核中会维护两个队列)
1)未完成队列:接收到一个SYN建立连接请求,处于SYN_RCVD状态
2)已完成队列:已完成TCP三次握手过程,处于ESTABLISHED状态
当有一个SYN到来请求建立连接时,就在未完成队列中新建一项。当三次握手过程完成后,就将套接口从未完成队列移动到已完成队列。
backlog曾被定义为两个队列的总和的最大值,也曾将backlog的1.5倍作为未完成队列的最大长度

TCP/IP
是通信协议的统称(包括tcp,ip,udp,http,smtp等)
TCP/IP五层模型:应用(HTTP)-传输(TCP/UDP)-网络(IP协议,负责在没有直连的两个网络之间进行通信传输)-数据链路(提供直连两个设备之间的通信功能)-物理。物理层将电压高低、光的闪灭、电波强弱转换成二进制的01,数据链路层负责将二进制的01封装成帧,然后再进行传输。

IP协议
主要负责将数据包发送给最终的目标计算机。ip协议是面向无连接的,ip地址是IP协议的基石。DNS负责将域名转换为IP地址,ARP负责根据IP找到MAC地址,RARP功能与ARP相反。DHCP可以自动获取IP地址,若DHCP服务器故障,将导致无法分配IP,主机无法联网。socket是应用程序实现TCP/UDP的API

网络通信方式
分组交换,将要发送的数据分成多个数据包,按照一定的顺序排列之后分别发送,在每个分组的首部写入了发送端和接收端的地址。在分组交换中,由分组交换机(路由器)连接通信线路,发送端计算机将数据发送给路由器,路由器收到这些分组数据以后,缓存到自己的缓冲区,然后在转发给目标计算机。
网卡:计算机连接网络的设备
网桥:数据链路层连接两个网络的设备,能够识别数据链路层中的数据帧并将其转换成一个全新的帧发送给另一个网段
交换机:可以看做持有多个端口的网桥
路由器:作用在网络层,对分组报文进行转发

TCP/IP发送数据简要流程
应用层到传输层的TCP,TCP在数据前加上TCP首部,包括源端口与目的端口、校验和等,再到网络层IP协议,IP协议在数据前加上IP首部,IP首部包含源IP与目的IP,再交由路由器进行转发到数据链路层,在数据链路层给数据加上以太网首部,包含MAC地址等,可以通过ARP协议找到MAC地址

关于TCP协议的总结_第11张图片

TCP对HTTP性能影响的几个方面
三次握手慢启动拥塞控制Nagle算法(试图在发送分组前,将多个数据包绑定在一起以提高网络效率),用于捎带确认的TCP延迟确认算法(若确认报文较小,可以将其同数据一同发送,为了增加确认报文找到同向传输数据分组的可能性,TCP使用延迟算法,在一个特定的时间窗口停留以寻找能够捎带他的数据分组),TIME_WAIT时延与端口耗尽(TIME_WAIT防止在该段时间内创建两个具有相同IP和端口的连接)

HTTPS
采用共享密钥加密和公开密钥加密两者混合加密,使用非对称加密获取后续通信的秘钥,使用对称加密来进行通信(秘钥即为上步非对称加密获取的)

https通信过程与加密算法
非对称加密通信前要交换秘钥,由于非对称加密比对称加密慢,先生成一个对称加密算法秘钥,使用RSA(非对称加密)的方式发送给对方,随后只需使用这个对称加密来进行通信。那么如何确认双方身份并确保数据不被篡改?使用大家都公认的CA证书(包括公钥与个人信息,CA会用自己的私钥对消息摘要进行加密,对方再用CA公钥解密并对比查看是否被人篡改)。
具体过程:客户端请求服务端-》服务端返回CA(含后续非对称加密用的公钥)-》客户端用自己的CA解密-》客户端生成对称加密秘钥并用非对称方式发送给服务端-》服务端收到后双方使用对称加密方式通信

Http2.0与3.0部分区别
2.0:二进制格式传输数据而非1.x中的文本格式;多路复用,同一域名通信在单个连接上完成;首部压缩
3.0:放弃TCP,使用基于UDP的QUIC协议,减少RTT,重启TLS连接0RTT,则最多需要消耗初始TLS1.5RTT+信息传输1RTT = 2.5RTT【交易信息放在浏览器缓存中】(原始页面加载时间,三次握手1.5RTT(一个半来回)+SSL加密1.5RTT+信息传输1RTT);2.0多路复用若一个stream中的包丢失会影响其他stream上的包,3.0不存在该问题;重传序列号问题优化等。缺点比如UDP流量过大运营商丢包问题

HTTP方法
GET,POST,HEAD(只获取首部),PUT(将请求的主体部分存储在服务器上),TRACE(追踪,服务器最终会返回给客户端一条trace响应,并携带收到的报文,客户端可以检查报文是否被修改),OPTIONS(请求服务器告知其支持的方法和功能),DELETE

HTTP状态码

关于TCP协议的总结_第12张图片

HTTP常见首部
content-type,content-length,date,accept,expires,last-modified等

你可能感兴趣的:(关于TCP协议的总结)