实战TCP三次握手

news2024/12/26 21:19:42

开篇

在几乎所有的后端开发面试题中,TCP三次握手绝对是最被面试官青睐的题目之一。但是这个东西,平时开发中看不见,摸不着,对于很多人来说,是纯理论的知识,玄之又玄。但是为了应对面试,又不得不去死记硬背。就……真的是硬背。

我之前面试过一个小哥,问了一嘴三次握手,这小哥掰着手指头搁那背,ACK和SEQ都搞反了,我问他SYN标志代表什么意思,也说不大清楚。所以是不是真的搞懂了,一问便知。

对于Java或者Go之类语言的开发者,一个Dial函数就完事了,根本不清楚内部发生了什么,C/C++的开发者相对好一点,最起码知道几个原生的posix API,知道创建socket之后要bind,bind完了之后要listen,然后才是accept。

但这些也是已经封装好的函数,离三次握手离得似乎还是有点远。

我有一个小弟,做golang开发的,有一次我让他调研一下ulimit -c达到上限以后fd的行为,小弟一脸懵逼,问fd是什么。所以说,高级语言封装的太好,的确是方便了开发人员,但也带来了对基础原理的疏远。

我将本文题目取为《实战TCP三次握手》,就是要以一种看得见摸得着的方式,让大家真切感受一下TCP建立的过程中,三次握手到底做了些什么。

关于TCP三次握手的理论知识,往上一搜一大片,本文就跳过理论,直接上手。Let’s go。

准备知识

抓一个TCP三次握手的包

开启三个窗口,窗口1执行命令:

sudo tcpdump -i lo -nn -s0 -vvv port 7899 -A -X

这个命令用来抓包,抓的是7899端口的包。-A-X是为了显示详细的包内容,方便分析。如果不习惯用tcpdump直接分析,也可以使用wireshark,更加直观一些。

窗口2执行命令:

nc -l 7899

该命令监听7899端口,相当于启动了一个监听7899端口的server。当然你要是有兴趣的话,可以用代码写一个server。

窗口3执行命令:

telnet 127.0.0.1 7899

这个命令是向127.0.0.1:7899建立连接,相当于client执行connect函数。

这个命令一执行,就会连接到7899端口上 ,在第一个窗口上立即就会抓到连续的三个包,如下图所示:

在这里插入图片描述

如上步骤,演示了TCP建立连接的过程,tcpdump抓到的三个包,正好就是三次握手。

很多资料讲解三次握手时,都会有一幅类似于这样的图:
在这里插入图片描述

我们对应抓到的三个包来看。

  • 第一个包:
    • 127.0.0.1.48448 > 127.0.0.1.7899 说明是从client 发往server的, client的端口是48448
  • 第二个包:
    • 127.0.0.1.7899 > 127.0.0.1.48448 说明是从server发往client的
  • 第三个包:
    • 127.0.0.1.48448 > 127.0.0.1.7899 从client发往server

这个步骤,和上图大致是能一一对应上的。

除了这些简而易见的信息,还有一些 可能一时半会儿看不懂的东西,比如:

Flags [S], cksum 0xfe30 (incorrect -> 0x2d48), seq 3051156309, win 65495, options [mss 65495,sackOK,TS val 2052530964 ecr 0,nop,wscale 7], length 0

要了解这些东西,需要先了解TCP协议栈。

了解一下TCP协议栈

首先,我们应该知道,一个完整的以太网帧,包含了ethdr + iphdr + tcpdhr + data + etend

其中,以太网头占14字节,IP头占20字节,TCP头占20字节,以太网尾占4字节,应用数据大小不定,但不会超过一个MTU。

因为我们只研究三次握手,所以关于以太网帧,了解这些就够了。
在这里插入图片描述

我们再来看看具体的TCP协议栈:

