【读书笔记-《网络是怎样连接的》- 2】Chapter2_1-协议栈通信详细过程

第二章从协议栈这部分来看网络中的通信如何实现,准备从两部分来进行分解。本篇是第一部分:详细介绍TCP协议栈收发数据的过程。

在这里插入图片描述
首先来看下面的图。从应用程序到网卡需要经过如下几部分,上面的部分通过委托下面的部分来完成工作。首先是应用程序,通过Socket库来委托协议栈完成工作。Socket库中包含解析器,可以通过向DNS发送信息获取IP地址,这在第一篇【读书笔记-《网络是怎样连接的》- 1】Chapter1-从Web浏览器开始中已经做了介绍。

接下来进入协议栈。协议栈的上半部分分两种:TCP协议与UDP协议。TCP协议与UDP协议会在后面详细介绍,这里只需要先记住浏览器、邮件等一般应用程序收发数据时用TCP,DNS查询等收发较短的控制数据时用UDP就可以了。

下半部分是IP协议控制网络包收发操作的部分。在互联网上传送数据时,数据会被切分成多个网络包,IP协议就负责将网络包发送给通信对象。此外IP中还包括ICMP协议与ARP协议。ICMP用于告知网络包传送过程中产生的错误以及各种控制消息,ARP用于根据IP地址查询相应的以太网MAC地址。

再下面就是网卡驱动程序,控制下一层的网卡完成数据的收发操作。

本篇我们就来看协议栈的上半部分中TCP协议完成数据收发操作的过程。

在这里插入图片描述

1. 创建套接字

我们已经知道套接字在收发数据中发挥着关键作用,那么套接字具体是什么?

其实套接字没有实体。协议栈在创建套接字时会分配一块内存,其中存放了通信控制信息,这块内存空间就可以被称为套接字。协议栈在执行操作时要参照这些控制信息。这些控制信息包含什么呢?例如,在发送数据时,需要查看套接字中通信对象的IP地址与端口号。发送数据之后,协议栈会等待对方的响应信息。网络中的数据可能丢失。如果一直等不到响应信息,则需要在等待一定时间之后重新发送,这就需要在套接字中记录是否收到响应信息,以及发送数据后经过的时间等等。

从以上的例子可以看出,协议栈是根据套接字中的控制信息来工作的

我们来看看实际的套接字。在Windows系统下运行netstat -ano命令,可以查看到如下信息:
在这里插入图片描述展示的每一行信息表示一个套接字。

创建套接字主要有两个步骤。首先协议栈分配一块内存空间,并写入如上初始的控制信息;接下来还需要将套接字的描述符告知应用程序。这样后续应用程序在使用套接字时只需要提供这个描述符即可。通过描述符,协议栈可以定位套接字,并获取所有的相关信息。

2. 建立连接

套接字创建完毕,接下来需要建立连接。

2.1 建立连接的目的

服务器和客户端能实现通信,物理上的网线肯定是连接好的,不需要每次访问都进行插拔网线的操作。那么这里的建立连接是指什么呢?

简而言之,这里建立连接的过程是通信双方交换控制信息,在套接字中记录这些信息并准备收发数据的一系列操作。

套接字刚刚创建完成时,套接字中没有通信对象的信息。在客户端一侧,协议栈不知道应该将信息发给谁。虽然应用程序知道通信对象的信息,如Web客户端知道要通信的服务器IP与端口号,但是在创建套接字的时候,这些信息并没有传递给协议栈,因此建立连接的目的之一就是将这些信息通知协议栈,协议栈将这些信息保存在套接字中。

而在服务器一侧,是创建好了套接字等待客户端一侧的连接。在连接建立之前,服务器端的应用程序和协议栈都不知道客户端通信对象的信息。因此建立连接的第二个目的是客户端向服务器传达开始通信的请求,传送自己的控制信息。

此外,还需要分配一块内存空间用于临时存放收发的数据,称为缓冲区。

2.2 控制信息

以上就是建立连接的目的。所说的控制信息具体包含哪些内容呢?

