三次握手,四次挥手(TCP)
示意图
tcp协议中内容,用于建立与断开连接.其中
- 三次握手用于建立连接,保证客户端与服务端各自的收发能力
- 四次挥手用于关闭连接,关闭双工连接
三次握手
- 三次握手为什么能保证双方各自的收发能力?
第一次握手
: 客户端向服务端发送SYN,如果服务端成功接收到,则服务端能确定客户端的发送能力、自己(服务端)的接收能力
在服务端接收完成后会在半连接队列中为SYN包开设一个条目,标识该连接处于Syn_RECV状态
第二次握手
: 服务端给客户端发送Syn+Ack,如果客户端接收到,则客户端能确定自己(客户端)的发送能力和接受能力,能确定服务端的发送能力和接受能力.此时客户端进入Established状态第三次握手
: 客户端给服务端发送Ack,如果服务端接收到,则服务端能确定客户端的接收能力和自己的发送能力,此时服务端进入Established状态
在第三次握手后服务端将从半连接队列删除本次连接,将本次连接加入全连接队列
- 为什么需要三次握手
- 三次握手能够保证双方各自的收发能力.
- 可以组织重复历史连接的初始化:
客户端发给服务端的某个报文,因为网络原因留在了网络中,然后本次连接结束了,新连接开始了,这是旧报文又发到了服务端,服务端返回ack,然后客户端返回RST断开连接(第三次握手)。为什么客户端能识别出这是旧请求的ack:如果是最新请求的ack,则该ack的序列号应该是客户端最近生成的序列号+1.
- 可以同步双方的序列号
第一次握手SYN客户端发送初始序列号,然后服务端第二次握手序列号+1,然后还需要保证这个序列号被客户端接收到了(第三次握手) - 避免资源的浪费
四次挥手
一定是四次挥手嘛?
不一定.第二次挥手和第三次挥手可能合并,当服务端接收到第一次挥手的SYN后,如果服务端->客户端的方向上没有数据要发送时,第二次和第三次挥手可以合并为一次.如果连接中,服务器挂了,客户端会断开连接吗
- 当服务器挂了指的是进程崩溃时,内核会向客户端发送FIN,完成四次挥手
- 当服务器挂了指的是服务器宕机时:
如果客户端向服务器发送了请求,会失败,则会引起重试机制,当最远重试间隔达到某一阈值时,客户端会关闭连接
如果客户端未向服务器发送请求,这时取决于客户端的keepAlive设置
如果开启了keepAlive机制,客户端会定时向服务器发送检测报文,如果发现服务器掉线则断开连接
如果没有开启keepAlive机制,就会保持连接直至发送请求讲讲拥塞控制
拥塞控制是防止过多的数据进入到网络层,造成过负载.是针对全局而言的
- 慢开始算法
cwnd从1开始逐渐翻倍,网络阻塞时重置为1 - 拥塞避免算法
cwnd达到ssthresh后,cwnd的增长方式不再是翻倍,而是+1,当网络阻塞时就爱那个ssthresh/2,cwnd重置为1 - 快重传算法
当客户端发现没有接收到某个报文时,传回三个ACK,然后服务端马上重传丢失的报文而不用等待定时器超时 - 快恢复算法
一般与快重传算法一起.当收到三个ACK后(说明网络情况没那么糟糕)即窗口和慢开始上限均变为窗口大小的一半1
2cwnd=cwnd/2
ssthresh = cwnd
timewait是多久
2MSL为什么要有timewait
- 处理延时的报文,防止对后续连接有影响
并不能保证完全处理掉延时的报文,如果要完全处理应该考虑对方的重传次数,最大超时重传时间,MSL,远不止2MSL
- 保证被动关闭方收到了自己的ack
TIME_WAIT至少需要持续2MSL时长,这2个MSL中的第一个MSL是为了等自己发出去的最后一个ACK从网络中消失,而第二MSL是为了等在对端收到ACK之前的一刹那可能重传的FIN报文从网络中消失。
timewait的坏处
连接处于timewait状态时,该端口已经不再进行实际的通信,但是端口号没有释放,占用着端口号
在高并发环境下,可能造成大量的端口号处于timewait状态,占用着端口资源
另外大量的timewait也会占用内存,cpu资源(当然这不是主要的坏处)如何解决大量的timewait
- 修改系统内核参数
1
2
3net.ipv4.tcp.tw.reuse = 1 //表示可重用timewait的端口
net.ipv4.tcp.tw.recycle = 1 //表示快速回收timewait端口
.... - 将短连接改为长连接
TCP,UDP区别
- Tcp面向连接,UDP无连接
- TCP可靠,UDP不可靠
- TCP具有重传机制(还有Ack机制),保证有序,Udp没有且无序
- tcp对系统资源要求多,相对慢;udp更快
- tcp有流量控制和拥塞控制的能力
TCP,udp各自应用场景
TCP: web浏览,文件传输,邮件…
UDP: 视频与直播流媒体, 网络游戏…tcp是长连接还是短连接
tcp既有长连接,也有短连接短连接: 每次请求都会新建,断开连接;方便管理(连接的都是有用的)但是频繁地新建断开浪费cpu资源
长连接: 请求完可以不断开连接;不方便管理(连接的都是有用的)但无需频繁地新建断开什么是tcp粘包
接收方接收到的某一个数据包中包含多个数据包(包括数据包发生拆包形成的小数据包)
解决方案:
- 为数据包头部添加数据包长度
- 为数据包之间添加特殊的分隔符
- 设置数据包长度为固定值,如果不够则用指定字符凑
- 怎么实现udp的可靠性
现在已经有了较成熟的udp可靠性方案: QUIC协议
- 如何实现可靠性的
QUIC也有重试机制,并且与tcp不同的是QUIC的序列号(Packet Header中的Packet Number)是递增的(tcp重传序列号是不变)
通过FrameHeader来保证顺序性,以Stream这种Frame类型为例,通过其中的StreamId和offset保证数据的有序性
优点:
可以解决tcp重传rtt歧义的问题(即接收到重传的数据,怎么知道是第一次发的还是哪次重传发的,导致rtt计算不准确)
可以乱序确认,即使某个序列号的数据没收到,也可以继续往下确认
- quic如何解决队头堵塞问题
tcp通过抽象Stream来实现请求的并发,但是共用的tcp窗口,如果一个stream丢包了,会把后面所有的stream都阻塞
quic为每一个steam分配一个独立的滑动窗口,即使一个Strean异常了,也不会阻塞其他的stream