TCP协议栈包含:

  • 16位源端口号,占2字节
  • 16位目的端口号,占2字节
  • 32位序号(seq),占4字节
  • 32位确认序号(ack),占4字节
  • 4位首部长度,占0.5字节
  • 6位保留位,占0.75字节
  • 6位标志位,占0.75字节, 以上:4位首部长度+6位保留长度+6位标志位,合计16位,计2字节
    • 标志位包括:
      • URG
        • 紧急指针标志
        • 此标志用于将输入数据标识为“紧急”。这样的进入段不必等待直到先前段被接收端消耗,而是直接发送并立即处理
      • ACK
        • 用于确认数据包的成功接收
      • PSH
        • 推送标志
        • 就是指数据包到达接收端以后,不对其进行队列处理,而是尽可能的将数据交给应用程序处理
      • RST
        • 重置标志
        • 段到达不用于当前连接时,使用复位标志,表示主机已重置连接
      • SYN
        • 发送/同步标志
        • 用来建立连接,一般和ACK搭配使用
      • FIN
        • 结束标志
        • 用于结束一个TCP会话, 一般用于四次挥手
  • 16位窗口大小(window size),占2字节
  • 16位校验和(checksum),占2字节
  • 16位紧急指针,占2字节

庖丁解牛,深度剖析TCP协议栈的三次握手

有了以上这些知识,我们再来解析上面的协议栈。

第一个包

127.0.0.1.48448 > 127.0.0.1.7899: Flags [S], cksum 0xfe30 (incorrect -> 0x2d48), seq 3051156309, win 65495, options [mss 65495,sackOK,TS val 2052530964 ecr 0,nop,wscale 7], length 0
0x0000:  4510 003c dbf7 4000 4006 60b2 7f00 0001  E..<..@.@.`.....
        0x0010:  7f00 0001 bd40 1edb b5dc f355 0000 0000  .....@.....U....
        0x0020:  a002 ffd7 fe30 0000 0204 ffd7 0402 080a  .....0..........
        0x0030:  7a57 2314 0000 0000 0103 0307            zW#.........

十六进制报文中,前20个字节是IP协议头,后20个字节虽然也属于TCP协议 ,但是是可选项option,并非标准的TCP协议一定有的内容,所以我们真正关心的内容 , 是下面高亮的部分:
在这里插入图片描述
即:

bd40 1edb b5dc f355 0000 0000 a002 ffd7 fe30 0000

接下来,我们逐个字节解析:

  • 16位源端口, 即 bd40, 转换成10进制为48448

  • 16位目的端口,即1edb,转换成10进制为7899

    • 从以上信息可知,该条消息是从48448发往7899端口,即客户端发往服务端
  • 32位序号:b5dc f355, 即3051156309

  • 32位确认号:0000 0000,即0

  • 后面三个域由于不是 完整的字节,放在一块解析:

    • a002翻译成二进制 ,为: 1010 0000 0000 0010

    • 其中,4位首部长度,为1010,即10

    • 6位保留字段,即0000 00,不做解释

    • 6位标志位,即00 0010

      • 标志位要解释一下 :

        URGACKPSHRSTSYNFIN
        000010
      • 标志位哪一位设置为1,就代表当前属于什么包

      • 由上面对应关系,可知当前是一个SYN包。

  • 16位窗口大小:ffd7, 即65495

  • 16位校验和,即:fe30

  • 16位紧急指针,即0000

由以上内容,我们提取一些关键信息:

第一次握手:

  • 客户端发往服务端
  • 标志位为SYN
  • seq为3051156309
  • ack为0

第二个包

127.0.0.1.7899 > 127.0.0.1.48448: Flags [S.], cksum 0xfe30 (incorrect -> 0xd4f6), seq 2031501770, ack 3051156310, win 65483, options [mss 65495,sackOK,TS val 2052530964 ecr 2052530964,nop,wscale 7], length 0
        0x0000:  4500 003c 0000 4000 4006 3cba 7f00 0001  E..<..@.@.<.....
        0x0010:  7f00 0001 1edb bd40 7916 41ca b5dc f356  .......@y.A....V
        0x0020:  a012 ffcb fe30 0000 0204 ffd7 0402 080a  .....0..........
        0x0030:  7a57 2314 7a57 2314 0103 0307            zW#.zW#.....

由上面的知识,我们知道TCP报文主要是下面这段:

1edb bd40 7916 41ca b5dc f356 a012 ffcb fe30 0000

通过同样的方法,可以解析出:

第二次握手:

  • 服务端发往客户端
  • 标志位为ACK+SYN
  • seq为2031501770
  • ack为3051156310, 正好是第一次握手的seq+1

第三个包

127.0.0.1.48448 > 127.0.0.1.7899: Flags [.], cksum 0xfe28 (incorrect -> 0xfbb2), seq 1, ack 1, win 512, options [nop,nop,TS val 2052530964 ecr 2052530964], length 0
        0x0000:  4510 0034 dbf8 4000 4006 60b9 7f00 0001  E..4..@.@.`.....
        0x0010:  7f00 0001 bd40 1edb b5dc f356 7916 41cb  .....@.....Vy.A.
        0x0020:  8010 0200 fe28 0000 0101 080a 7a57 2314  .....(......zW#.
        0x0030:  7a57 2314                                zW#.

TCP协议部分:

bd40 1edb b5dc f356 7916 41cb 8010 0200 fe28 0000

可以解析出 :

第三次握手:

  • 客户端发往服务端
  • 标志位: ACK
  • seq为3051156310,为第一次我收的 seq+1,也是第二次握手的ack
  • ack为2031501771, 为 第二次握手的seq+1

归纳:

以上内容,如果用比较直观的方式总结一下 ,大约如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGYNkakE-1684539759784)(tcp三次握手.assets/image-20230520072022886.png)]

