【Linux】三次握手和四次挥手详解

本文详细解析了TCP协议的工作原理,包括三次握手建立连接、四次挥手断开连接的过程,并介绍了TCP如何确保数据传输的安全可靠。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三次握手和四次挥手

​ TCP 协议提供的是:面向连接、可靠的、字节流服务。使用 TCP 协议通信的双发必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。 TCP 连接是全双工的,双方的数据可以通过一个连接进行读写。完成数据交换之后,通信双方都必须断开连接以释放系统资源。

TCP流式服务的特点:发送和接收的次数不对应,会出现沾包问题

TCP协议报头
在这里插入图片描述

6位标志位包含如下几项

(1)URG标志,表示紧急指针(urgent pointer)是否有效

(2)ACK标志(Acknowledge Character),表示确认号是否有效,我们称携带ACK标志的TCP报文段为确认报文段,是在数据通信传说中,接收站发给发送站的一种传输控制字符,表示确认发来的数据已经接受无误。ACL确认序号的值是对方发送的序号值+数据长度

(3)PSH标志,提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间(如果应用程序不将接收到的数据读走,它们就会一直停留在TCP 接收缓冲区中)

(4)RST标志,表示要求对方重新建立连接,我们称携带RST标志的TCP报文段为复位报文段

(5)SYN 标志(Synchronize),表示请求建立一个连接,我们称携带SYN 标志的TCP报文段为同步报文段,是客户端第一次发出的连接信号,之后会收到服务器的ACK信号;

(6)FIN标志(Finish),表示通知对方本端要关闭连接了,我们称携带FIN标志的TCP报文段为结束报文段

窗口大小: 指的是缓冲区大小

TCP状态转换图

状态转换图

为什么说TCP是安全可靠的协议?

​ TCP是面向连接的安全的数据传输, 在客户端与服务端建立建立的时候要经过三次握手的过程, 在客户端与服务端断开连接的时候要经历四次挥手的过程, 下图是客户端与服务端三次握手建立连接, 数据传输和断开连接四次挥手的全过程。

TCP时序:

在这里插入图片描述

建立连接(three-way hand shake)

TCP三次握手发生在内核执行connect()函数的时候

·主动打开(passive open):服务器必须准备好接受外来的连接,通常通过socket、bind和listen完成。

·被动打开(active open):客户端通过connect发起主动打开。

TCP建立连接的三次握手图
在这里插入图片描述

客户端与服务器三次握手过程介绍

  1. 服务器准备好接受外来连接,通常通过socket、bind和listen完成。(服务器:CLOSED->LISTEN)
  2. 客户端通过connect连接服务器,客户端TCP将发送一个SYN包,告诉服务器客户端将在待建立连接发送数据的初始序列号。(客户端:CLOSED->SYN_SENT)
  3. 服务器端必须ACK客户端SYN,同时发送一个SYN,告诉客户端,服务器将在待建立连接发送数据的初始序列号。(服务器:SYN_RCVD)
  4. 客户端必须ACK服务器SYN。(客户端:SYN_SENT->ESTABLISHED)
  5. 服务器接收到客户端ACK。(服务器:SYN_RECV->ESTABLISHED)

对应的状态转移图

状态转移图

建立连接同时打开(simultaneous open)

这种情况发生在两端几乎同时发送SYN并且这两个SYN在网络中交错的情形。这种情况可能发生,但是非常罕见。

例如,主机A的应用程序使用本地端口7777,并与主机B的端口8888执行主动打开。主机B的应用程序使用本地端口8888,并与主机A的端口7777执行主动打开。

下图给出同时打开过程:

同时打开过程

下图给出同时打开的状态转移图:

状态转换图

说明:从目前个人经验来看,这种场景没有遇到过,但这是完整理解TCP状态转移必须的一部分。

tcpdump抓包观察TCP的链接的建立和关闭;

建立连接失败

考虑场景1:
当客户端尚未接收到服务器ACK+SYN,异常退出(崩溃退出)。这时,当客户端接收到服务器的ACK+SYN时,客户端回复RST(reset)。此时服务器处于SYN_RCVD状态,当接收到客户端RST时,则从SYN_RCVD转移到LISTEN状态。

