TCP 的 三次握手 四次握手

解释 

  • 同步 SYN :synchronous。创建链接,将 SYN = 1。
  • 序号 seq: sequence。第一个字节的编号随机产生。
  • 确认位 ACK : acknowledgement 。
  • ack : 表示确认字段的值。(对哪一个进行确认)。
  • 结束 FIN : finish。FIN = 1 表示但愿断开链接。

状态 

  • SYN-SENT : 同步已发送。
  • SYN-RCVD:同步收到。
  • ESTABLISHED: 已创建链接。
  • FIN-WAIT-1:终止等待1。
  • FIN-WAIT-2:终止等待2。
  • CLOSE-WAIT: 关闭等待。 
  • LAST-ACK : 最后确认。
  • TIME-WAIT: 时间等待。 
  • CLOSED :关闭状态。

三报文握手

TCP创建链接的过程叫作握手,握手须要在客户和服务器之间交换三个 TCP 报文段。html



最初,客户端和服务器的 TCP 进程都处于 CLOSED (关闭) 状态。B 的 TCP 服务器进程先建立 传输控制块 TCB ,准备接受客户进程的链接请求。而后服务器进程处于 LISTEN (收听) 状态,等待客户的链接请求。A 的 TCP 客户进程也是首先建立 传输控制块 TCB
服务器

第一次握手 : 客户端打算创建链接时,向服务器发出链接请求报文段,此时首部中的同步位 SYN = 1 ,同时选择一个初始须要 seq = x 。 TCP 规定,SYN = 1 的报文段 不能携带数据,但要消耗掉一个序号。这时,TCP 客户进程进入 SYN-SENT (同步已发送)状态。
网络

第二次握手:服务器收到链接请求报文段后,若是赞成创建链接,则向客户端发送确认。在确认报文段中应把 SYN 位 和 ACK 位 都置 1 ,确认号是 ack = x + 1,同时也为本身选择一个初始序号 seq = y。(这个报文段也不能携带数据,但一样要消耗掉一个序号。)这时 TCP 服务器进程进入 SYN-RCVD (同步收到) 状态。
计算机网络

第三次握手:客户端收到服务器的确认后,还要向服务器给出确认。确认报文段的 ACK 置为 1 ,确认号 ack = y + 1,而本身的序号 seq = x + 1 。这时, TCP 链接已经创建,客户端进入 ESTABLISHED (已创建链接) 状态。当 服务器 收到 客户端 的确认后,也进入 ESTABLISHED (已创建链接) 状态。3d

经过这样的三次握手,客户端与服务器端创建可靠的双工的链接,开始传送数据。三次握手的主要目的是保证链接是双工的,可靠更可能是经过重传机制来保证的。
cdn

为何 客户端 最后还要发送一次确认?

主要是为了防止已失效的链接请求报文段忽然又传到了 服务器,于是产生错误。 htm

现假定出现一种异常状况,即 客户端 发出的第一个链接请求报文段并无丢失,而是在某些网络结点长时间滞留了,以至延误到链接释放之后的某个时间才到达 服务器。原本这是一个早已失效的报文段。但 服务器 收到此失效的链接请求报文段后,就误认为是 客户端 又发出一次新的链接请求。因而就向 客户端 发出确认报文段,赞成创建链接。假定不采用报文握手,那么只要 服务器发出确认,新的链接就创建了。因为如今 客户端 并无发出创建链接的请求,所以不会理睬 服务器 的确认,也不会向 服务器 发送数据。可是 服务器 却觉得新的运输链接已经创建了,并一直等待 客户端 发来数据。服务器 的许多资源就这样白白浪费了。 采用三次报文握手的办法,能够防止上述现象的发生。假如在刚才的异常状况下,客户端 不会像 服务器 的确认发出确认。服务器 因为收不到确认,就知道 客户端 并无要求创建链接。
blog

四报文握手

数据传输结束后,通讯的双方均可以释放资源。此时 客户端 和 服务器 都处于 ESTABLISHED 状态。进程



