【Linux】TCP三次握手,四次挥手原理

news2024/11/15 14:04:40

今天在书中找到了比较详细的解释,记录一下

三次握手

在可以使用TCP链路之前,必须在客户端和主机之间显式建立连接。如上所述,在主动(active)和被动(passive)连接的建立方式是有区别的。

内核(即连接所涉及的两台机器的内核)在连接建立之前,会看到下述情形:客户端进程的套接字状态为CLOSED,而服务器套接字的状态是LISTEN。

建立TCP连接的过程需要交换3个TCP分组,因而称为三次握手(three-way handshake),会发生下列操作。

 客户端通过向服务器发送SYN来发出连接请求。客户端的套接字状态由CLOSED变为SYN_SENT。

 服务器在一个监听套接字上接收到连接请求,并返回SYN和ACK。服务器套接字的状态由LISTEN变为SYN_RECV。

 客户端套接字接收到SYN/ACK分组后,切换到ESTABLISHED状态,表明连接已经建立。一个ACK分组被发送到服务器。

 服务器接收到ACK分组,也切换到ESTABLISHED状态。这就完成了两端的连接建立工作,可以开始数据交换。

原则上,可以仅使用一个或两个分组建立连接。但这可能带来一种风险,由于与同一地址(IP地址和端口号)之间的旧连接的延期分组的存在,可能导致建立有缺陷的连接。三次握手的目的就是要防止这种情况。

在连接建立后,TCP链路的特点就很清楚了。每个分组发送时都指定一个序列号,而接收方的TCP协议实例在接收到每个分组之后,都必须确认。我们考察一下向Web服务器发出的连接请求的记录:

1 192.168.0.143 192.168.1.10 TCP 1025 > http [SYN] Seq=2895263889 Ack=0

2 192.168.1.10 192.168.0.143 TCP http > 1025 [SYN, ACK] Seq=2882478813 Ack=2895263890

3 192.168.0.143 192.168.1.10 TCP 1025 > http [ACK] Seq=2895263890 Ack=2882478814

客户端对第一个分组生成随机的序列号2895263889,保存在在TCP首部的SEQ字段。服务器对该分组的到达,响应一个组合的SYN/ACK分组,序列号是新的(在本例中是2882478813)。

我们在这里感兴趣的是SEQ/ACK字段的内容(数值字段,不是标志位)。服务器填充该字段时,将接收到的字节数目加1,再加到接收的序列号上(底层的原理,在下文讨论)。

分组还需要设置ACK标志,这用于向客户端表示已经接收到第一个分组。无须产生额外的分组来确认收到第一个分组。

确认可以在任何分组中给出,只要该分组设置了ACK标志并填充ack字段即可。为建立连接而发送的分组不包含数据,只有TCP首部是有意义的。首部中len字段存储的长度总是0。

这里描述的机制不是特定于Linux内核的,对所有希望通过TCP通信的操作系统来说,都是必须实现的。下面几节将更多阐述上述操作特定于Linux内核的实现。

四次挥手

类似于连接建立,TCP连接的关闭也是通过一系列分组交换完成的,连接可以采用下列两种方法关闭。

- 在参与传输的某一方(偶尔也会两个系统同时发出请求的情况)显式请求关闭连接时,连接会以优雅关闭(graceful close)的方式终止。

- 高层协议有可能导致连接终止或异常中止(例如,可能因为程序崩溃)。幸运的是,因为第一种情况通常更为常见,这里只讨论这种情况并忽略第二种情况。为了优雅地关闭连接,TCP连接的参与方必须交换4个分组。各个步骤的顺序描述如下:

计算机A调用标准库函数close,发出一个TCP分组,首部中的FIN标志置位。A的套接字切换到FIN_WAIT_1状态。

B收到FIN分组并返回一个ACK分组。其套接字状态从ESTABLISHED改变为CLOSE_WAIT。收到FIN后,以“文件结束”的方式通知套接字。

在收到ACK分组之后,计算机A的套接字状态从FIN_WAIT_1变为FIN_WAIT_2。

计算机B上与对应套接字相关的应用程序也执行close,从B向A发送FIN分组。计算机B的套接字状态变为LAST_ACK。

计算机A用一个ACK分组确认B发送的FIN,然后首先进入TIME_WAIT状态,接下来在一定时间后自动切换到CLOSED状态。

计算机B收到ACK分组,其套接字也切换到CLOSED状态。

解释:

- FIN_WAIT_1:这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

- FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

- TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