具体过程:

  1. 服务器准备好接受外来连接,通常通过socket、bind和listen完成。(服务器:CLOSED->LISTEN)
  2. 客户端通过connect连接服务器,客户端TCP将发送一个SYN包,告诉服务器,客户端将在待建立连接发送数据的初始序列号。然后客户端异常退出。(客户端:CLOSED->SYN_SENT,然后突然crash,则退出SYN_SENT)
  3. 服务器端ACK客户端SYN,同时发送一个SYN,告诉客户端,服务器将在待建立连接发送数据的初始序列号。(服务器:SYN_RCVD)
  4. 客户端找不到服务器ACK+SYN对应的SYN_SENT状态的socket,则响应RST。(服务器:SYN_RCVD->LISTEN)

下图给出建立连接失败的状态转移图:

状态转换图

考虑场景2:
服务器的进程异常退出,客户端不知道。那么客户端发送SYN后,服务器端响应RST,则客户端建立连接失败。

考虑场景2:服务器机器关闭,导致服务器IP不可达。那么客户端发送SYN后,超时重发,超过重试次数,最终TIMEOUT,则客户端建立连接失败。

具体过程:

  1. 假设服务器进程退出。(服务器:LISTEN->CLOSED)
  2. 客户端通过connect连接服务器,客户端TCP将发送一个SYN包,告诉服务器,客户将在待建立连接发送数据的初始序列号。(客户端:CLOSED->SYN_SENT)
  3. 服务器端收到客户端SYN,响应RST(服务器:CLOSED)
  4. 客户收到RST。(客户端:SYN_SENT->CLOSED)

建立连接失败的状态转移图

状态转换图

数据传输阶段

在这里插入图片描述

四次挥手阶段

服务器或者客户端执行close()函数的时候执行四次挥手

·主动关闭(active close):某个应用程序首先调用close,发送一个FIN包。

·被动关闭(passive close):接收到FIN的对端执行被动关闭。

TCP连接断开的四次挥手过程图
在这里插入图片描述

客户端与服务器的四次挥手过程:

  1. 某个应用程序首先调用close,该端发送一个FIN包,表示数据发送完毕,该应用程序再无更多数据发送给对端。(例如HTTP服务器发送Reponse数据给client后,再无多余数据发送,则Server可以执行主动关闭)(主动端:ESTABLISHED->FIN_WAIT_1)
  2. 接收到FIN的对端执行被动关闭。首先ACK这个收到的FIN包。该FIN包的接收也作为一个文件结束符(EOF)传递给应用程序(放在已排队等候该应用进程接收的任何其他数据之后),因为FIN包意味着接收端应用进程在相应的连接上再无额外数据可接收。(被动端:ESTABLISHED->CLOSE_WAIT,主动端:FIN_WAIT_1->FIN_WAIT_2)
  3. 一段时间后,接收到这个EOF的应用进程将调用close关闭socket。这导致它的TCP也发送一个FIN包。(被动端:CLOSE_WAIT->LAST_WAIT)
  4. 接收这个最终FIN的执行主动关闭的那一端ACK这个FIN。(被动端:LAST_WAIT->CLOSED,主动端:FIN_WAIT_2->TIME_WAIT(2MSL之后,TIME_WAIT->CLOSED))

四次挥手的状态转移图

状态转换图

完整TCP时序

理解数据之间变换的关系
在这里插入图片描述

断开连接(同时关闭simultaneous close)

​ 一方(通常但不总是客户方)发送第一个FIN执行主动关闭。双方都执行主动关闭也是可能的,TCP协议也允许这样的同时关闭(simultaneous close)。

同时关闭过程图:

同时打开过程

同时关闭的状态转移图

状态转换图

断开连接(在FIN_WAIT_1状态中,接收FIN+ACK)

考虑场景:被动关闭端收到FIN包后,直接发送FIN+ACK,则主动关闭方则从FIN_WAIT_1跳过FIN_WAIT_2,直接进入TIME_WAIT。

具体流程如下:

  1. 某个应用程序首先调用close,该端发送一个FIN包,表示数据发送完毕,该应用程序再无更多数据发送给对端。(例如HTTP服务器发送Reponse数据给client后,再无多余数据发送,则Server可以执行主动关闭)(主动端:ESTABLISHED->FIN_WAIT_1)
  2. 接受到FIN的对端执行被动关闭。收到FIN包之后,被动端调用close关闭socket,则FIN+ACK同时发给主动端。(被动端:ESTABLISHED->CLOSE_WAIT->LAST_ACK,主动端:FIN_WAIT_1->TIME_WAIT)
  3. 接收这个最终FIN的执行主动关闭的那一端ACK这个FIN。(被动端:LAST_WAIT->CLOSED,主动端:FIN_WAIT_1->TIME_WAIT(2MSL之后,TIME_WAIT->CLOSED))

