剑指Offer(网络)——TCP协议的三次握手原理详解

首先我们先来简单介绍一下传输控制协议TCP

  1. TCP协议是面向连接的、可靠的、基于字节流的传输层通信协议。

  2. 当数据传输的时候,应用层向TCP发送数据流,然后TCP会将应用层的数据流分割成报文段并发送给目标节点的TCP层。

  3. 而TCP为了保证不丢包,就给每一个包一个序号(Sequence Number),同时序号也保证了,对方接受数据的时候顺序是一定的。

  4. 然后当对方收到数据的时候,就会回复一个ACK去确认,但如果在合理的时延之内没有收到数据,就会认为已丢失,也就会将其重传。

  5. TCP所使用的是奇偶校验核函数检验数据在传输的过程中是否有错误,在发送和接收的时候,都要计算校验和。

然后再来介绍5个TCP报文传输时候的几个常见的Flag:

  1. URG:紧急指针标志(1表示紧急指针有效,0表示忽略紧急指针)
  2. ACK:确认序号标志(1表示确认号有效,0表示不需要确认)
  3. PSH:push标志(1标记的数据代表提示对方应该快速将信息发给应用程序,0相反)
  4. RST:重置连接标志(拒绝连接请求,出意外了就用)
  5. SYN:同步序号,用于建立连接过程(在连接请求中,SYN=1,ACK=0没有使用捎带的确认域,而SYN=1,ACK=1代表连接应答捎带一个确认域)
  6. FIN:finish标志,代表释放连接(为1是代表发送方已经没有数据要发送了)

当一个应用程序渴望通过TCP连接另一个应用程序的时候,它会发送一个通信请求,这个请求必须被送到一个确切的

地址,在双方握手之后,TCP将在两个应用程序之间,建立一个全双工的通信,将占用两个计算机的通信线路,直到

断开连接。“握手”是为了建立连接,TCP的三次握手的流程如下:

在这里插入图片描述

扫描二维码关注公众号,回复: 9189352 查看本文章

接下来就来讲一下各个过程

  1. 最开始的时候,我们假设,A和B处于Close的状态,假设主动打开的是客户端,被动打开连接的是服务端。

  2. 刚开始的时候,TCP服务器进程,先创建传输控制块PCB,时刻准备接受其他客户进程发送过来的连接请求,然后就进入了LISTEN的状态。

  3. 此时,我们的TCP Client也是先创建一个传输控制块PCB,然后向服务器发送请求连接的报文,并且携带的初始序号sequence=x,SYN=1,这时候,TCP Client进入了一个SYN-SENT的状态,也就是同步已发送,此时发送过去的数据包,被称为SYN报文段,是不可以发送数据的,但是要消耗掉一个序号,这就是第一次握手了。

  4. 当我们的服务器接收到请求报文之后,如果同意连接,就发送确认报文,确认报文中包含SYN=1,ACK=1,序列号sequence=y,返回号ack由于上面发送过来了一个sequence=x作为回应,应该回应一个和x相关的信息,而且上面难点报文消耗掉了一个序号,所以ack=x+1 ,此时服务器进入SYN-RCVD,同步收到的状态,这个报文也是不能携带数据的,并且同样需要消耗掉一个序号,这就是第二次握手。

  5. 那么,当TCP Client收到了确认报文之后,还要向服务器给出一个确认,确认的报文携带的flag是ACK=1。sequence=x+1,ack=y+1,这里的ack=y+1是因为,之前发送过来的sequence是y,所以作为回应,就必须和y相关,又不能和y重复,就是y+1了,而且之前我们发送过去的seq是x,服务器返回过来的时候是x+1,那么再去确认的时候,就也得加一了,所以sequence=x+1,并且,这个报文段是可以携带数据的,前两个都是不可以携带数据的,当然,它也可以不携带数据,如果不携带数据,就不会消耗序号,这就是第三次握手。

  6. 当服务器收到客户端的确认之后,也会进入到ESTABLISH的状态,此后,双方就可以开始通信了。

那么为什么我们需要三次握手才能将连接建立起来呢?

主要是为了初始化Sequence Number的初始值,通信的双方要通知对方自己初始化的Sequence Number,这个序号

要作为以后数据通信的序号,让应用层接收到数据的时候,不会因为网络上的传输而导致顺序错乱,也就是说,tcp

利用Sequence Number来拼接数据,所以这就是我们发送第三次握手的原因,让服务端知道客户端已经收到了服务

端的Sequence Number。

此外,首次握手有一个隐患——SYN超时,问题起因如下:

如果Server端收到了Client端的SYN,然后回复SYN-ACK的时候未收到ACK确认,此时Client还下线了,那么连接就

会处于一个中间状态,也就是失败,于是Server端那边会不断重试直到超时,Linux默认等待63秒后才会断开连接。

那么,为什么是63秒呢,其实,说是63秒,不如说是5次,实际上是在 1 2 4 8 16 32秒的时候,都会进行重传,第一

秒的时候是第一次发送,所以不算数,也就是说,当这五次重传,还是没有接收到回应,就算是断开连接了。

那么,这样的后果是什么呢?

将会遭到SYN Flood,于是我们再来解释一下针对SYN FLOOD的防护措施

这个事情的原理是这样的,在重试的那63秒内,恶意的程序将SYN对应连接队列耗尽,使之不能处理正常的握手请求。

在linux下,是有一定解决措施的,当SYN队列满了之后,通过tcp_syncookies参数将会回发SYN Cookie,如果要是

正常的连接,那么Client就会回发一个SYN Cookie,直接建立连接。

如果一段时间之后,Client出现了故障怎么办?

TCP默认使用保活机制,在规定的时间内,向对方发送保活探测报文,如果没有收到响应,就会继续发送,直到尝试

的次数达到保活探测数仍未收到响应,就中断连接了。

这里是四次挥手的笔记:https://blog.csdn.net/qq_41936805/article/details/103443031

发布了296 篇原创文章 · 获赞 53 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_41936805/article/details/103441134