***控制信息可以分为两类。一类是客户端和服务器端相互通信需要交换的控制信息。***这类信息不仅在建立连接是需要,在后续收发数据以及断开连接的过程中也需要。这些内容在TCP协议的规格中进行了定义,如下表所示。这些字段是固定的,在每次客户端与服务器端进行通信时都需要提供,会被添加在二者之间传递的网络包的开头。由于位于网络包的开头,因此被称为头部。以太网协议与IP协议等也有自己的控制信息,也被称为头部,因此有以太网头部(MAC头部),IP头部,TCP头部等。
在这里插入图片描述
***另一类是保存在套接字中的控制信息。***这些控制信息与协议栈的实现有关,如在Windows系统和Linux系统中,协议栈的实现不同,套接字中保存的控制信息就有所不同。但只要根据协议将正确的信息写入了头部,就可以进行正常通信。

2.3 建立连接的实际过程

下面来看连接的实际过程。应用程序调用Socket库中的connect函数,调用connect函数时会传送套接字的描述符与服务器的IP地址、端口号,这些信息会传送给协议栈中的TCP模块。接下来TCP模块会与该IP地址对应的对象,即服务器端的TCP模块进行信息交换,这一过程包括以下几个步骤:

  1. 客户端创建一个包含表示开始数据收发操作的控制信息的头部,如上表所示。字段很多,主要关注发送方与接收方的端口号。这样客户端套接字就准确找到了服务器端的套接字,然后将头部信息中控制位的SYN比特设置为1,当前可以先理解为表示连接。此外还需要设置序号和窗口大小,会在稍后详细讲解。客户端TCP模块接下来委托IP模块将信息发送给服务器端。

  2. 在服务器端IP模块接收到信息之后,再传送给服务器端的TCP模块,服务器端的TCP模块会根据端口号找到对应的套接字,也就是在状态为等待连接的套接字中找到与接收信息中端口号一致的套接字。找到之后,这一套接字的状态会被修改为正在连接。完成后,服务器端的TCP模块会返回响应。与客户端操作一样,需要在TCP头部中设置发送发与接收方的端口号以及SYN比特。此外,还需要设置ACK比特。ACK比特用于互相确认信息是否送达,稍后也会进行详细介绍。

  3. 服务器端的信息返回到客户端,客户端通过TCP头部信息确认连接是否成功。如果SYN比特为1,则表示连接成功,此时会向套接字中写入服务器的IP地址与端口号,并将套接字的状态修改为连接完毕。最后,对于服务器端发来的信息,客户端也需要将ACK比特设置为1并返回服务器。服务器收到响应之后,连接操作才算全部完成了。

3. 收发数据

3.1 平衡发送时间与发送数据量

到此为止,连接建立,接下来就可以进行收发数据的操作了。

对于协议栈来说,应用程序委托其发送的数据只是二进制序列而已,并不关心其具体内容。而且协议栈并不会一收到数据就马上发送出去。如果协议栈一收到数据就马上发送出去,可能会发送大量的小包,导致网络的效率下降。一般会先存放在缓冲区中,积累到一定量时再发送出去。至于积累的量,不同的操作系统也会有所不同,主要考虑的要素有以下两个。

***首先是每个网络包所能容纳的数据长度。***MTU表示一个网络包的最大长度,在以太网中一般是1500字节,其中包含了头部。因此MTU减去头部的长度,得到的就是一个网络包所能容纳的最大数据长度MSS。当数据积累到接近或超出MSS时再进行发送,就可以避免发送大量小包的问题了。

第二个要素是时间。当应用程序发送数据的频率比较低的时候,如果每次都积累到MSS再发送,可能会因为等待时间过长而导致延迟。因此协议栈中有一个计时器,经过一定时间后也会将网络包发送出去。

这两个要素其实是互相矛盾的。如果长度有限,则网络效率得到提高,但可能因为等待填满缓冲区而产生延迟;相反如果时间优先,则延迟时间会变少,但网络效率又降低了。所以在实际发送过程中需要综合考虑这两个要素以达到平衡,因此不同的操作系统在实现上就存在一定的差异。

此外协议栈也给应用程序保留了控制发送的时机。像浏览器这种会话型的应用程序在向服务器发送数据时,延迟会产生很大影响,因此一般会使用直接发送的选项。

对于一次发送大量数据的情况下,缓冲区中的数据远远超出MSS的长度,这时候就需要将缓冲区中的数据以MSS为单位拆分成许多块,每一块加上TCP头部后就可以委托给IP模块进行发送了。

3.2 序号与ACK号

