TCP三次握手、四次挥手全过程,超详细

前言

国际标准化组织ISO在20世纪70年代提出一种使各种计算机在世界范围内互联成网的标准框架,即开放系统互联基本参考模型 OSI/RM(open system interconnection reference model),简称OSI。OSI的七层协议体系图如下:
TCP三次握手、四次挥手全过程,超详细_第1张图片
但是OSI七层模型既复杂又不实用,所以现在应用最广泛的不是国际标准OSI,而是非国际标准TCP/IP,体系架构图如下:
TCP三次握手、四次挥手全过程,超详细_第2张图片
本文所讲TCP、UDP都处在传输层。传输层任务就是负责向两个主机中的进程之间的通信提供通用的数据传输服务。

介绍

TCP

传输控制协议(Transmission Control Protocol)简称:TCP,提供面向连接的、可靠的数据传输服务,其数据传输的单位是报文段(segment)
TCP的主要特点:

  • TCP是面向连接的传输层协议。应用程序在使用TCP之前,必须先建立TCP连接。在数据传送完毕后,必须释放已经建立的TCP连接。
  • 每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的,这个“点”不是指主机,也不是应用进程,而是套接字(socket),根据RFC 793的定义:端口号拼接到IP地址即构成了套接字。也就是:ip:port
  • TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复、按序到达。
  • TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序把数据传送给TCP缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层应用进程在合适的时候读取缓存中的数据。
  • 面向字节流。TCP中的“流”指的是流入到进程或者从进程流出的字节序列

TCP虽然是面向字节流的,但是TCP传送的数据单元却是报文段。一个TCP报文段分为首部和数据两个部分,而TCP的全部功能都体现在它首部中的各个字段的作用。下图是TCP报文段首部格式:
TCP三次握手、四次挥手全过程,超详细_第3张图片
TCP报文首部前20个字节是固定的,后面4n(n为正整数)个字节是根据需要而增加的选项。首部数据含义如下:

  • 源端口和目的端口:各占2个字节(byte),分别写入源端口号和目的端口号。
  • 序号:占4个字节(byte)。序号范围是[0, 232-1],共232(即4294967296)个序号。序号增加到 232-1后,下一个序号就又回到0。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。这个字段的名称也叫做“报文段序号”。
  • 确认号:占4个字节(byte),是期望收到对方下一个报文段的第一个数据字节的序号
  • 数据偏移:占4位(bit),指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。实际上就是TCP报文段首部的长度,因为TCP首部具有可选项,所以长度是不确定的。需要注意的是数据偏移是有单位的,单位既不是byte,也不是bit,而是32bit(或者4byte)。如果TCP首部可选项为空的话,那么TCP首部长度就是20byte,数据偏移就是5(20 / 4 = 5),换算成二进制就是0101。由于4位二进制能表示的最大十进制数值为15,所以TCP首部最大长度为:15 * 4 (byte) = 60 (byte)
  • 保留:占6位(bit),保留为今后使用,目前应置为0.
  • URG:urgent (紧急的),占1位(bit),当URG=1时,表明紧急指针字段有效,告诉系统此报文段中有紧急数据,应但尽快传送(相当于高优先级的数据)。URG置为1,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据查到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中的紧急指针(Urgent Pointer)字段配合使用。
  • ACK:acknowledgment(确认),占1位(bit),当且仅当ACK=1确认号字段才有效。ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1.
  • PSH:push(推送),占1位(bit),当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。把PSH置1,接收方TCP收到后,就尽快交付给接收应用进程,而不再等到整个缓存都填满再向上交付。
  • RST:reset(复位),占1位(bit),当RST=1时,表明TCP连接中出现严重差错(例如主机奔溃等),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或者拒绝打开一个连接。RST也可称为重建位或者重置位。
  • SYN:synchronization(同步),占1位(bit),在建立连接时用来同步序号。当SYN=1ACK=0时表明这是一个连接请求报文段。对方若同意建立连接,则在响应的报文段中使用SYN=1ACK=1。因此,SYN=1就表示这是一个连接请求或者连接接受报文。
  • FIN:finish(终止),占1位(bit),用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已经发送完毕,并要求释放运输连接。
  • 窗口:占2个字节(byte),窗口值范围[0, 216-1]之间的整数。是指发送方接收窗口。是为了告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。窗口值作为接收方让发送方设置其发送窗口的依据。明确指出了现在允许对方发送的数据量,是经常在动态变化着。
  • 检验和:Checksum,占2个字节(byte),是一个端到端的校验和,由发送端计算,然后由接收端验证。其目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。校验和字段检测的范围包括首部和数据两个部分。要在TCP报文段的前面加上12字节的伪首部。接收方收到此报文,仍要加上这个伪首部来计算校验和。
  • 紧急指针:占2个字节(byte),紧急指针在URG=1时才有意义。指出本报文中紧急数据的字节数(紧急数据在普通数据的前面),因此,它指出了紧急数据末尾在报文段中的位置。当所有紧急数据处理完成后,TCP就告诉应用程序恢复到正常操作。即使窗口值为0也可以发送紧急数据

