前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >请求数据包从发送到接收,都经历什么?

请求数据包从发送到接收,都经历什么?

作者头像
SH的全栈笔记
发布于 2022-08-17 07:32:17
发布于 2022-08-17 07:32:17
8590
举报
文章被收录于专栏:SH的全栈笔记SH的全栈笔记

之前讲了「从输入 URL 再到浏览器成功看到界面」中的域名是如何变成 IP 地址的,了解了 DNS 相关的东西。这篇文章就聊聊发生在 DNS 解析之后的操作——建立连接。也就是我们常说的三次握手

看到三次握手你可能会说,这不是面试都被问烂了的题吗?

三次握手不就是:

  1. 服务器开始为 CLOSE 状态,然后监听某个端口,此时服务器会进入 LISTEN 状态
  2. 客户端最初也是 CLOSE 状态,客户端会向服务器发送一个带 SYN 标志位的数据包,主动发起连接。此时客户端会变成 SYN-SENT 状态
  3. 服务器接收到客户端的数据包之后,通过标志位判断出了客户端想要建立连接。然后返回一个 SYNACK ,此时服务器的状态变为了 SYN-RCVD
  4. 客户端收到了服务器的 ACK 之后,会回一个 ACK 给服务器,回完这个 ACK 之后,服务器的状态就变为了 ESTABLISH
  5. 服务器收到了客户端回复的 ACK 之后,服务器的状态也变成了 ESTABLISH

这不就完了吗?还有什么好聊的?

这篇文章不会涉及到上面提到的什么各种状态的变化,包内的标志位是什么,而是会更加关注于底层的东西,也就是上面那些发来发去的数据包是如何发送出去的

其实不仅仅是建立连接时的三次握手,像浏览器中调用的很多 HTTP 接口,都会和服务器进行通信。

那这些个请求到底都是怎么发送给服务器的呢?

这还用问?不就是发个 HTTP 请求就过去了吗?

当然,这个答案可能是很多不了解网络的人可能会说出的答案。

其实更具体、更准确的说法是通过协议栈网卡发送出去的。

其中,协议栈负责对数据进行打包,打包完成之后就由网卡将数据转换成电信号,通过光纤发送出去了。

网卡自不必说,用来和其他的计算机进行通讯的硬件,我们常说的 MAC(Medium Access Control) 地址,其实就是网卡的编号,从其被生产出来的那一刻就被确定的一个唯一编号。MAC 地址长为 48 个比特,也就是 6 个字节,用十六进制进行表示。

当我们知道了和我们通信的 IP 地址之后,就可以委托操作系统中的协议栈将来来自应用程序的数据,打包成数据包然后发送出去。那协议栈,具体是啥呢?协议栈其实是一系列网络协议的总和,例如:

  • TCP
  • UDP
  • IP

不同的应用程序在进行数据传输的时候,可能会选择不同的协议。例如我们使用的浏览器就是使用的 TCP 协议,而像之前讲过的 DNS 解析就用的 UDP 协议。

那数据在协议栈中到底经历了什么?才变成了一个一个的数据包?

就拿我们向服务器发送一个 HTTP 请求作为例子,我们知道 HTTP 请求中有:

  • 请求行
  • 请求头
  • 请求体

HTTP 是属于应用层的协议,而应用层还有很多其他的协议,每个协议所涉及到的数据也都不同,协议栈要怎么去兼容不同协议之间的数据呢?

答案是不做兼容。对于协议栈来说,所有的数据都只不过是一堆二进制序列

那协议栈收到了这一堆二进制序列之后是不是就直接交给网卡发送了呢?

我都这么问了,那显然不是了...

其实协议栈在收到数据之后并不会马上就会就发送出去,而是会先写入位于内存的 Buffer 中。那为啥不直接发出呢?

其实很简单,假设你现在正在公交车的起始站,你觉得公交车会来一个人就立马发车吗? 显然不是,它会等一段时间,有更多的乘客上车之后再发车。但是它又不能等太长的时间,不然后续站台的乘客就会等的很久。

协议栈之所以不立即发出去,其实也是同样的道理。其实这背后无非基础两种考虑:

  1. 数据的长度
  2. 等待的时间

应用层的程序发送过来的数据可能长度都不太一样,有的可能一个字节一个字节的发, 有的可能一次性就传入所有的数据。