TCP协议的一项重要功能就是确认对方是否成功收到网络包。因此发送网络包之后,还需要进行确认操作。

首先,TCP模块在拆分数据时,会计算处每一块数据相当于从头开始的第几个字节,在发送时会将这个字节数写在TCP头部中,这就是“序号”字段。此外对方还可以通过网络包的长度减去头部的长度,计算得到发送数据的长度。

通过序号和长度,对方可以确认接收的数据有没有遗漏。如果上次接收到第1460字节,下一次接收从1461字节开始的包,则说明中间没有遗漏。如果确认没有遗漏,接收方会将到目前为止接收到的数据长度加起来,计算一共收到了多少字节,将这个字节数写入到TCP头部的ACK号来返回给发送方。这样发送方就可以确认接收方一共收到了多少数据。

原理如此,实际操作过程中还有些变化。由于序号从1开始很容易被预测和攻击,因此序号的初始值是一个随机数,发送方需要在数据收发开始之前将这个初始值告知通信对象。在连接过程中将SYN比特设置为1就是为了实现这一步骤的。在将SYN比特设置为1的同时,会将序号字段设置为初始值。

前面只考虑了单向的传输,反之亦然。客户端需要计算序号发送给服务器端,服务器端收到后会回复ACK号给客户端;服务器端也需要计算出一个序号发送给客户端,客户端收到后同样会回复ACK号给服务器端。如下图所示。TCP采用这样的方法确认对方是否收到了数据,在得到对方确认之前,发送过的包都会保存在发送缓冲区中。如果对方没有返回某些包对应的ACK号,那么就重新发送这些包。因为有了这一机制,在网络的其他部分也不需要对错误进行补救了。在网卡、集线器、路由器等部分,一旦检测到错误就直接丢弃相应的包。

当然,如果出现了服务器宕机等情况,无论重试多少次都不会收到响应,TCP在重试几次后会强制结束通信,并向应用程序报错。

在这里插入图片描述

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

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

相关文章

Windows 10、Office 2016/2019 和 PPTP 和 L2TP协议即将退役,企业应尽早做好准备

关心微软技术和产品的朋友一定对这个网站很熟悉:https://microsoftgraveyard.com/,这里静静的躺着很多微软技术和产品。近日,微软又在准备一场新的“告别仪式”了,这次是 Windows 10、Office 2016/2019 和一些老旧的协议与技术。让…

Apache Seata 新版本集成了 RocketMQ 事务消息

大家好,我是君哥。 Apache Seata 是一款高性能、简单易用的分布式事务中间件,它包含 AT、TCC、SAGA 和 XA 四种模式。 在最近发布的新版本中,Apache Seata 引入了 RocketMQ 中间件,并且跟 RocketMQ 的事务消息配合使用。今天我们…

Vue Router实现路由懒加载

为了提高页面的加载速度,我们可以使用Vue Router的路由懒加载功能。路由懒加载是什么呢,路由懒加载就是只有当访问某个路由的时候再加载其相应的页面。 官方文档地址https://router.vuejs.org/guide/advanced/lazy-loading.html 以前我写路由懒加载的时候…

详细教程:使用Grafana监控Mysql

什么是Grafana Grafana是一个跨平台的开源的度量分析和可视化工具,可以通过将采集的数据查询然后可视化的展 示,并及时通知。 下载Grafana 下载地址: https://grafana.com/grafana/download [rootgrafana ~]# wget https://dl.grafana.com/oss/relea…

qt QPushButton详解

