tcp三次握手 四次挥手

tcp头部 

tcp三次握手 四次挥手_第1张图片

相关术语:

  • 一个连接由一个四元组(默认是tcp)或五元组来定义:即源ip,目的ip,源端口,目的端口,传输协议(tcp或udp)
  • 一个TCP连接通常分为三个阶段:启动、数据传输、退出(关闭)。
  • ISN(Initial Sequence Number):当SYN flag置1时的序列号

ISN = M + F(localhost, localport, remotehost, remoteport).

M是一个计时器,这个计时器每隔4μs加1。因此 ISN 会在大约 4.55 小时循环一次。而一个tcp段在网络中的最长寿命(Maximum Segment Lifetime )默认是2分钟,所以我们可以认为 ISN 会是唯一的。

F是一个Hash函数,根据源IP、目的IP、源端口、目的端口生成一个随机数值。

  • seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。
  • SYN(Synchronize Sequence Numbers):连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。
  • ACK (ACKnowledge Character):在数据通信传输中,接收端发给发送端的一种传输控制字符。它表示确认发来的数据已经接受无误。ACK在握手和挥手期间(即此时没有数据传输)通常为接收到的syn+1,如果在数据传输阶段,则ack为syn+1+len。len为传输的数据大小。
  • FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接
  • 3次握手是指发送了3个报文段,4次挥手是指发送了4个报文段
  • 3次握手的目的是交换双方的初始序列号ISN,TCP 的可靠性。让对方知道具有什么样的序列号的数据是合法的。

 

时序图

 

tcp三次握手 四次挥手_第2张图片

tcp三次握手 四次挥手_第3张图片 (图片来源:http://www.cnxct.com/something-about-phpfpm-s-backlog/)

三次握手详细步骤

tcp三次握手 四次挥手_第4张图片

1、client执行系统调用connect()发送syn(初始序列号为seq=x,随机生成)至server以请求建立一个连接,此时client的状态变为SYN_SENT,并等待server的SYN+ACK。如果在一段时间后没有收到,则重新发送,默认次数是5(tcp_syn_retries)。大约是180s。重试次数完成后还没收到,则放弃此连接。

 

2、server收到syn后,检查SYN_RCVD半连接队列是否达到阈值(tcp_max_tcp_backlog),如果达到阈值,则丢弃此syn,不予响应。如果没有达到阈值,则将这个连接信息存入这个半连接队列,只要进入队列,server状态就会由listen()变为SYN-RCVD,同时向client发送ack+syn(seq=y,ack=x+1)。并等待client回复一个ack。如果一段时间后没有收到ack,则会重新发送syn+ack。发送次数默认是5(tcp_synack_retries)。重试的间隔时间从1s开始,下次的重试间隔时间是前一次的双倍,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s, 总共31s, 称为指数退避,第5次发出后还要等32s才知道第5次也超时了,因此如果在1s + 2s + 4s+ 8s+ 16s + 32s = 63s后还没有收到cleint的ack回复,server会断开这个连接。


3、client接收到server发过来的syn+ack,进入ESTABLISHED状态(单方面认为)。同时向server发送ACK。server接收后,检查accept queue全连接队列是否达到阈值(取决于min(backlog, net.core.somaxconn) ,backlog是在socket创建的时候传入的,net.core.somaxconn是系统级别的一个端口能监听的最大连接数)。如果没满则进入队列,server由SYN_RECV变为accept状态,server端执行accept()系统调用,进入ESTABLISHED状态。如果满了,则按照tcp_abort_on_overflow的指示进行。如果值为0,那么server会丢掉client 发过来的ack(server端认为此时连接还没建立起来),此时客户端会显示read timeout。如果是1,server发送一个reset包给client,表示废掉这个握手过程和这个连接(本来在server端这个连接就还没建立起来)。客户端会显示connection reset by peer。

 

客户端状态变化路径:SYN_SENT ->ESTABLISHED

服务端状态变化路径:LISTEN->SYN_RECV ->ESTABLISHED

 

四次挥手详细步骤

1、 client执行系统调用close(),向server发送FIN+seq,由ESTABLISHED进入FIN_WAIT_1状态

client--->server:我已经没有数据要发送了,你还有数据发送吗?

2、 server收到FIN后,向client发送ACK表示确认,由ESTABLISHED进入CLOSE_WAIT状态。client收到server的ACK后,进入FIN_WAIT_2状态。

server-->client:我知道你已经没有数据要发送了,但我还要再确认一下我是不是还有数据要给你。

3、server将未完成的数据传完后,server向client发送FIN,进入LAST_ACK状态。

server-->client:好了,这下我也没有东西要给你了,你可以终结连接了。此时服务器不确认客户端是否收到信息,继续保持连接。

4、client收到server的FIN后,向server发送ACK,同时进入TIME_WAIT状态,启动TIME_WAIT定时器,超时时间设为2MSL。

服务器端收到ACK,执行系统调用close(),进入CLOSED状态。客户端在2MSL时间内没收到对端的任何响应,TIME_WAIT超时,进入CLOSED状态。

在客户端的TIME_WAIT状态持续2MSL的时间后,如果客户端没有收到服务器发来的任何消息,则客户端会终结连接。如果最后一步客户端发给服务器的ack丢失,服务器会重发fin给客户端,然后客户端再重发最后的ack给服务器。注意如果客户端此时不处于time_wait的话,客户端会发送RST给server,server会将此包解释为一个错误(在java中会抛出connection reset的SocketException)

client-->server: 我知道了,你也终结连接吧

 

客户端状态:ESTABLISHED——FIN_WAIT_1——FIN_WAIT_2——TIME_WAIT——CLOSED

服务端状态:ESTABLISHED——CLOSE_WAIT——LAST_ACK——CLOSED

 

 

 

 

 

你可能感兴趣的:(网络)