为什么需要三次握手

又回到老生常谈的话题:为什么需要三次握手?少一次行不行?只握手一次成不成?

在聊这个话题之前,我们引入一下著名科幻小说《三体》中叶文杰教主和三体文明建立联系的过程。

首先,叶教主向三体文明发送了一条消息,紧接着,三体人回复了一条消息,内容是“不要回答,不要回答,不要回答!”然后叶教主回复了这条消息 ,导致地球成功被三体人定位。

不得不说,大刘是懂TCP协议的。至少他懂三次握手的重要性。

第一次发消息,你说三体人收到没有?肯定是收到了的。但这个连接可靠不?明显不可靠。对于三体人来说,他怎么知道这个消息是谁发的?发消息的文明是否还活着?对于地球来说,更是如此,他怎么知道 这条消息对方肯定收到了?又没有人收?

第二次发消息,三体人差不多要把ACK标志写在脸上了,就是明明白白告诉你,我这是一个ACK消息,你只要不应答这个ACK,我们这个连接就建立不成,三体小说就全剧终。这就相当于三体人告诉叶教主:我活着,并且能收到你的消息,但是我还不知道你是谁,你能不能收到我这条消息。

所以第三条消息,狡猾的大刘当然不会让三体就此game over,就是老叶告诉三体人,我也能收到你的消息,从此以后,咱们是“同志”了。

类比三次握手,和这个步骤非常相似,缺少其中任意一环,这个连接都是不可靠的,因为你不知道对方能不能收到我的消息。所以三次握手,并不是表示连接“可达”的,而是表示连接“可靠”的。这之间是有区别的,可达很简单,UDP也能可达,一次握手也是可达的,但是并不可靠。因为无法知道这条消息对方能不能正确接收到。只有这样反复确认后,才能表示这个连接是可靠的连接。

有杠精肯定表示不服,说理虽然是这么个理,但是会不会有巧合啊。比如某个服务既是客户端又是服务端,我在给你发第一次握手的时候,你也恰好在给我发第一次握手,让我误以为你给我的消息是第二次握手的回包,从而建立了一个不可靠的连接?

而杠精之所以是杠精,就是因为木有脑子。你考虑的问题,咱们祖师爷肯定都考虑到了。

我们在前面分析三次握手的过程的时候,为什么要强调ack = 上一次的seq+1?就是代表我不仅收到了你的,我还在你的seq上加1,代表我收到的确实是你的消息,这就相当于给这条消息打上了独一无二的标志,别人想鱼目混珠都不可能。