如果收到数据就发送出去,会导致在网络中传输着很多小包,而这会降低网络传输的效率。

所以,协议栈在收到数据之后会等待一段时间,等数据达到一定量之后,再执行发送操作。

但是,协议栈又不能等的太久是吧?等太久了你让正在电脑面前操作的用户情何以堪,这种发送延迟会让用户体验刷刷的往下掉。

但是吧,想做到对这两者的平衡却不是一件简单的事。数据包太短,降低网络传输效率,等待太长时间,又会造成发送延迟。所以协议栈索性就把控制权交给了应用程序。

应用程序可以自己控制到底采取哪种措施,例如我们常用的浏览器,因为和用户实时的在进行交互,用户对整个页面的响应速度也相当敏感,所以一般都会采用直接发送数据的方式,即使其数据并没有达到「一定的量」

这一个「一定的量」到底是啥?

的确,上面都只说一定的量、一定的量,那这个量到底是多少?

要了解这个我们需要知道两个参数,分别是:

  1. MTU(Maximum Transmission Unit)最大传输单元
  2. MSS(Maximum Segment Size)最大分段大小

MTU 其实就代表了上面途中数据包的最大长度,一般来说是 1500 字节。而我们需要知道数据包是由以下部分组成的:

  1. 各种头部信息
  2. 真实数据

而从 MTU 中减去各种头部数据的大小,剩下的就是 MSS 了,也就是实际的数据。

知道了数据包的组成和 MTU、MSS 的概念之后,我们就可以继续接下来的步骤了。某次发送的数据,没有超过 MSS 还好,就可以直接发送出去了。

那如果超过了 MSS 咋办?例如我发这篇文章时所发请求的数据长度就可能超过 MSS 。

过长数据包拆分

此时就需要对数据进行拆分,按照 MSS 的长度为单位进行拆分,将拆出来的数据分别装进不同的数据包中。拆分好之后,就可以发送给目标服务器了。

TCP 会确保通信的服务器能够收到数据包。传输时对每个字节都进行了编号,举个例子,假设此次传输的数据是 1 - 1000 字节,然后服务器回的 ACK 就会是 1001,这就代表没有丢包

这些发送过的包都会暂存在 Buffer 中,如果传输的过程中出错,则可以进行重发的补偿措施。这也是为什么在数据链路层(例如网卡、路由器、集线器)等等都没有补偿机制,它们一旦检测到错误会直接将包丢弃。然后由传输层重发就好。

那要是网络很拥堵,服务器一直没有返回怎么办?

在服务器端,我们去和其他第三发进行交互时,是不是都会设定一个超时的时间?如果不设置超时时间那难道一直在这等下去吗?

TCP 也同理。客户端在等待服务器响应时,会有一个时间叫 ACK 等待时间,其实也是超时时间。

当网络发生拥堵时,其实你完全也可以把网络拥堵理解成路上堵车。此时,ACK 的返回就会变慢。如果返回时间长到了让客户端认为服务器没有收到,就有可能会重发。

并且有可能刚刚重发完,ACK 就到了。虽然服务器端可以通过序号来对包进行判重,不会造成错误,但是这种没有意义的重复包,在本身网络负担已经很重的情况下,你还往里怼重复的无用的数据包,这不是扯淡吗?这明显不行的。

那怎么避免上面的这个情况呢?答案很简单,稍微延长一点 ACK等待时间,这样一来就能一定程度上避免上述的问题。但是用屁股想想应该也知道,这个时间肯定不是越长越好,再长用户那又该等爆炸了。

除了网络波动会影响到 ACK 的返回时间,通信的物理距离也是一个影响的因素。说白了就是这玩意儿不可能设置一个固定的时间。所以,实际上,这个等待时间动态调整的,这次稍微返回慢了点,那我下次就稍微延长一点等待时间。返回 ACK 的速度如果很给力,那么就会相应的减少 等待

上面的概念也有一个大家很熟悉的名字,叫——超时重传

我们来设想一个更加极端的情况,假设你们通信的网线被挖断了,甚至机房起火了,这个时候无论你重发多少次都没用。那 TCP 不就一直无限循环的把请求发下去了?

当然 TCP 设计时也考虑到了这种情况,其在重传几次无效之后,就会强制中断通信,并抛出错误给应用程序。

