tcp的三次握手
1.第一次握手:首先由客户端发送syn包假设序号为x。
第一次握手是为了检查客户端的发送功能
2.第二次握手:服务器接受到客户端发送的syn(x),然后发送ack(x+1)和syn(y)给客户端。
第二次握手是为了检查服务端的接受和发送功能
3.第三次握手:客户端接收到syn(y)后发送ack(y+1)给服务端。
第三次握手是为了检查客户端的接收功能
syn(synchronized sequence number)同步序列号,其实就是消息的序号,客户端和服务端分开算
ack(x + 1),就是应答,也可以理解成我已经收到了第x条消息,期待第x+1条消息
时序图:
半连接队列的作用
其实就像一个计时器,服务器收到连接请求后会把连接放入半连接队列然后发送ack和syn,只有客户端在规定时间内返回正确的ack,连接才会被放入全连接队列,否则服务器就会重发ack和syn直到到达最大重传次数(默认值为5)
全连接队列作用
全连接队列的主要作用是等待应用层通过accept()
函数来处理这些已经建立的连接。应用层通过调用accept()
函数从全连接队列中取出连接,并开始处理数据传输。
队列溢出
半连接队列溢出:如果半连接队列满了,服务器会丢弃新的SYN请求,或者根据配置返回RST包。可以通过调整/proc/sys/net/ipv4/tcp_max_syn_backlog
参数来增加半连接队列的长度。
全连接队列溢出:如果全连接队列满了,服务器会根据/proc/sys/net/ipv4/tcp_abort_on_overflow
参数的配置来处理:
- 当
tcp_abort_on_overflow=0
时,服务器会丢弃客户端的ACK,客户端会重传ACK,但服务器不会处理。 - 当
tcp_abort_on_overflow=1
时,服务器会发送RST包给客户端,表示放弃这个连接。
为什么要三次握手?
三次握手是为了,主要是防止历史连接的干扰。
如果有三次握手的话:
tcp的四次挥手
因为tcp全双工的特性所以要确认两方都断开连接。
tcp的四次挥手其实可以看作客户端告诉服务器说我要断开连接了,然后服务端说收到;再服务端告诉客户端说我要断开连接了,客户端回复收到,就这么简单。
1.第一次挥手:客户端准备好断开连接后发送FIN包(FIN
标志位为1的TCP报文)给服务器,seq为x,客户端进入FIN_WAIT_1
状态。
但是这时的tcp连接出于半关闭状态,客户端已经告诉服务器自己不再发送数据了,但仍然可以接收服务器发送过来的数据。
2.第二次挥手:服务端收到客户端的FIN报文后会发送一个ack(x+1),seq为y,给客户端;然后服务器进入CLOSE_WAIT
状态。客户端收到ack后进入FIN_WAIT_2
状态
这就代表客户端已经确认完了,接下来就是服务端确认
3.第三次挥手:服务端准备好关闭连接后也是先发送一个FIN报文,seq为y+n(n为tcp连接在半关闭状态下发送的消息数)给客户端。服务端进入LAST_ACK
状态。
4.第四次挥手:客户端收到后返回一个ack(y+n+1),seq为x+1,客户端进入TIME_WAIT
状态,并在TIME_WAIT计时结束后(2MSL)关闭连接,服务端则是收到ack后关闭连接。当两端都关闭后tcp连接正式断开。
MSL:最大报文段生存时间
时序图:
我们分析一下三次挥手可以不
我们这样来看好像是行的,就是要改变一下策略,原先可能服务端收到了客户端的断开连接请求后可以直接先返回一个ack然后做好断开连接的准备(把要传的数据传完),准备好在发FIN;但是如果只有三次握手的话服务端就必须在回复客户端前做好连接断开前准备才可以回复客户端,否则可能造成数据丢失。
但是我有个问题就是再客户端等待过程中(如果服务端准备时间过长),客户端没法判断是服务端正在准备还是发送的请求丢了(或是别的网络问题)引起的。我想这可能也是为什么是四次挥手的原因之一。