最后,咱们说说,三体人和叶文杰建立的是TCP连接吗?咳咳,明显不是。本文只是举例类比。要知道,叶文杰第一个包可是broadcast,谁都能收到的。


本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对C/C++课程感兴趣的读者,可以点击链接,查看详细的服务:C/C++Linux服务器开发/高级架构师

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

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

相关文章

《JavaEE》网络编程TCP/IP五层协议万字详解

文章目录 TCP/IP五层协议栈应用层xml &#xff08;可读性比较好 但是运行效率不高&#xff09;json&#xff08;可读性好 但是运行效率不高&#xff09;prtobuffer(可读性不好 但是运行效率很高) 传输层UDP TCPTCP数据解读32位序号32位确认序号4位首部的长度保留位6位标志位字段…

C语言实现学生管理系统

学习完C语言之后&#xff0c;我们可以通过简单写一个学生管理系统来检验自己学的怎么样。很多计算机系大学生都会学到C语言&#xff0c;对于C语言课程的设计作业可能会感到困难&#xff0c;该篇博客的核心点就是带领读者单独完成学生管理系统&#xff0c;此篇博客附有整个学生管…

【C++ 入坑指南】(11)指针

文章目录 一、概念定义和使用二、空指针 & 野指针2.1 空指针2.2 野指针2.3 小结 三、const 修饰的指针四、指针 和 数组五、指针和函数六、实例 学习 C 的指针既简单又有趣。通过指针&#xff0c;可以简化一些 C 编程任务的执行&#xff0c;还有一些任务&#xff0c;如动态…

数据全生命周期管理

数据存储 时代"海纳百川&#xff0c;有容乃大"意味结构化、半结构和非结构化多样化的海量的 &#xff0c;也意味着批数据和流数据多种数据形式的存储和计算。面对不同数据结构、数据形式、时效性与性能要求和存储与计算成本等因素考虑&#xff0c;应该使用适合的存储…

组合预测模型 | ARIMA-CNN-LSTM时间序列预测(Python)

组合预测模型 | ARIMA-CNN-LSTM时间序列预测&#xff08;Python&#xff09; 目录 组合预测模型 | ARIMA-CNN-LSTM时间序列预测&#xff08;Python&#xff09;预测结果基本介绍程序设计参考资料 预测结果 基本介绍 ARIMA-CNN-LSTM是一种结合了传统时间序列模型和深度学习模型的…

chatgpt赋能Python-python3的下载

Python 3-您在编程路上不可或缺的伙伴 如果您正在寻找一种流行的编程语言&#xff0c;那么Python 3就是一个不错的选择。Python 3作为一种高级编程语言&#xff0c;可以轻松地创建各种应用程序和网站。它是最受欢迎的编程语言之一&#xff0c;就是因为它易于学习和使用。 Pyt…

本地部署 VisualGLM-6B

本地部署 VisualGLM-6B 1. 什么是 VisualGLM-6B2. Github 地址3. 安装 Miniconda34. 创建虚拟环境5. 安装 VisualGLM-6B6. 启动 VisualGLM-6B7. 访问 VisualGLM-6B8. API部署9. 命令行部署 1. 什么是 VisualGLM-6B VisualGLM-6B 是一个开源的&#xff0c;支持图像、中文和英文…

大模型时代下智能文档处理核心技术大揭秘

大模型时代下智能文档处理核心技术大揭秘 前言一张图全览文档图像分析与预处理图像预处理的整体架构核心技术点应用场景 版面分析与还原整体架构核心技术点应用场景 AI安全文档图像篡改检测 大模型时代思考总结 前言 最近&#xff0c;中国图像图形大会在苏州圆满结束&#xff0…

碳交易机制下考虑需求响应的综合能源系统优化运行(matlab代码)

目录 1 主要内容 架构模型&#xff1a; 需求响应模型&#xff1a; 目标函数&#xff1a; 2 部分程序 3 程序结果 4 下载链接 1 主要内容 该程序复现文献《碳交易机制下考虑需求响应的综合能源系统优化运行》&#xff0c;解决碳交易机制下考虑需求响应的综合能源系统优化…