同时关闭的状态转移图

状态转换图

TCP连接的可靠性保证

1.应答确认

2.超时重传机制

无差错数据的交互流程:
在这里插入图片描述

出现差错数据的交互流程:
在这里插入图片描述

3.乱序重排以及对数据的去重操作

以上三点保证了TCP连接的可靠性

滑动窗口

​ TCP 协议是利用滑动窗口实现流量控制的。一般来说,我们总是希望数据传输得更快一些,不会一次只发一个字节。但是如果发送方把数据发得过快,接受方就可能来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要快,要让接收方来的及接收。

​ 在 TCP 的报头中有一个字段叫做接收通告窗口,这个字段由接收端填充,是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。所以发送端就会有一个发送窗口,这个发送窗口的大小是由接收端填充的接收通告窗口的大小决定的,并且窗口的位置会随着发送端数据的发送和接收到接收端对数据的确认而不断的向右滑动,将之称为滑动窗口。
在这里插入图片描述

(可参考《计算机网络》204页“滑动窗口”的内容)

MTU和mss

​ MTU:通信术语最大传输单元(Maximum Transmission Unit,MTU),是指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为 单位)。最大传输单元这个参数通常与通信接口有关(网络接口卡、串 口等), 这个值如果设置为太大会导致丢包重传的时候重传的数据量较大, 图中的最大值是1500, 其实是一个经验值。

在这里插入图片描述

​ mss(Maximum Segment size): 最大报文长度, 只是在建立连接的时候, 告诉对方我最大能够接收多少数据, 在数据通信的过程中就没有mss了。

