计算机网络之-------TCP 三次握手和四次挥手

1.TCP的概念

       TCP(Transmission Control Protocol) 传输控制协议,是一种面向连接的、可靠的、基于字节流的传输控制协议。TCP就是一个双向通信的规范标准。

2 TCP头部报文

   

   1)source port   和destination port

         source port 就是源端口号,具体指本地端口号,destination port 就是远程端口号。

       一个数据包被解封装成数据段后就会涉及到连接上层协议的端口号问题。简单的说我们本地发送方有多种端口,接收方(远程)也会有多种端口, source port和destination port就分别代表从哪个规定的串口发送到对方接受的窗口。两者之间一一对应。不同的应用程序有不同的端口。比如发送方的微信端口8080对应着接受方的微信端口8080。

     说明:应用程序的端口号和应用程序所在主机的IP地址统称为套接字(socket)。IP:端口号,在互联网上socket唯一标识每一个应用程序,源端口+源IP+目的IP称为“套接字对”,一个套接字就是一个连接,一个客服端与服务器之间的连接。

  2)Sequence Number 

       初始序列号,用于TCP通信过程中某一传输方向上字节流的每个字节编号,为了确保数据通信的有序性,避免网络中乱序的问题。接收端根据这个编号进行确认,保证分割数据段在原始数据包的位置。每个字段在传送中用序列号来标记自己的位置,而这个字段就是用来完成双方传输中确保字段原始位置是按照传输顺序的。

     说明:初始的序列号是自己定的,而后续的序列号由对端的ACK确定。SN_x=ACK_y(x的序列号等于y发送给x的ACK)。

3)Acknowledgement Number

     ack确认序列号,接收确认端所期望收到的下一个序列号确认序列号应当是上次已经成功收到的数据字节序号加1,只有当标志位的ACK标志为1时,该确认序列号才有效,主要用来解决不丢包的问题。

   如果确认序列号=N,那么就表示序号N-1为止的所有数据都能已经正确收到。

   数据传输是一段一段的,都是有序列号进行标识的,因此,接收端每接收一段,之后想要的下一段的序列号称为确认序列号。

4)TCP Flag

     TCP 首部有6个标志比特,他们中多个可同时被设置为1。主要用来操控TCP的状态机,依次为URG,ACK,PSH,RST,SYN,FIN。

    ACK

        ACK指发送端发送数据到接收端,发送的时候ACK为0,表示接收端还没应答,一旦被接收端接收数据之后,就将ACK置为1,发送端接收之后,就知道接收端已经接收了数据。

      ACK标志表示应答域有效,就是说TCP应答号将会包含在TCP数据包中:取值为0和1,1代表应答域有效,否则为0,

 SYN

    同步序列号,是TCP握手发送的第一个数据包。SYN用来建立TCP的连接,SYN标识位和ACK标识位搭配使用,当连接请求时,SYN为1,ACK为0,在连接被响应之后,SYN为1,ACK为1;这个标识的数据包经常被用来进行端口的扫描,扫描者发送一个只有SYN的数据包,如果对方相应了一个数据包回来,就表示这个主机存在这个端口。

      过程为:发送端 SYN=1,ACK=0,发送端向接收端发送请求消息,接收端收到SYN=1,ACK=0的数据包,就知道发送端想给他发送数据,这时接收端将SYN=1,ACK=1,将其回应给发送端,告诉发送端,我已经准备好了,以开始发送消息吧。

  FIN

    FIN表示发送端已经发送到数据末尾,就是说双方的数据已经传输完成,没有数据可以传送了。发送FIN标识位的TCP数据包后,连接就会被断开,这个标识的数据包也经常用于端口扫描。

   当发送端只剩一个数据时,需要告诉接收端我这里没有数据了,数据发送完了,就用FIN=1来标识一下,接收端收到FIN=1的标识之后,就知道这是最后的数据,接收这个数据之后,就将连接断开。

5)Window size

   滑动窗口大小,用来进行流量控制。

TCP滑动窗口:

  RTT:发送一个数据包到收到对方回应的ACK,所花费的时间。

 RTO:重传时间间隔,TCP在发送一个数据包之后,会启动一个重传定时器,RTO就是定时器的重传时间。如果收到了对方的ACK,那么RTO就失效,如果没有收到,RTO重传定时器的时间到了之后,就需要重传数据包。RTO通过RTT计算得出。

 TCP使用滑动窗口做流量控制与乱序重排:

    1.保证了TCP的可靠性。

   2.保证TCP的流控特性。

    流量控制:Window size 用于接收方通知发送方,告诉发送发自己还有多少缓冲区可以接收数据,发送方就会根据接收方的处理能力来接收数据,不会导致接收方处理不过来数据,这就是流量控制。

 

       LastByteAcked: 连续被接收端接收并已经返回的确认序列号的最大值。

      LastByteSend:已经发送的最后一个字节的位置(未收到ACK确认)

     LastByteWritten:上层应用已经写完的的最后一个字节的位置。

     LastByteRead:上层应用已经读完的最后一个字节的位置。

     NextByteExpected:接收到发送端的连续序列号的最大值的位置,接收到没有反馈确认ACK

   LastByteRcved:已经收到的最后一个字节的位置。

    AdvertisedWindow:接收端还能接收的窗口大小。

   EffectiveWindow:发送端还需要发送的窗口大小。

  

 

     TCP会话的发送方分为四个区域,发送已经接收到ACK的数据段、发送没有接收到ACK的数据段、没有发送准备发送的数据段、没有发送不能发送的数据段。

     其中发送没有接收到ACK的数据段、没有发送准备发送的数据段的长度和,称为滑动窗口,假设滑动窗口的长度为序列号32-51之间的数据段。其中32-40为发送没有接收到ACK的数据段,41-51位没有发送准备发送的数据段。这时当发送方收到接收方发来的ACK=36时(ACK只能是32-40之间的数据),滑动窗口就会移动到36-55的区域。这时52-55原来属于没有发送不能发送的数据段,在滑动窗口移动之后,52-55数据段就变成了没有发送准备发送的数据段。

  

 

