⬜⬜⬜ 🐰🟧🟨🟩🟦🟪(*^▽^*)欢迎光临 🟧🟨🟩🟦🟪🐰⬜⬜⬜
✏️write in front✏️
📝个人主页:陈丹宇jmu
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
🙉联系作者🙈by QQ:813942269🐧
🌈致亲爱的读者:很高兴你能看到我的文章,希望我的文章可以帮助到你,祝万事顺意🏳️🌈
✉️少年不惧岁月长,彼方尚有荣光在 🏆
📋笔记目录
建议在文章界面右边的导航栏中选择隐藏侧边栏并显示文章目录
《TCP三次握手由入门到精通》
1.1 三次握手的基本概念
1.1.1 三次握手概念简述
三次握手是TCP/IP协议中建立可靠连接的过程,其基本原理如下:
三次握手(Three-way Handshake)是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。
进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常;并且指定自己的初始化序列号(Sequence Number)为后面的可靠性传送做准备。
三次握手实质上其实就是连接服务器指定端口(传输层),建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
1.1.2 三次握手具体过程
刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。
进行三次握手:
第一次握手:
客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN(随机生成的)。此时客户端处于 SYN_SENT 状态。
首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
第二次握手:
服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(随机生成的)。同时会把客户端的 ISN + 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_RCVD 的状态。
在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。
第三次握手:
客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。
确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
在socket编程中,客户端执行connect()时,将触发三次握手。
1.1.3 三次握手深入理解
要想能深入理解三次握手的深刻内涵,熟悉TCP头部的报文格式必不可少,只有深刻认识和了解到了TCP头部报文每一个字段的内容和含义,结合抓包分析工具,更加深刻地认识到三次握手的过程。
TCP头部报文字段是TCP协议在数据传输过程中用来控制和管理数据包的信息。以下是TCP头部报文的一些常见字段:
源端口(Source Port):16位字段,表示发送方的端口号。
目标端口(Destination Port):16位字段,表示接收方的端口号。
序列号(Sequence Number):32位字段,表示发送方发送的数据字节流的序列号。
确认号(Acknowledgment Number):32位字段,表示接收方期望接收的下一个数据字节流的序列号。
数据偏移(Data Offset):4位字段,表示TCP头部的长度,以4字节为单位。
控制位(Flags):6位字段,包括以下标志位:
- URG(Urgent):表示紧急指针字段是否有效。
- ACK(Acknowledgment):表示确认号字段是否有效。
- PSH(Push):表示接收方应该尽快将数据交给应用程序。
- RST(Reset):表示中断连接。
- SYN(Synchronize):表示发起连接请求。
- FIN(Finish):表示结束连接。
窗口大小(Window Size):16位字段,表示接收方可接收的数据量大小,用于流量控制。
校验和(Checksum):16位字段,用于检测TCP头部和数据是否有错误。
紧急指针(Urgent Pointer):16位字段,在URG标志位有效时指示紧急数据的位置。
选项(Options):可变长度的字段,用于传递一些额外的控制信息,如最大段长度、时间戳等。
这些字段共同组成了TCP头部报文,通过对这些字段的设置和解析,TCP协议能够实现可靠的数据传输和连接管理。
三次握手过程中比较需要注意的TCP头部报文字段有:
- 序列号(Sequence Number)
- 确认号(Acknowledgment Number)
- 控制位(Flags)中的ACK(Acknowledgment)标志位------表示确认号字段是否有效。
- 控制位(Flags)中的SYN(Synchronize)标志位------表示发起连接请求。
1.2 三次握手的报文解析
1.2.1 第一次握手的报文解析
💡第一次握手报文摘要Info
TCP 60 12660 → 23 [SYN] Seq=0 Win=4128 Len=0 MSS=1460
第一次握手报文解析:
- 源端口号:12660
- 目标端口号:23
- SYN标志:该数据包是建立TCP连接的第一个数据包,用于发送方发起连接请求。
- 序列号(Seq):0
- 表示这是一个新的TCP连接,初始序列号被设置为0。
- 窗口大小(Win):4128
- 表示发送方的接收窗口大小,用于告知接收方可以接收的数据量。
- 数据长度(Len):0
- 数据包中携带的数据长度为0,即没有负载数据。
- 最大段大小(MSS):1460
- 表示发送方能够接收的最大TCP段(即数据包)的大小。
💡第一次握手的完整解析
根据数据包信息,可以看出这是一个从源端口12660向目标端口23发起的TCP连接请求。发送方将序列号设置为0,表示一个新的连接。发送方希望接收方将接收窗口大小设置为4128,并且发送方自己支持的最大段大小为1460。
这个数据包中没有携带任何实际的数据负载,而是仅用于建立连接。接收方可以对该数据包进行回应,建立双向的TCP连接。
1.2.2 第二次握手的报文解析
💡第二次握手报文摘要Info
TCP 60 23 → 12660 [SYN, ACK] Seq=0 Ack=1 Win=4128 Len=0 MSS=1460
第二次握手报文解析:
- 源端口号:23
- 目标端口号:12660
- SYN, ACK标志:该数据包是接收方对连接请求的回应,表示接收方同意建立连接。
- 序列号(Seq):0
- 表示接收方建立的TCP连接的初始序列号。
- 确认号(Ack):1
- 表示接收方已经收到了发送方的序列号为0的数据包,并期望下一个数据包的序列号是1。
- 窗口大小(Win):4128
- 表示接收方的接收窗口大小,用于告知发送方可以接收的数据量。
- 数据长度(Len):0
- 数据包中携带的数据长度为0,即没有负载数据。
- 最大段大小(MSS):1460
- 表示接收方能够接收的最大TCP段(即数据包)的大小。
💡第二次握手的完整解析
根据数据包信息,可以看出这是接收方对源端口23向目标端口12660发起的TCP连接请求的回应。接收方将序列号设置为0,表示它自己建立的TCP连接的初始序列号。同时,确认号设置为1,表示接收方已经成功收到了发送方的序列号为0的数据包。接收方还告知发送方接收窗口大小为4128,可以接收的最大段大小为1460。
这个数据包中没有携带任何实际的数据负载,而是仅用于建立连接的确认。发送方可以对该数据包进行回应,以完成TCP连接的建立。
1.2.3 第三次握手的报文解析
💡第三次握手报文摘要Info
TCP 60 12660 → 23 [ACK] Seq=1 Ack=1 Win=4128 Len=0
第三次握手报文解析:
- 源端口号:12660
- 目标端口号:23
- ACK标志:该数据包是发送方对接收方建立连接回应的确认。
- 序列号(Seq):1
- 表示发送方已经收到了接收方的序列号为0的数据包,并期望下一个数据包的序列号是1。
- 确认号(Ack):1
- 表示发送方确认已经成功接收到了接收方的序列号为0的数据包。
- 窗口大小(Win):4128
- 表示发送方的接收窗口大小,用于告知接收方可以发送的数据量。
- 数据长度(Len):0
- 数据包中携带的数据长度为0,即没有负载数据。
💡第三次握手的完整解析
根据数据包信息,可以看出这是发送方对接收方建立连接回应的确认数据包。发送方将序列号设置为1,表示它自己期望接收方下一个数据包的序列号是1。同时,确认号设置为1,表示发送方确认已经成功接收到了接收方的序列号为0的数据包。发送方还告知接收方接收窗口大小为4128,即发送方可以继续发送的数据量。
这个数据包中没有携带任何实际的数据负载,而是仅用于确认建立连接。接收方可以根据该确认进行进一步的数据传输。
1.3 TCP三次握手常考面试题及存在的误区
(1)为什么需要三次握手,两次不行吗?
需要三次握手确保TCP的可靠链接在于考虑到了:验证双方的通信能力,误当成有效的连接,网络延迟三个方面的问题。
确保双方的通信能力:
通过三次握手,客户端和服务器可以相互验证对方的地址是否可达,以及确保双方具备正常的通信能力。在第一次握手中,客户端发送SYN报文请求连接;在第二次握手中,服务器回应ACK确认,并发送自己的SYN请求连接;在第三次握手中,客户端再次回应ACK确认。通过这样的交互过程,双方可以确保彼此的网络连接正常运作。
防止已失效的连接请求被误认为有效的连接:
如果采用两次握手,那么只有一次请求和确认,缺少了第三次确认的过程。这种情况下,如果客户端发出连接请求后,在网络中滞留的这个请求被延迟到服务端很晚才到达,导致服务端在超时时间内未收到请求,会认为客户端并未真正想建立连接。然而,客户端可能只是因为网络延迟等原因,所以在超时后重新发送连接请求。如果只有两次握手,服务端会认为之前的连接请求是有效的,这样就可能与客户端之前的连接请求发生冲突。
防止网络延迟产生的问题:
TCP是一种面向连接的可靠协议,能够保证数据传输的可靠性。通过三次握手,可以验证双方的收发能力,并建立起一条完整的连接。如果只有两次握手,由于没有第三次握手的确认,就无法准确判断网络延迟带来的问题。例如,如果第二次握手的确认包因为网络延迟而丢失,那么服务端就无法确认客户端的请求,也无法建立可靠的连接。
(2)ISN(Initial Sequence Number)是固定的吗?
ISN(Initial Sequence Number)并不是固定的。ISN是TCP连接建立过程中的一个起始序列号,用于标识发送方传输的数据段。每个TCP连接都会使用不同的ISN。
ISN的选择原则是确保在一段时间内唯一且随机。
这样可以增加TCP连接的安全性,防止攻击者通过猜测或预测ISN来进行网络攻击,例如连接劫持、数据包重放等。
ISN的生成算法通常基于以下几个因素:
- 以时间为基础:常见的实现方式是使用当前的系统时间作为ISN的一部分。由于时间是不断变化的,这样可以保证在一定时间内生成的ISN是唯一的。
- 随机性:为了进一步增加ISN的安全性,通常会将一些随机数或随机算法引入ISN的生成过程。这样可以使ISN更难被猜测或预测。
- 混合其他因素:根据具体实现,ISN的生成可能还会考虑其他因素,如IP地址、端口号等。这样可以确保不同主机之间的ISN不会发生冲突。
需要注意的是,ISN不是永久性的,它只在建立连接时使用,并在连接建立后逐渐增加。每个数据段的序列号都以ISN为基准进行增量偏移。
总而言之,ISN是动态生成并具有一定随机性的,它在TCP连接建立过程中起到重要的作用,并且为连接提供一定的安全性。
(3)三次握手过程中可以携带数据吗?
在TCP的三次握手过程中,实际上并没有定义用于携带数据的字段或报文。三次握手的目的是确保客户端和服务器之间建立一个可靠的连接,以便后续的数据传输。
但是,这也并不意味着三次握手的过程中不能在相关字段中嵌入数据信息,当然这属于非正常报文。其实第三次握手的时候存在携带数据的可能。但是,第一次、第二次握手是一定不可以携带数据的。
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
(4)SYN攻击是什么?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向服务器端不断地发送SYN包,服务器端则回复确认包,并等待客户端确认,由于源地址不存在,因此服务器端需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。
netstat -n -p TCP | grep SYN_RECV
常见的防御 SYN 攻击的方法有如下几种:
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
(5)什么是半连接队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
这里在补充一点关于SYN-ACK 重传次数的问题: 服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。 注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s......
🚩结尾
考虑到阅读篇幅,更多知识内容参考本专栏中的其他文章
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
🌈写给读者:很高兴你能看到我的文章,希望我的文章可以帮助到你,祝万事顺意🏳️🌈