问题又来了,客户端在向服务器发送数据包之后,等待 ACK 的过程中,真的就只是等 ACK,其他的什么也不做吗?

当然不是,这样极其的浪费资源,降低通信效率。发送完一个数据包之后,不用等待 ACK 的返回,会直接继续发送下一个包,这就是滑动窗口

但是这样会有一个问题,应用程序发送包发送的过于频繁,导致服务器接收不过来了。

因为刚刚说过,应用程序发送的时候,会将发送过的数据存储在 buffer 中。而对于接收方也是一样的,接收方收到消息之后,会将数据存储在 Buffer 中,然后在 Buffer 中对收到的数据进行重组,还原成最初的应用程序发送的数据。

但是如果发送的数据太快,超过了重组的速度,缓冲区就会被填满。而缓冲区一旦被填满,后续的数据就无法再接收了,然后丢包就出现了。

那 TCP 是如何解决这个问题的呢?答案是 流量控制。为了防止传输方发送的过快直接造成丢包,继而触发上面的超时重传机制,根据接收方的接受能力,来决定发送方的传输速度,这个机制就是流量控制

该机制作用于接受方。在TCP报文头部中会用一个16位的字段来表示窗口大小非常重要的调优参数。这个数字越大,则说明接收方的缓冲区越大,能够接收更多的数据。接收方会在确认应答的时候,将自己的剩余窗口大小写入,随ACK一起发送给发送方。

TCP流量控制

如果发送方接收到的大小为0,那么此时就会停止发送数据。这样会有一个问题,如果下一个应答(也就是窗口大小不为0)在过程中丢了,那么发送方就会进入死锁,相互等待。所以发送方会定期的向接收方发送窗口探测的数据段