<think>好的,我现在需要回答用户关于Linux环境中TCP三次握手四次挥手的详细过程。首先,我得回忆一下TCP协议的基本概念,确保自己理解正确。用户已经提供了三个引用,我需要结合这些内容来构建答案,同时注意正确使用LaTeX格式,并且生成相关问题。 首先,三次握手。根据引用[1]引用[2],三次握手是为了建立连接,确认双方的收发能力,并且是全双工通信的最小成本确认方式。引用中还提到三次握手实际上是四次,但中间两次被合并了。我需要详细描述每一步:客户端发送SYN,服务端回应SYN-ACK,客户端再发送ACK。同时,需要说明每个步骤中的标志位(SYN,ACK)序列号的变化。可能还需要提到状态变化,比如LISTEN、SYN-SENT、SYN-RECEIVED、ESTABLISHED等,但引用中提到了TCP连接的11种状态,这里需要确认是否需要详细展开。不过用户的问题主要是过程,所以可能简要提及状态即可。 然后是四次挥手。根据引用[1]引用[2],四次挥手用于断开连接,这里需要说明为什么需要四次而不是三次。引用[2]提到四次挥手,可能是因为双方都需要独立关闭自己的连接。步骤包括FIN、ACK、FIN、ACK。状态变化如FIN-WAIT-1、CLOSE-WAIT、LAST-ACK等,但同样是否需要详细描述状态取决于用户需求,用户的问题是关于过程,所以重点放在步骤上。 需要确保使用中文回答,结构清晰,分步骤说明。同时,按照系统级指令,行内数学表达式用$...$,但这里可能更多是协议步骤,可能不需要数学公式,但如果有涉及变量或技术术语,可能需要用LaTeX。例如,序列号可能用$x$表示,但根据示例,可能不需要特别处理,除非明确有数学表达式。 接下来,检查是否需要引用。每个引用的内容需要对应到回答中的相关部分。例如,引用[3]提到TCP的可靠性UDP的区别,可能在回答中不需要,但用户的问题是关于三次握手四次挥手,所以主要引用[1][2]。 现在组织内容: 1. 三次握手过程: - 客户端发送SYN(seq=x) - 服务端响应SYN-ACK(seq=y, ack=x+1) - 客户端发送ACK(ack=y+1) - 建立连接,状态变为ESTABLISHED 引用[1][2]说明三次握手的目的合并中间步骤。 2. 四次挥手过程: - 客户端发送FIN(seq=u) - 服务端响应ACK(ack=u+1) - 服务端发送FIN(seq=v, ack=u+1) - 客户端响应ACK(ack=v+1) - 进入TIME-WAIT状态,等待2MSL后关闭 引用[1][2]说明四次挥手的原因,如全双工关闭需要独立步骤。 注意状态转换可能需要提及,但用户的问题可能更关注过程而非状态细节。需要确认是否必要。 然后生成相关问题,如: 1. 为什么三次握手需要三次而不是两次? 2. TIME-WAIT状态的作用是什么? 3. 如果握手过程中丢包会怎样? 确保符合用户要求的格式,使用正确的引用标识,例如在解释三次握手时末尾添加[^1][^2],在四次挥手部分添加。 最后,检查LaTeX是否符合要求,例如如果有变量或公式,如序列号使用$x$,则用$...$包裹,但根据示例,可能不需要,除非明确有数学表达式。例如,在描述seq=x时,可以写成$seq = x$,但需要看是否需要。根据示例中的快速排序代码,可能用户的问题中不需要太多LaTeX,但按照系统指令,所有行内数学表达式必须使用$...$,因此像seq=x可能需要写成$seq = x$。需要检查这一点。 例如,步骤中的序列号确认号可能需要用行内公式,如客户端发送SYN,序列号为$x$,即$seq = x$,这样符合系统指令。 现在,开始撰写回答,分步骤详细说明三次握手四次挥手,确保引用正确,结构清晰,生成相关问题,并检查LaTeX格式是否正确。</think>### TCP三次握手四次挥手的过程详解Linux环境) #### 一、TCP三次握手:建立连接 TCP通过三次握手确保双方具备双向通信能力,并同步初始序列号(ISN)。 1. **第一次握手(SYN)** 客户端发送SYN报文,设置标志位$SYN=1$,并生成随机初始序列号$seq = x$。此时客户端进入$SYN\text{-}SENT$状态。 2. **第二次握手(SYN-ACK)** 服务端收到SYN后,回复SYN-ACK报文,设置$SYN=1$$ACK=1$,生成自己的序列号$seq = y$,确认号为$ack = x + 1$。服务端进入$SYN\text{-}RCVD$状态。 3. **第三次握手(ACK)** 客户端确认服务端的SYN-ACK,发送ACK报文,设置$ACK=1$,序列号$seq = x + 1$,确认号$ack = y + 1$。双方进入$ESTABLISHED$状态,连接建立完成。 > **关键点**:三次握手本质上是四次交互,但服务端将$SYN$$ACK$合并为一次发送,减少开销[^2]。 --- #### 二、TCP四次挥手:终止连接 四次挥手确保双方数据收发完全结束,并安全释放连接[^2]。 1. **第一次挥手(FIN)** 主动关闭方(如客户端)发送FIN报文,设置$FIN=1$,序列号$seq = u$,进入$FIN\text{-}WAIT\text{-}1$状态。 2. **第二次挥手(ACK)** 被动关闭方(如服务端)回复ACK报文,确认号$ack = u + 1$,进入$CLOSE\text{-}WAIT$状态。客户端收到后进入$FIN\text{-}WAIT\text{-}2$状态。 3. **第三次挥手(FIN)** 被动关闭方完成数据发送后,发送FIN报文,设置$FIN=1$,序列号$seq = v$,确认号$ack = u + 1$,进入$LAST\text{-}ACK$状态。 4. **第四次挥手(ACK)** 主动关闭方回复ACK报文,确认号$ack = v + 1$,进入$TIME\text{-}WAIT$状态,等待$2MSL$(最大报文生存时间)后关闭。服务端收到ACK后立即关闭连接。 > **关键点**:四次挥手因TCP全双工特性,需独立关闭两个方向的连接。$TIME\text{-}WAIT$状态防止旧报文干扰新连接[^3]。 --- #### 三、Linux环境中的实践 - **抓包分析**:使用`tcpdump`命令可捕获握手与挥手报文,例如: ```bash tcpdump -i eth0 'tcp port 80' -w capture.pcap ``` - **状态查看**:通过`netstat`或`ss`命令查看TCP连接状态: ```bash netstat -ant | grep ESTABLISHED ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值