- CLOSING:这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也就会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

- LAST_ACK:这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

状态迁移在中枢的分配器函数(tcp_rcv_state_process)中进行,可能的代码路径包括处理现存连接的tcp_rcv_established,以及尚未讨论的tcp_close函数。

在用户进程决定调用库函数close关闭连接时,会调用tcp_close。如果套接字的状态为LISTEN(即没有到另一台计算机的连接),因为不需要通知其他参与方连接的结束。在过程开始时会检查这种情况,如果确实如此,则将套接字的状态改为CLOSED。否则,在通过tcp_close_state并tcp_set_state调用链将套接字状态设置为FIN_WAIT_1之后,tcp_send_fin向另一方发送一个FIN分组。②

从FIN_WAIT_1到FIN_WAIT_2状态的迁移通过中枢的分配器函数tcp_rcv_state_process进行,因为不再需要采取快速路径处理现存连接。我们熟悉的一种情况是,收到的带有ACK标志的分组触发到FIN_WAIT_2状态的迁移,具体的状态迁移通过tcp_set_state进行。现在只需要从另一方发送过来的一个FIN分组,即可将TCP连接置为TIME_WAIT状态(然后会自动切换到CLOSED状态)。

在收到第一个FIN分组因而需要被动关闭连接的另一方,状态迁移的过程是类似的。因为收到第一个FIN分组是套接字状态为ESTABLISHED,处理由tcp_rcv_established的低速路径进行,涉及向另一方发送一个ACK分组,并将套接字状态改为TCP_CLOSING。

下一个状态转移(到LAST_ACK)是通过调用close库函数(进而调用了内核的tcp_close_state函数)进行的。此时,只需要另一方再发送一个ACK分组,即可终止连接。该分组也是通过tcp_rcv_state_process函数处理,该函数将套接字状态改为CLOSED(通过tcp_done),释放套接字占用的内存空间,并最终终止连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185105.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

生鲜巨变:每日优鲜、叮咚买菜、盒马“分道扬镳”?

此前,在疫情影响下,人们出门购物频次减少,传统买菜模式也受到了一定的冲击。在此背景下,既能够解决人们买菜难题又能够减少人与人接触的生鲜电商,赢得了众多消费者的青睐。而随着大量用户涌入其中,整个生鲜…

【GD32F427开发板试用】硬件IIC读取SHT40温湿度传感器

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:烟花易冷 介绍 很荣幸又能再次的参加技术社区的开发板试用活动,此次参加用的是GD32F427系列的芯片,该芯片相较于GDF31…

OpenPPL PPQ量化:原理与实践

目录 量化原理 为什么需要量化? 量化粒度 框架综述 算子划分 量化中的图融合操作 量化实践:以pytorch mobilenet v2 模型为例 源码阅读 torch模型和onnx量化过程中的区别 后记 量化原理 为什么需要量化? 1、减少内存带宽和存储空…

C++Morris遍历

一、关于Morris算法 简介 Morris算法是针对二叉树实现的一个遍历算法,它是一种空间复杂度为O(1)的遍历算法 通常情况下使用迭代或递归的方式遍历二叉树的空间开销都是O(N)级别的,较为理想的情况下可以做到O(logn)级别,而Morris算法通过更改…

Windows Kerberos客户端配置并访问CDH

安装 Kerberos 客户端 配置 hosts 1、配置集群 hosts 到 Windows(C:\Windows\System32\drivers\etc\hosts); 2、调整windows环境变量,将系统环境变量 PATH 中的 C:\Program Files\MIT\Kerberos\bin 放置在最前边,建…

目标跟踪心得篇五:MOT数据集标注、DarkLabel不能自动跟踪解决方案

跟踪方向的标注成本非常很大的 ,那么我们如何尽可能一次性弄好呢? 所选标注工具:DarkLabel DarkLabel是一个轻量的视频标注软件,尤其做MOT任务非常友好,其标注可以通过脚本转化为标准的目标检测数据集格式、ReID数据集格式和MOT数据集格式。 使用之前: darklabel.yml:保…

Python国际化学习教程

很幸运python提供了中文等其他语言的教程! 这里以13.11.1为例 Python 是一门易于学习、功能强大的编程语言。它提供了高效的高级数据结构,还能简单有效地面向对象编程。Python 优雅的语法和动态类型以及解释型语言的本质,使它成为多数平台上写…

nacos的本地配置与启动步骤及NoDataSourceset问题解决

