TCP连接之三次握手,四次挥手👋

242 阅读7分钟

前言

高能预警:下文可能会引起身体不适(犯困),请谨慎阅读(给我读!)

TCP是什么

TCP是传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能。用户数据报协议(UDP)是同一层内另一个重要的传输协议。

在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。

应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来透过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认信息(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失并进行重传。TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和。

在了解TCP连接之前,我们需要先知道这几个请求状态:

  • LISTEN - 侦听来自远方TCP端口的连接请求

  • SYN-SENT - 在发送连接请求后等待匹配的连接请求

  • SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认

  • ESTABLISHED - 代表一个打开的连接,数据可以传送给用户即连接已经建立

  • FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认

  • FIN-WAIT-2 - 从远程TCP等待连接中断请求

  • CLOSE-WAIT - 等待从本地用户发来的连接中断请求

  • CLOSING - 等待远程TCP对连接中断的确认

  • LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认

  • TIME-WAIT - 等待足够的时间以确保远程TCP接收到连接中断请求的确认

  • CLOSED - 没有任何连接状态也就是关闭连接

TCP全双工特性

这个概念还是比较好理解的,简单概括一下其实就是两端都可以接收和发送数据包,不过这是其中一个重要的特性,所以单拎出来一个小标题说一下,这样比嵌套在文章里更加让人印象印刻一些。

三次握手

为了方便理解,先放上一张图片,这张图片表示TCP连接和关闭全过程,看不懂没关系,先看下文解释后再回来看图就会清晰很多:

  • 第一次握手:建立连接时,客户端发送SYN包到服务器,并进入SYN_SENT状态,等待服务器确认

  • 第二次握手:服务端收到SYN包,必须确认客户端的SYN,同时自己也发送一个SYN包,即SYN+ACK包,此时服务器 进入SYN-RECEIVED状态

  • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK,此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手

PS:关于SYN和ACK包的概念百度一下就可以,我这里为了方便大家就放上这两个概念:

  1. SYN: 是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN+ACK应答表示接收到了这个消息,最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。
  2. ACK: 是确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。在TCP/IP协议中,如果接收方成功的接收到数据,那么会回复一个ACK数据。通常ACK信号有自己固定的格式,长度大小,由接收方回复给发送方。

为什么是三次握手,而不是四次、五次、N次?

这是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

通俗的讲也就是TCP之前发的连接请求因为某种原因在网络节点上滞留了一段时间,不过这个时候它已经是失散多年的孩子了,早已被客户端淡忘,当服务器端接到这个可怜的孩子后再给客户端发请求确认说:“这是不是你的孩子啊”,这时客户端已经忘记了这个孩子,所以并不会对服务端发送确认,服务端傻傻等待反馈会浪费资源;三次握手是确保最低次数获取对方状态,第二次握手把SYN和ACK合并发送,握手过程是为了确保客户端和服务端的双工连接是正常的,TCP连接双方必须确保有一次SYN和ACK包的发送。

四次挥手

  • 第一次挥手:客户端发出送FIN并且进入FIN_WAIT_1状态
  • 第二次挥手:服务器收到客户端的后,发出ACK确认并进入CLOSE-WAIT状态
  • 第三次挥手:客户端收到服务器确认结果后,进入FIN_WAIT_2状态。此时服务器发送释放FIN信号,服务器进入LAST-ACK
  • 第四次挥手:客户端收到回复后,发送确认ACK,客户端进入TIME-WAIT,客户端经过等待后,客户端CLOSE,服务器收到确认后,立刻进入CLOSE状态

为什么不可以和连接时候一样使用三次挥手?

这是因为双工特性的的半关闭状态,客户端发送FIN只是单独关闭它自己的传输,这时候服务端响应ACK后如果有没有发送完的数据,服务端是可以继续发送的,因为它还没有关闭传输,只有服务端发送FIN后,客户端响应ACK,客户端和服务端才会依次进入CLOSE状态,这个过程三次挥手无法满足。

说到这里细心的朋友会发现上诉有两种状态还没有提到,分别为CLOSING和LISTEN,下面说下这两个状态:

· LISTEN:

   上述三次握手之前因为客户端和服务端都是CLOSE状态,所以还会有一个状态就是服务端创建socket监听之后变为LISTEN状态,然后客户端发送SYN请求连接。

· CLOSING:

   如果客户端发送了FIN,但是没有收到服务器的ACK,却收到了服务器的FIN,因为网络传输有时会有意外情况,所以这个状态会在ACK丢包的时候表示。

总结

这种底层知识在当今实干家遍地的行情里可能并不是被人所重视,但是作为前端工程师的我们应该多学习这些理论知识才能够做到知其然知其所以然,我这里简单总结一下,更多详细内容可以点击我主页右上角个人博客进行探讨。