Emacs之快速高亮查找字符(九十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

ubuntu22.04静态ip设置(桥接模式、only-host+NAT模式)

在创建一台虚拟机后&#xff0c;默认的方式往往是通过DHCP动态的进行分配&#xff0c;DHCP服务器会告知创建的虚拟机分配到的ip地址&#xff0c;网关地址等信息。所以在创建好虚拟机之后&#xff0c;这些信息都不需要我们来配置&#xff0c;我们直接用就好了。 但是&#xff0…

redis集群之hash槽分析算法

上文提过了 hash取余算法和hash一致性算法 一致性hash算法是为了减少节点数目发生改变时尽可能的减少数据迁移 将所有的存储节点排在首位相连的Hash环上&#xff0c;每个key在计算hash后会顺时针找到临近的存储节点。 而当有节点加入或退出时&#xff0c;仅影响该节点在hash环上…

chatgpt赋能Python-python3求平均值

Python3求平均值-从基础到实践 Python3作为一种广泛使用的编程语言&#xff0c;被广泛应用于不同的领域。今天我们将探讨如何使用Python3求平均值。求平均值在数学和统计学中非常常见&#xff0c;使我们能够了解数据的中心趋势&#xff0c;并简化数据分析过程。让我们深入了解…

DELPHI7实现XP菜单风格

在DELPHI7中不使用任何第三方控件,实现放在工具栏上可拖动的XP风格菜单 今天有点空闲时间,顺便写点东西,不是什么深奥的东西,但实用,对于不想第三方控件但又想加点效果的朋友可能有点用.实现的效果如图: 步骤一:把Win32面板上把CoolBar组件加到窗体上 步骤二:把Additional面板上…

VBA 密码删除软件 4n6.VBA Password Remover 1.2 Crack

VBA 密码删除软件 软件评级&#xff08;基于 1541 条评论的平均评分 4.8&#xff09; 该工具是完美的软件&#xff0c;可以解锁任何类型的受密码保护的 VBA 文件。用户可以轻松使用此 VBA 密码删除软件并从 VBA 文件中删除密码保护。 兼容所有 Office 文件格式&#xff1a;.d…

Linux线程5——生产消费模型

生产消费模型 1个交易场所:超市 2种角色:生产者/消费者 3种关系:生产者和生产者(竞争关系也叫互斥关系),消费者和消费者(竞争关系同样是互斥关系),生产者和消费者(互斥,同步关系:生产完再消费或消费完再生产)。 以上是生产消费模型遵守的“321”原则。 生产者和消…

RocketMQ Connect 核心知识点概述

一、概览 RocketMQ Connect是RocketMQ数据集成重要组件&#xff0c;可将各种系统中的数据通过高效&#xff0c;可靠&#xff0c;流的方式&#xff0c;流入流出到RocketMQ&#xff0c;它是独立于RocketMQ的一个单独的分布式&#xff0c;可扩展&#xff0c;可容错系统&#xff0…

英文文本情感分析textblob模块sentiment方法

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 英文文本情感分析 textblob模块 sentiment方法 [太阳]选择题 关于下列代码说法错误的是&#xff1f; from textblob import TextBlob myText"Textblob is amazingly simple to us…

chatgpt赋能Python-python3绝对值

Python3绝对值——学习Python3编程的基础 Python3是一种非常流行的编程语言&#xff0c;可以应用于各种不同的场景&#xff0c;例如数据科学、机器学习、网络编程、自动化脚本、游戏开发等。在Python3编程中&#xff0c;绝对值是一个基础的概念。 什么是绝对值&#xff1f; …

【网络编程】实现UDP/TCP客户端、服务器

目录 一、UDP 1、Linux客户端、服务器 1.1udpServer.hpp 1.2udpServer.cc 1.3udpClient.hpp 1.4udpClient.cc 1.5onlineUser.hpp 2、Windows客户端 二、TCP 1、单进程版的TCP客户端、服务器 1.1tcpServer.hpp 1.2tcpServer.cc 1.3tcpClient.hpp 1.4tcpClient.cc …