好了,关于数据包的发送就介绍到这里。之后有机会再聊聊 TCP 的拥塞控制相关的东西。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SH的全栈笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
编程开发中的Compile、Make、Build详细对比
针对Java的开发工具,一般都有Compile、Make和Build三个菜单项,完成的功能的都差不多,但是又有区别。
JavaEdge
2022/11/30
1K0
编程开发中的Compile、Make、Build详细对比
【Java】idea找不到符号找不到类,但是却没有错误
友情提示:打包,先clean在package,如果为子包(被其他项目所引入包:先clean,再install)
全栈程序员站长
2022/09/13
4K0
【Java】idea找不到符号找不到类,但是却没有错误
CMake vs Make对比
程序员现在已经使用了CMake和Make了很久。当您加入大公司或开始使用大型代码库开发项目时,您需要处理所有这些构建。你必须看到这些“CMakeLists.txt”文件浮动。你应该在终端上运行“cmake”和“make”命令。很多人只是盲目地按照指示,不是真的关心为什么我们需要以某种方式做事情。这个整个构建过程是什么,为什么它这样构造?CMake和Make之间有什么区别?有关系吗?可以互换吗? 事实证明,它们是完全不同的。了解他们之间的区别是非常重要的,以确保您不会陷入困境。在分析之前,先看看它们是什么。 make 我们设计软件系统的方式是我们首先编写代码,然后编译器编译并创建可执行文件。这些可执行文件是执行实际任务的可执行文件。“Make”是从程序的源文件中控制程序的可执行文件和其他非源文件的生成工具。 “Make”工具需要知道如何构建程序。它了解如何从名为“makefile”的文件构建程序。这个makefile列出了每个非源文件以及如何从其他文件中计算它。编写程序时,应该为其编写一个makefile,以便可以使用“Make”来构建和安装程序。简单的东西!如果您不明白,请再次阅读该段落,因为下一部分重要。 为什么我们需要“Make”? 我们需要“Make”的原因是因为它使最终用户能够构建和安装您的软件包,而无需了解其操作的详细信息。每个项目都有自己的规则和细微差别,每当你有一个新的合作者,它都会变得非常痛苦。这就是我们有这个makefile的原因。构建过程的细节实际上记录在您提供的makefile中。根据哪些源文件已更改,“自动”自动显示需要更新的文件。它还自动确定更新文件的正确顺序,以防一个非源文件依赖于另一个非源文件。 每当我们改变系统的一小部分时,重新编译整个程序将是低效的。因此,如果您更改了一些源文件,然后运行“Make”,它不会重新编译整个事情。它仅更新直接或间接依赖于您更改的源文件的那些非源文件。很整洁!“Make”不限于任何特定语言。对于程序中的每个非源文件,makefile指定了用于计算它的shell命令。这些shell命令可以运行一个编译器来产生一个对象文件,链接器生成一个可执行文件,以便更新一个库,Makeinfo格式化文档等。“Make”不仅限于构建一个包。您还可以使用“Make”来控制安装或卸载软件包,为其生成标签表, CMake的 CMake代表跨平台制作。CMake识别哪个编译器用于给定类型的源。如果您不知道,您不能使用相同的编译器来构建所有不同类型的源。您可以在每次建立项目时手动执行,但这将是乏味和痛苦的。CMake为每种类型的目标调用正确的命令序列。因此,没有明确指定像$(CC)这样的命令。 为了编码真正想要血液细节的垃圾,请继续阅读。如果你不是所有的,你可以跳到下一节。处理包含头文件,库等的所有常见的编译器/链接器标记都被平台独立的和构建系统无关的命令所取代。调试标志包括将变量CMAKE_BUILD_TYPE设置为“调试”,或者在调用程序时将其传递给CMake: cmake -DCMAKE_BUILD_TYPE:STRING =调试。 CMake还提供平台独立包含'-fPIC'标志(通过POSITION_INDEPENDENT_CODE属性)和许多其他。尽管如此,还可以通过CMake以及Makefile(通过使用COMPILE_FLAGS和类似属性)手动实现更为模糊的设置。当然,当第三方库(如OpenGL)以便携式的方式被包含时,CMake真的开始闪耀。 有什么不同? 如果您使用Makefile,即在命令行中键入“make”,则构建过程有一个步骤。对于CMake,有两个步骤:首先,您需要设置构建环境(通过在构建目录中键入cmake <source_dir>或运行某些GUI客户端)。根据您选择的构建系统(例如,在Windows上的Make on * nix,VC ++或MinGW等),这将创建一个makefile或相当的东西。构建系统可以作为参数传递给CMake。但是,CMake根据您的系统配置做出合理的默认选项。其次,您在选定的构建系统中执行实际构建。 我们将在这里跳入GNU构建系统领域。如果你不熟悉,这一段可能看起来像是jibber-jabber给你。好的,现在我给了法定的警告,我们继续吧!我们可以比较CMake和Autotools。当我们这样做时,我们可以看到Make的缺点,它们构成了Autotools创建的原因。我们还可以看到CMake对Make的明显优势。Autoconf解决了一个重要的问题,即可靠地发现系统特定的构建和运行时信息。但这只是便携式软件开发中的一小部分。为此,GNU项目开发了一套集成的实用工具来完成Autoconf开始的工作:GNU构建系统,其最重要的组件是Autoconf,Automake和Libtool。 “做”不能这样做,至少没
sunsky
2020/08/20
4.2K0
make menuconfig makefile kconfig详解
前面有一片文章分析make menuconfig执行过程:http://blog.csdn.net/xinyuan510214/article/details/50964808
全栈程序员站长
2022/09/01
1.9K0
./configure,make,make install的作用
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haluoluo211/article/details/50390508
bear_fish
2018/09/20
3.3K0
Gradle Spring Intellij Idea下热部署实现“敏捷”开发 | TW洞见
今日洞见 文章作者来自ThoughtWorks:朱本威。 本文所有内容,包括文字、图片和音视频资料,版权均属ThoughtWorks公司所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布/发表。已经本网协议授权的媒体、网站,在使用时必须注明"内容来源:ThoughtWorks洞见",并指定原文链接,违者本网将依法追究责任。 #百万奖金有奖问答#程序员的什么最值钱? 是他/她们的聪明才智,简洁代码,惊艳的颜值,还是无与伦比的手速,都不是,是宝贵的时间。 如果,你有机会尝试纯前端
ThoughtWorks
2018/04/20
1.8K0
Linux 下的make命令与Makefile
博客内容包含linux下make命令的使用与makefile的书写规则等,希望通过本文档使读者对make命令makefile文件有进一步了解,由于鄙人经验学识有限文档中会有描述不准确以及理解偏差,欢迎读者指正。fythons@sina.com
全栈程序员站长
2022/09/05
10.2K0
成为Oceanbase贡献者(2):源码解读build.sh debug --make 的执行过程
本文主要描述:源码如何编译ob build.sh debug --make 的执行过程
程序员小王
2025/01/27
480
IDEA配置Tomcat服务器并创建Java Web项目
一:创建Web项目 Step-one:创建Web项目 File->new Project Step-two:在WEB-INF目录下创建classes和lib目录 new -> Directory S
AlicFeng
2018/06/08
2.1K0
IDEA快速入门(Mac版)
【持续更新】一篇今年年头的老文章顺道发布了,大家有任何问题可以留言沟通。当时刚刚加入团团,愿大家有机会还是购买一台MAC,确实能给大家的效率赋能,虽然在一开始会有一些艰难!⛽️ 望借着换工作的东风,好好的俊一波IDEA,之前始终习惯于Eclipse的使用。
用户1216676
2018/12/27
3.5K0
IDEA快速入门(Mac版)
Delphi入门教程[通俗易懂]
Delphi是基于Pascal语言的RAD快速应用程序开发工具(Rapid Application Development),为Windows系统下的可视化集成开发工具,它提供强大的VCL(Visual Component Library,可视化组件库)
全栈程序员站长
2022/07/02
7.3K0
Delphi入门教程[通俗易懂]
CMake使用教程和原理
CMake是一个主要用于CPP的构建工具。CMake语言是平台无关的中间编译工具。同一个CMake编译规则在不同系统平台构建出不同的可执行构建文件。在Linux产生MakeFile,在Windows平台产生Visual Studio工程等。CMake旨在解决各平台的不同Make工具的产生的差异(比如GNU Make, QT的qmake,微软的nmake, BSD的pmake)。
mariolu
2019/12/28
13.9K0
make命令和makefile文件
  make命令和makefile文件的结合提供了一个在项目管理领域十分强大的工具,它不仅常被用于控制源代码的编译,而且还用于手册页的编写以及将应用程序安装到目标目录。