QPushButton是Qt Widgets模块中的一个基本控件,用于提供可点击的按钮。它是用户界面中最为常见和常用的控件之一,通过点击按钮,用户可以触发特定的应用程序操作。 重要方法 QPushButton(const QIcon &icon, const QString &text, QWi…

【OpenAI】第五节(图像生成)利用 OpenAI 的 DALL·E 实现自动化图像生成:从文本到图像的完整教程

引言 OpenAI 推出的 DALLE 工具因其能够生成令人惊叹的艺术作品而备受瞩目。DALLE 不仅能够生成静态图像,还能根据用户的需求进行风格化处理,创造出独特的艺术作品。通过 OpenAI 的 API,你可以轻松将 DALLE 的强大功能集成到你的 Python 程序…

《分布式机器学习模式》:解锁分布式ML的实战宝典

在大数据和人工智能时代,机器学习已经成为推动技术进步的重要引擎。然而,随着数据量的爆炸性增长和模型复杂度的提升,单机环境下的机器学习已经难以满足实际需求。因此,将机器学习应用迁移到分布式系统上,成为了一个不…

Xcode16 编译运行YYCache iOS18 sqlite3_finalize 闪退问题解决方案

问题原因 升级Xcode 16 之后,真机运行APP,发现会有Crash,崩溃堆栈线上Crash 在 YYCache 之中。如下图所示 崩溃堆栈如下: * thread #1, queue com.apple.main-thread, stop reason signal SIGABRTframe #0: 0x00000001d9391…

免费开源Odoo软件如何实现电商仓库高效发货

世界排名第一的免费开源ERP软件Odoo,拥有非常强大的仓库管理WMS功能。本文以电商仓库发货管理为例,介绍电商订单的仓库发货作业的各种方法。电商订单仓库发货流程,通常分为三个步骤,即拣货、打包、发货。根据仓库日处理订单数量的…

九、pico+Unity交互开发——触碰抓取

一、VR交互的类型 Hover(悬停) 定义:发起交互的对象停留在可交互对象的交互区域。例如,当手触摸到物品表面(可交互区域)时,视为触发了Hover。 Grab(抓取) 概念&#xff…

京东笔试题

和谐敏感词 🔗 题目地址 🎉 模拟 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();String s scanner.next();String[] words new String[…

【毕业设计】基于SpringBoot的网上商城系统

前言 🔥本系统可以选作为毕业设计,运用了现在主流的SSM框架,采用Maven来帮助我们管理依赖,所选结构非常合适大学生所学的技术,非常合适作为大学的毕业设计,难以适中。 🔥采用技术:Sp…

C++:模板(2)

目录 非类型模板参数 模板的特化 概念 函数模板特化 类模板特化 全特化 偏特化 模板的分离编译 分离编译的概念 模板的分离编译 ​编辑 模板总结 非类型模板参数 模板参数分为类型形参与非类型形参。 类型形参:在模板参数列表中,跟在class…

HttpURLConnection构造请求体传文件

HttpURLConnection构造请求体传文件 在Java中,使用HttpURLConnection构造请求体传输文件,你需要做以下几步: 1、创建URL对象指向你想要请求的资源。 2、通过URL打开连接,转换为HttpURLConnection实例。 3、设置请求方法为POST。 …

GB/T28181-2022规范解读、应用场景和技术实现探究

GB/T28181-2022和GB/T28181-2016区别 GB/T28181-2022《公共安全视频监控联网系统信息传输、交换、控制技术要求》与 GB/T28181-2016 相比,主要有以下区别: 术语和定义方面: 术语删减:GB/T28181-2022 删除了 “联网系统信息”“数…

Win安装Redis

目录 1、下载 2、解压文件并修改名称 3、前台简单启动 4、将redis设置成服务后台启动 5、命令启停redis 6、配置文件设置 1、下载 【下载地址】 2、解压文件并修改名称 3、前台简单启动 redis-server.exe redis.windows.conf 4、将redis设置成服务后台启动 redis-server -…

pikachu靶场CSRF-post测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、抓包使用burp生成csrf脚本 四、源代码分析 五、结论 一、测试环境 1、系统环境 渗透机:本机(127.0.0.1) 靶 机:本机(127.0.0.1) 2、使用工具/软件 Burp sui…

老机MicroServer Gen8再玩 OCP万兆光口+IT直通

手上有一台放了很久的GEN8微型服务器,放了很多年,具体什么时候买的我居然已经记不清了 只记得开始装修的时候搬家出去就没用了,结果搬出去有了第1个孩子,孩子小的时候也没时间折腾,等孩子大一点的时候,又有…

【去哪儿-注册安全分析报告-缺少轨迹的滑动条】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…

RabbitMQ service is already present - only updating service parameters

Windows下卸载RabbitMQ之后,然后重新注册RabbitMQ服务的时候,报错以下信息: D:\software\rabbitmq-server-4.0.2\rabbitmq_server-4.0.2\sbin>D:\software\rabbitmq-server-4.0.2\rabbitmq_server-4.0.2\sbin\rabbitmq-service.bat install RabbitMQ service is already …