UDP

用户数据报协议(User Datagram Protocol)简称:UDP,提供无连接的、尽最大努力的数据传输服务(不保证数据传输的可靠性),其数据传输的单位是用户数据报
UDP的主要特点:

  • UDP是无连接的,即发送数据前不需要建立连接,所以发送数据结束时也没有连接可释放,因此减少了开销和发送数据之前的时延。
  • UDP使用最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。
  • UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就想下交付IP层。UDP对应用层交下来的报文既不合并,也不拆分,而是保留这些报文的边界。也就是说,应用层交给UDP多长的报文,UDP就照样发,即一次发送一个报文。在接收方的UDP,对IP层交上来的UDP用户数据报,在除去首部后就原封不动的交付上层应用。UDP一次交付一个完整的报文。因此,应用程序必须选择大小合适的报文,若报文太长,DUP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率。反之报文太短,UDP把它交给IP层后,会使IP数据报的首部的相对长度太大,这也降低了IP层的效率。
  • UDP没有拥塞控制,因此网络出现拥塞不会使发送方的发送速率降低。
  • UDP支持一对一、一对多、多对一和多对多的交互通信。
  • UDP首部开销小,只有8个字节,比TCP的20个字节的首部要短。

UDP有两部分:数据和首部。首部字段很简单,只有8个字节。如下图所示:
TCP三次握手、四次挥手全过程,超详细_第4张图片

  • 源端口:原端口号。在需要对方回信时选用。不需要时可用全0。
  • 目的端口:目的端口号。这在终点交付报文时必须要使用到。
  • 长度:UDP用户数据报的长度,最小值为8(仅有首部)。
  • 校验和:检测UDP用户数据报在传输中是否有错。有错就丢弃。

TCP三次握手

TCP在连接的过程中要解决三个问题:

  1. 要使每一方能够确知对方的存在
  2. 要允许双方协商一些参数(如:窗口最大值、是否使用窗口扩大选项和时间戳选项以及服务质量等)
  3. 能够对运输实体资源(如:缓存大小、连接表中的项目等)进行分配

TCP的连接采取客户服务器的方式。主动发起连接建立的应用进程叫做客户端(client),而被动等待连接建立的应用进程叫服务器(server)。连接过程如下:
TCP三次握手、四次挥手全过程,超详细_第5张图片
客户端A和服务器B下面的方框表示TCP进程所处状态。A主动打开连接,B被动打开连接。

  1. A的TCP客户进程首先创建传输控制块TCB,然后向B发送连接请求报文段,此时首部中的同步位SYN=1,同时选择一个初始序号seq=x。TCP规定,SYN报文段(即SYN=1的报文段)不能携带数据,但是要消耗一个序号。此时A的TCP客户进程进入SYN-SEND(同步已发送)状态。
  2. B收到连接请求报文段后,如同意建立连接,则向A发送确认。在确认报文首部中把SYN和ACK都置为1,确认号是ack=x+1,同时也为自己选择一个初始化序列号seq=y。这个报文也不能携带数据,同样也要消耗一个序号。此时B的TCP服务进程进入SYN-RCVD(同步收到)状态。
  3. TCP客户进程收到B的确认后,还要想B给出确认。确认报文段首部ACK置为1,确认号ack=y+1,而自己的序号seq=x+1。TCP规定,ACK报文段可以携带数据。但如果不携带数据则不消耗序号。这时,TCP连接已经建立,A进入ESTABLISHED(已建立连接)状态。B收到A的确认后,也进入ESTABLISHED状态。