全栈程序员站长
2022/07/18
2.6K0
Visual Studio 2008 每日提示(三十二)
#321、使用xml可视化工具 原文链接:You can use the XML Visualizer to view XML 操作步骤: 例如,在一段代码段文件里,你有一些有趣的字符串其中包含xml。 你可以选择文本可视化工具,不过看起来不是很舒服 如果你选择xml可视化工具,可以看见xml属性高亮显示 评论:在调试状态看有关xml内容选择xml可视化工具最合适了。 #322、使用html可视化工具 原文链接:You can use the HTML Visualizer to vie
Jianbo
2018/03/01
1.2K0
深入掌握 Makefile 与 Make 工具:高效管理自动化编译的核心原理和最佳实践
make 是一个在 Unix/Linux 系统中广泛使用的构建工具,用于自动化编译和构建项目。make 命令通过读取一个名为 Makefile 或 makefile 的文件,根据其中定义的规则执行各种任务(如编译、链接等),从而简化和自动化项目的构建过程。
Srlua
2024/10/30
6120
深入掌握 Makefile 与 Make 工具:高效管理自动化编译的核心原理和最佳实践
make makefile cmake qmake都是什么,有什么区别?
作者:玟清 链接:https://www.zhihu.com/question/27455963/answer/36722992 来源:知乎 著作权归作者所有,转载请联系作者获得授权。
bear_fish
2018/09/19
2.3K0
make makefile cmake qmake都是什么,有什么区别?
CMake编写总结
make和CMake之间的关系是CMake 通过命令可以生成make执行的Makefile文件,所以说CMake 是make 的升级版的生成工具
impressionyang
2020/08/27
1.1K0
Maven入门教程
静默虚空
2018/01/05
1.4K0
Maven入门教程
Cmake的使用
有了Cmake以后,只需要编写一个CmakeLists文件就可以对应将一个C++工程不通操作系统
全栈程序员站长
2022/09/22
1.4K0
Cmake的使用
make编译安装程序的技巧
在 Linux 中,源码安装软件灵活且适应性强,适用于各种平台,同时也方便维护,比如我们可以指定安装路径。
鳄鱼儿
2024/08/19
1640
相关推荐
编程开发中的Compile、Make、Build详细对比
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文