3 TCP的三次握手

  

     初始状态:客户端处于close(关闭)状态。服务器处于listen(监听)状态。

  1)第一次握手:建立连接时,客服端发动SYN包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认。

           客户端发送请求报文将同步序列号SYN=1,初始化序列号seq=x,发送给服务器,在发送完成之后,客户端就进入SYN_send状态(发送等待转态)。

   2)第二次握手:服务器收到SYN包,必须确认客户端的SYN(ack=x+1),同时自己也要发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECEVICE状态。

        服务器收到客服端发送的SYN请求报文之后,如果服务器同意连接,会将自己的同步序列号SYN(服务器端)=1、初始化序列号seq=y、确定序列号(期望下次从客户端收到的数据包)ack=x+1、确认号ACK=1,作为应答报文,之后服务器处于SYN_Receive状态(确认接收状态)。

     3)第三次握手:客服端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1).此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

           客户端接收到服务器端的SYN和ACK之后,知道可以下次发送下一序列的数据包了,然后发动确定序列号ack=y+1和数据包的序列号seq=x+1、确认号ACK=1,作为应该报文。之后客服端进入established(确认连接状态)。

4 为什么要三次握手

    防止服务器端的一直等待而浪费资源。

   为 了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。如果此时客户端发送的延迟的握手信息服务器收到,然后服务器进行响应,认为客户端要和它建立连接,此时客户端并没有这个意思,但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。

  为什么需要三次握手才能建立连接?

      为了初始化Sequence Number 的初始值。

建立连接后,client出现故障怎么办?

   保活机制:

         (1)向对方发送保活探测报文,如果没有收到响应就继续发送。

        (2) 尝试次数达到保活探测数仍然没有收到响应就会断开连接

  

 

5 TCP的四次挥手

     初始化状态:客户端和服务器都处于连接阶段。下面进行四次挥手端来连接。

 1)第一次挥手:client发送一个FIN,用来关闭client到sever的数据传送,Client进入FIN_WAIT_1状态。

         第一次挥手客户端和服务器都可以发起,因为TCP是双全工的。

         假设客户端发送的数据已经发送完毕,发送FIN=1,告诉服务器,客户端所有的数据都已近发送完毕了,服务器可以关闭接收了。但是这时如果服务器还有数据要发送给客户端,客户端还可以继续接收数据,此时的客户端处于FIN=1等待服务器确认释放连接状态(FIN_Wait)。

  2)第二次挥手:Sever收到FIN后,发送一个ACK给Client,确认序列号为收到序列号+1(与SYN相同,一个FIN占用一个序号),Sever进入CLOSE_WAIT状态。

       服务器接收到客户端的释放连接请求后,知道客户端没有数据要发送给自己了,之后,服务器就会发送一个ACK=1,来告诉客户端已经接收到给我发送的消息了。此时的服务器处于CLOSE_WAIT等待关闭状态。

3)第三次挥手:Sever发送一个FIN,用来关闭Server到Client的数据传送,Sever进入LAST_WAIT转态。

      此时的服务器已经把所有的数据发送完了,然后向客服端发送一个FIN=1,用来告诉客户端,服务器的数据已经全部发送完毕,客户端你也可以关闭接收数据连接了。此时的服务器处于确定关闭状态(LAST_ACK),来等待客户端确定是否收到了自己的请求。

 4)第四次挥手:Client收到FIN之后,Client进入TIME_WAIT状态,接着发送一个ACK给Serve,确认序号为收到序号+1,Sever进入CLOSED状态,完成四次挥手

    此时如果客户端收到了服务器发送的消息之后,就发送一个ACK=1,告诉服务器,客户端已经收到了你的消息。这里会有一个2MSl的延迟等待。

   对应这样一种情况,最后客户端发送的ACK = 1给服务端的过程中丢失了,服务端没收到,服务端怎么认为的?我已经发送完数据了,怎么客户端没回应我?是不是中途丢失了?然后服务端再次发起断开连接的请求,一个来回就是2MSL,这里的两个来回由那一个来回组成的?

   客户端给服务端发送的ACK = 1丢失,服务端等待 1MSL没收到,然后重新发送消息需要1MSL。如果再次接收到服务端的消息,则重启2MSL计时器,发送确认请求。客户端只需等待2MSL,如果没有再次收到服务端的消息,就说明服务端已经接收到自己确认消息;此时双方都关闭的连接,TCP 四次分手完毕。

为什么会用TIME_WAIT状态?

   1.确保有足够的时间让对方收到ACK包

   2、避免新旧连接混淆

为什么需要四次挥手才能断开连接?

  因为TCP是全双工的,发送方和接收方都需要FIN报文和ACK报文。