文章前提是本地机器已经安装好了mysql,配置好了mysql与Java环境变量。 首先在网络上找到一个nacos-server包。我本想上传自己的包,但是总是提示资源已经存在,那么可以自行搜索下。 解压开后是个.gz的文件,可以用windows自带的Win…

Golang Profiling - pprof 使用

Golang Profiling - pprof 使用 在编写大型应用程序,处理复杂业务与逻辑时,开发者经常面临系统内存泄漏问题。查找代码是否有效运行的一种有效方法是检查内存堆、CPU、磁盘的使用情况。 要在运行时检查Go应用程序的CPU和内存使用情况以及其他配置文件&…

LeetCode | 704. 二分查找

题:力扣 704. 二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target , 写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。示例 1:输入: nums [-1,0,3,5,9,1…

Lua 调试(Debug)

Lua 调试(Debug) 参考至菜鸟教程。 Lua 提供了 debug 库用于提供创建我们自定义调试器的功能。Lua 本身并未有内置的调试器,但很多开发者共享了他们的 Lua 调试器代码。 Lua 中 debug 库包含以下函数: 序号方法 & 用途1.debug():进入一个用户交互模…

2022年前端React杂记

以下记录的是,我在学习中的一些学习笔记,这篇笔记是自己学习的学习大杂烩,主要用于记录,方便查找1、学习概述React 是当下最火的前端三大框架之一。之前一直没有时间来学习,国庆得空来快速消掉这一块的盲点。学习react…

python 字典 小白笔记

字典反映的是一种映射关系。1.定义用花括号括起来,每个元素包括键值对,键必须是可以用哈希值计算的对象,通常是数字或者字符串。值可以是任何类型的对象。键和值之间用“:”分割。zidian{jian:zhi,jian1:zhi,}2.查找字典可以用键获…

python采集某所有数据,从此不用money

前言 大家早好、午好、晚好吖 ❤ ~ 基本思路流程: <通用的> 一. 数据来源分析: 明确需求: 明确采集的网站是什么? 明确采集的数据是什么? 通过开发者工具<浏览器自带的工具(谷歌浏览器)>, 进行抓包分析 先分析一章内容, 然后再分析如何采集多章内容 打开开发…

ubuntu docker 安装rocketmq记录

安装链接参考该博客 上面的是非ubuntu安装的docker&#xff0c;下面记录ubuntu安装docker遇到的问题及解决 1 创建挂载目录 ─── rocketmq├── conf│ └── broker.conf└── data├── broker│ ├── logs│ └── store└── namesrv├── logs└── st…

ch1_3计算机硬件的技术指标

机器字长&#xff1a; CPU一次能够处理 数据的位数&#xff1b; 与CPU中的寄存器位数有关&#xff1b; 1. 运算速度 不同的指令&#xff0c;执行的频率不同&#xff1b; 部分指令&#xff0c; 执行起来很慢&#xff0c; 但是很少执行&#xff0c;出现的次数低&#xff0c;对…

gf-v1项目结构及目录说明

文章目录1. gf版本2. 项目结构3. 目录说明1. gf版本 2. 项目结构 / ├── app │ ├── common │ │ ├── adapter │ │ ├── api │ │ ├── dao │ │ ├── service │ │ ├── model │ │ ├── … │ ├── system │ │ ├── api │ │ ├── dao │…

MySQL的14个小技巧

我最近几年用MYSQL数据库挺多的&#xff0c;发现了一些非常有用的小玩意&#xff0c;今天拿出来分享到大家&#xff0c;希望对你会有所帮助。 1.group_concat 在我们平常的工作中&#xff0c;使用group by进行分组的场景&#xff0c;是非常多的。 比如想统计出用户表中&…

C++ 设计模式 外观模式 The Facade Pattern

C 设计模式 外观模式 The Facade Pattern 介绍 Facade Pattern 为一组复杂的子系统提供了一个统一的简单接口&#xff0c;它是一种结构型设计模式。 它隐藏了子系统的复杂性&#xff0c;并向客户端提供了一个简单的接口来访问子系统。通过使用 Facade 模式&#xff0c;客户端…

Tag和Untag相关知识科普

欢迎来到东用知识小课堂&#xff01;端口的出和入是针对交换机而言的&#xff0c;即数据帧进入交换机即为进入某个端口。接下来我们就以PEC系列工业级交换机为例&#xff0c;来给大家详细讲解一下1.Access&#xff1a;接入链路&#xff1a;1&#xff09;.入方向&#xff1a;收到…