第一次握手 : 客户端 的应用进程先向其 TCP 发出链接释放报文段,并中止在发送数据,主动关闭 TCP 链接。客户端把链接释放报文段首部的终止控制位 FIN 置 1,其序号 seq = u ,它等于前面已传过的数据的最后一个字节的序号加 1 。这时 客户端 进入 FIN-WAIT-1 (终止等待1) 状态,等待 服务器 的确认。( FIN 报文段即便不携带数据,它也消耗掉一个序号。)
资源

第二次握手:服务器收到链接释放报文段后即发出确认,确认号 ack = u + 1 ,而这个报文段 本身的序号是 v ,等于 服务器 前面已经传过的数据的最后一个字节的序号加 1 。而后 服务器 就进入 CLOSEWAIT(关闭等待)状态。TCP 服务器进程这时应通知高层应用进程(不肯定本身是否还有数据要发送给 客户端(因此是四次不是三次)),于是从 客户端 到 服务器 这个方向的链接就释放了,这时的 TCP 链接处于 半关闭(Half-close)状态,即 客户端 已经没有数据要发送了,但 服务器 若发送数据,客户端仍要接收。也就是说, 服务器 到 客户端 这个方向的链接并未关闭,这个状态可能会持续一段时间。

客户端 收到来自 服务器 的确认后,就进入 FIN-WAIT-2(终止等待2) 状态,等待 服务器 发出的链接释放报文段。

第三次握手:若 服务器 已经没有要向 客户端 发送的数据,其应用进程就通知 TCP 释放链接。这时 服务器发出的链接使用报文段必须使用 FIN = 1。现假设 服务器 的序号为 w(在半关闭状态 服务器 可能又发送了一些数据)。服务器还必须重复上次已发送过的确认号 ack = u + 1。这时 服务器 就进入 LAST-ACK (最后确认) 状态,等待 客户端 的确认。

第四次握手:客户端 在收到 服务器 的链接释放报文段后,必须对此发出确认。在确认报文段中把 ACK 置 1,确认号 ack = w + 1,而本身的序号是 seq = u + 1(根据 TCP 标准,前面发送过的 FIN 报文段要消耗一个序号)。而后进入到 TIME-WAIT(时间等待) 状态。请注意,TCP 链接如今尚未释放掉。必须通过 时间等待计时器(TIME-WAIT)设置的时间 2MSL 后,客户端 才进入到 CLOSED 状态。时间 MSL 叫作 最长报文段寿命,RFC 793 建议设为 2 分钟。

为何 客户端 在 TIME-WAIT 状态必须等待 2MSL 的时间呢?

第一,为了保证 客户端 发送的最后一个 ACK 报文段可以到达 服务器。这个 ACK 报文段有可能丢失,于是使 服务器 收不到确认。服务器 会超时重传这个 FIN + ACK 报文段,而 客户端 就能在 2MSL 时间内收到这个重传的报文段。接着 客户端 重传一次确认,从新启动 2MSL 计时器。最后,客户端 和 服务器 都能正常进入到 CLOSED 状态。若是 客户端 在 TIME-WAIT 状态不等待一段时间,而是在发送完 ACK 报文段后当即释放链接,那么就没法收到 服务器 重传 的 FIN+ACK 报文段,于是也不会再发送一次确认报文段。这样,服务器 就没法按照正常步骤进入 CLOSED 状态。

第二,防止“已失效的链接请求报文段” 出如今本次链接中。客户端 在发送完最后一个 ACK 报文段后,再通过 2MSL,就可使本次链接持续的时间内所产生的全部报文段都从网络中消失。这样就可使下一个新的链接中不会出现这种旧的链接请求报文段。

若是已经创建了链接,可是客户端忽然出现故障了怎么办?

TCP 设有一个 保活计时器。服务器每收到一次客户的数据,就从新设置保活计时器,时间的设置一般是两小时。若两小时没有收到客户的数据,服务器就发送一个 探测报文段 ,之后则每隔 75 秒钟发送一次。若一连发送 10 个探测报文段后仍无客户的响应,服务器就认为客户端出了故障,接着就关闭这个链接。


参考:《计算机网络》谢希仁