这就是TCP三次握手的整个过程。

为什么还需要第三次握手,两次行不行
主要是为了防止已失效的连接请求报文段突然又传送到了B,因而产生错误。
A发出连接请求(第一次握手),但是连接请求报文丢失而未收到确认。于是A重传一次连接请求(第一次握手),收到了确认,建立连接,传输数据,关闭连接。如果A的第一次请求并没有丢失,而是在某些网络节点长时间滞留了,以至于连接释放后的某个时间才到达B,B收到此请求后,就误认为A又发了一次连接请求。于是就向A发出确认报文,同意建立连接。如果没有第三次握手,此时新的连接就建立了。由于A并没有发出新的建立连接的请求,因此会无视第二次握手,也不会向B确认(第三次握手)。但是B却认为连接已经建立,并一直等待A发送数据。B的许多资源就会因此浪费。此时采用三次握手,B由于收不到第三次握手,自然知道A没有发出请求,所以不会建立连接。

TCP四次挥手

数据传输结束后,通信的双方都可以释放连接,现在A和B都处在ESTABLISHED状态,假设有客户端A请求释放连接,则释放连接过程如下:
TCP三次握手、四次挥手全过程,超详细_第6张图片

  1. A的应用进程先向其TCP发送释放报文段,并停止再发送数据,主动关闭TCP连接。A把连接释放报文段首部的终止控制位FIN置为1,其序号为seq=uu等于前面已发送过的数据最后一个字节序号加1。A进入FIN-WAIT-1(终止等待1)状态,等待B的确认。TCP规定,FIN报文段即使不带数据,也要消耗一个序号。
  2. B收到连接释放报文段后即发出确认,确认号是ack=u+1,而这个报文号自己的序号是seq=vv等于B已传送过的数据的最后一个字节的序号加1。B进入CLSOE-WAIT(关闭等待)状态。TCP服务器进程这时通知上层应用。因而A到B这个方向的连接就释放了,这时TCP处于半关闭(half-close)状态,即A已经没有数据要发送给B了,但是B如果发送数据给A,A任然要接受。因为B到A这个方向的连接并未关闭,这个状态可能会持续一段时间。A收到来自B的确认后,就进入FIN-WAIT-2(终止等待2)状态,等待B发出的连接释放报文段。
  3. 若B已经没有要向A发送的数据,其应用进程就通知TCP释放连接。这时B发出的连接释放报文段首部必须使FIN=1。现假设B的序号为w(在半关闭状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认号ack=u+1。这时B就进入LAST-ACK(最后确认)状态,等待A的确认。
  4. A在收到B的连接释放报文段后,必须对此发出确认。在确认报文段中把ACK置为1,确认号ack=w+1,而自己的序号是seq=u+1(前面发送过的FIN报文要消耗一个序号)。然后进入到TIME-WAIT(时间等待)状态。此时TCP连接还没有释放。必须经过时间等待计时器(TIME-WAIT timer)设置的时间2MSL后,A才进入CLOSED状态。MSL叫做最长报文段寿命(Maximum Segment Lifetime),RFC 793建议设置为2分钟(TCP允许不同的实现更改MSL值),即默认TIME_WAIT状态持续4分钟后,A进入CLOSED状态,才能开始建立下一个新的连接,当A撤销相应的传输控制块TCB后,就结束了TCP连接。

以上就是TCP四次挥手的全过程。

为什么A在TIME-WAIT状态必须等待2MSL的时间?

  • 为了保证A发送的最后一个ACK报文段能够到达B。这个ACK报文段可能丢失,因而使处在LAST-ACK状态的B收不到对已发送FIN+ACK报文段的确认。B会超时重传这个FIN+ACK报文段,而A就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着A重传一次ACK确认,重新启动2MSL计时器。最后A和B都正常进入CLOSED状态。如果A在TIME-WAIT不等待一段时间,而是发送ACK后马上进入CLOSED状态,一旦ACK丢失,B由于收不到ACK确认,所以会重传FIN+ACK报文段,但此时A已经进入CLOSED状态,自然无法再发送ACK确认。所以B也无法正常进入CLOSED状态。
  • 可以使本次连接所有报文段在网络上消失。A发送完最后一个ACK后,再等待2MSL,就可以使本连接持续的时间内所有产生的报文段都从网络上消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

除了时间等待计时器外,TCP还有一个保活计时器(keepalive timer)。当TCP连接完成后,客户端突然出现故障,无法发送报文段。保活计时器可以避免服务器白白等下去。服务器每收到一次请求,重置一下保活计时器,时间设置通常2小时。若2小时没有收到客户端请求,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若连续发送10个探测报文段仍无客户端响应,服务器就认为客户端出现故障,接着关闭这个连接。

TCP滑动窗口

TCP发送的报文段是交给IP层传送的。但是IP层只能提供最大努力的交付,也就是说TCP下面的网络提供的是不可靠传输。因此TCP必须采取适当的措施使得传输层之间的通信变得可靠。可以先看看最直接的方式:
TCP三次握手、四次挥手全过程,超详细_第7张图片
每发送完一个报文段就停止发送,等待对方确认,收到确认后再发送下一个分组。这便是停止等待协议。但是在传输过程中很有可能会出现异常情况:
TCP三次握手、四次挥手全过程,超详细_第8张图片
发送方A发送的M1出现了错误,被接收方B丢弃了,所以A收不到M1的确认。如果A在规定的时间内没有收到确认,就会认为刚刚发送的报文段丢失了,因而会重传前面发送过的报文段,这就是超时重传。由于这种重传是发送方A自动进行的,而不是接收方B请求A再次重传的。所以通常称为自动重传请求ARQ(automatic repeat request)
使用上述的确认和重传机制,我们就可以在不可靠的网络上实现可靠的传输。这种方式明显可以看出效率太低,所以TCP必须要支持批量发送报文段。于是便有了TCP滑动窗口
TCP三次握手、四次挥手全过程,超详细_第9张图片
滑动窗口将所有的报文段分为四类:

  1. Sent and Acknowledged:这些数据表示已经发送成功并已经被确认的数据,比如图中的前31个byte。
  2. Send But Not Yet Acknowledged:这部分数据称为已经发送但没有被确认,数据被发送出去,没有收到接收端的ACK,认为并没有完成发送。
  3. Not Sent,Recipient Ready to Receive:这部分是准备发送但还未发送数据,这部分数据已经被加载到缓存中,也就是窗口中了,等待发送,其实这个窗口是完全由接收方告知的,接收方告知还是能够接受这些包,所以发送方需要尽快的发送这些包。
  4. Not Sent,Recipient Not Ready to Receive: 这些数据属于未发送也暂时不允许发送

其中,中间两部分(Category#2和Category#3)就是TCP的滑动窗口
如上图所示,窗口边界为[32, 51],也就是说收到了31号的确认,如果接着收到了32、33、34、35号的确认,窗口就会向前滑动(序号递增的方向为前)
TCP三次握手、四次挥手全过程,超详细_第10张图片
此图表示窗口的滑动过程。收到了36号确认,便会向前移动一格(逻辑图上的一格,实际上是一个字节byte),同时,56号数据也能发送出去了。收到确认号就向前移动,值得注意的是此时如果收到后面的确认,如40号,窗口并不会移动到40号,因为前面37-39还没收到确认。
对于接收方来说,滑动窗口如下:
TCP三次握手、四次挥手全过程,超详细_第11张图片
滑动窗口把报文段分成三类:

  • Received and Acknowledged已接收并且已经回复确认,表示接收方收到了这些数据,并且回复了发送方
  • Not Yet Received, Transmitter Permitted To Send未接收但是可以接收,表示接收方尚未收到数据,但是此时若有数据传输过来,则可以接收。
  • Not Yet Received, Transmitter May Not Send未接收也不能接收

由于接收方从接收到回复几乎没有时间间隔,所以不存在已接收但未回复的状态。同样,中间部分(Category#3)就是TCP接收端的滑动窗口。接收端的滑动窗口的滑动过程和发送端的一致。
TCP的可靠性建立在确认重传机制上,TCP滑动窗口的可靠性也是基于确认重传机制的。

参考

  • 《计算机网络》

你可能感兴趣的:(计算机网络,计算机网络,TCP,UDP,三次握手,滑动窗口)