多路复用是怎么回事?

news2025/1/16 0:54:20
  • 《计算机组成原理》讲述的是如何去理解程序和计算。
  • 《操作系统》讲述的是如何去理解和架构应用程序。
  • 《计算机网络》讲述的是如何去理解今天的互联网。
    现在来看,“计算机网络”也许是一个过时的词汇,它讲的是怎么用计算实现通信。今天我们已经发展到了一个互联网、物联网的时代,社交网络、云的时代,再来看网络,意义已经发生转变。但这里面还是有很多经典的知识依旧在传承。比如说 TCP/IP 协议,问世后就逐渐成为占有统治地位的通信协议。虽然后面诞生出了许许多多的协议,但是我们仍然习惯性地把整个互联网的架构称为 TCP/IP 协议群,也叫作互联网协议群(Internet Protocol Suit)。

协议的分层

对于多数的应用和用户而言,使用互联网的一个基本要求就是数据可以无损地到达。用户通过应用进行网络通信,应用启动之后就变成了进程。因此,所有网络通信的本质目标就是进程间通信。世界上有很多进程需要通信,我们要找到一种通用的,每个进程都能认可和接受的通信方式,这就是协议。

应用层

从分层架构上看,应用工作在应用层(Application Layer)。应用的功能,都在应用层实现。所以应用层很好理解,说的就是应用本身。当两个应用需要通信的时候,应用(进程中的线程)就调用传输层进行通信。从架构上说,应用层只专注于为用户提供价值即可,没有必要思考数据如何传输。而且应用的开发商和传输库的提供方也不是一个团队。
在这里插入图片描述

传输层

为应用层提供网络支持的,就是传输层(Transport Layer)。传输层控制协议(Transmission Control Protocol)是目前世界上应用最广泛的传输层协议。传输层为应用提供通信能力。比如浏览器想访问服务器,浏览器程序就会调用传输层程序;Web 服务接收浏览器的请求,Web 服务程序就会调用传输层程序接收数据。考虑到应用需要传输的数据可能会非常大,直接传输不好控制。传输层需要将数据切块,即使一个分块传丢了、损坏了,可以重新发一个分块,而不用重新发送整体。在 TCP 协议中,我们把每个分块称为一个 TCP 段(TCP Segment)。
在这里插入图片描述
传输层负责帮助应用传输数据给应用。考虑到一台主机上可能有很多个应用在传输数据,而一台服务器上可能有很多个应用在接收数据。因此,我们需要一个编号将应用区分开。这个编号就是端口号。比如 80 端口通常是 Web 服务器在使用;22 端口通常是远程登录服务在使用。而桌面浏览器,可能每个打开的标签栏都是一个独立的进程,每个标签栏都会使用临时分配的端口号。TCP 封包(TCP Segment)上携带了端口号,接收方可以识别出封包发送给哪个应用。

网络层

接下来你要思考的问题是:传输层到底负不负责将数据从一个设备传输到另一个设备(主机到主机,Host To Host)。仔细思考这个过程,你会发现如果这样设计,传输层就会违反简单、高效、专注的设计原则。我们从一个主机到另一个主机传输数据的网络环境是非常复杂的。中间会通过各种各样的线路,有形形色色的交叉路口——有各式各样的路径和节点需要选择。核心的设计原则是,我们不希望一层协议处理太多的问题。传输层作为应用间数据传输的媒介,服务好应用即可。对应用层而言,传输层帮助实现应用到应用的通信。而实际的传输功能交给传输层的下一层,也就是网络层(Internet Layer) 会更好一些。
在这里插入图片描述
IP 协议(Internet Protocol)是目前起到统治地位的网络层协议。IP 协议会将传输层的封包再次切分,得到 IP 封包。网络层负责实际将数据从一台主机传输到另一台主机(Host ToHost),因此网络层需要区分主机的编号。在互联网上,我们用 IP 地址给主机进行编号。例如 IPv4 协议,将地址总共分成了四段,每段是 8 位,加起来是 32 位。寻找地址的过程类似我们从国家、城市、省份一直找到区县。当然还有特例,比如有的城市是直辖市,有的省份是一个特别行政区。而且国与国体制还不同,像美国这样的国家,一个州其实可以相当于一个国家。IP 协议里也有这个问题,类似行政区域划分,IP 协议中具体如何划分子网,需要配合子网掩码才能够明确。每一级网络都需要一个子网掩码,来定义网络子网的性质,相当于告诉物流公司到这一级网络该如何寻找目标地址,也就是寻址(Addressing)。
除了寻址(Addressing),IP 协议还有一个非常重要的能力就是路由。在实际传输过程当中,数据并不是从主机直接就传输到了主机。而是会经过网关、基站、防火墙、路由器、交换机、代理服务器等众多的设备。而网络的路径,也称作链路,和现实生活中道路非常相似,会有岔路口、转盘、高速路、立交桥等。因此,当封包到达一个节点,需要通过算法决定下一步走哪条路径。我们在现实生活中经常会碰到多条路径都可以到达同一个目的地的情况,在网络中也是如此。总结一下。寻址告诉我们去往下一个目的地该朝哪个方向走,路由则是根据下一个目的地选择路径。寻址更像在导航,路由更像在操作方向盘。

数据链路层(Data Link Layer)

考虑到现实的情况,网络并不是一个完整的统一体。比如一个基站覆盖的周边就会形成一个网络。一个家庭的所有设备,一个公司的所有设备也会形成一个网络。所以在现实的情况中,数据在网络中设备间或者跨网络进行传输。而数据一旦需要跨网络传输,就需要有一个设备同时在两个网络当中。通过路由,我们知道了下一个要去的 IP 地址,可是当前的网络中哪个设备对应这个 IP 地址呢?为了解决这个问题,我们需要有一个专门的层去识别网络中的设备,让数据在一个链路(网络中的路径)中传递,这就是数据链路层(Data Link Layer)。数据链路层为网络层提供链路级别传输的支持。

物理层

当数据在实际的设备间传递时,可能会用电线、电缆、光纤、卫星、无线等各种通信手段。因
此,还需要一层将光电信号、设备差异封装起来,为数据链路层提供二进制传输的服务。这就
是物理层(Physical Layer)。因此,从下图中你可以看到,由上到下,互联网协议可以分成五层,分别是应用层、传输层、网络层、数据链路层和物理层。

多路复用

在上述的分层模型当中,一台机器上的应用可以有很多。但是实际的出口设备,比如说网卡、网线通常只有一份。因此这里需要用到一个叫作多路复用(Multiplex)的技术。多路复用,就是多个信号,复用一个信道。

传输层多路复用

对应用而言,应用层抽象应用之间通信的模型——比如说请求返回模型。一个应用可能会同时向服务器发送多个请求。因为建立一个连接也是需要开销的,所以可以多个请求复用一个 TCP连接。复用连接一方面可以节省流量,另一方面能够降低延迟。如果应用串行地向服务端发送请求,那么假设第一个请求体积较大,或者第一个请求发生了故障,就会阻塞后面的请求。而使用多路复用技术,如下图所示,多个请求相当于并行的发送请求。即使其中某个请求发生故障,也不会阻塞其他请求。从这个角度看,多路复用实际上是一种 Non-Blocking(非阻塞)的技术。我们再来看下面这张图,不同的请求被传输层切片,我用不同的颜色区分出来,如果其中一个数据段(TCP Segment)发生异常,只影响其中一个颜色的请求,其他请求仍然可以到达服务。
在这里插入图片描述

网络层多路复用

传输层是一个虚拟的概念,但是网络层是实实在在的。两个应用之间的传输,可以建立无穷多个传输层连接,前提是你的资源足够。但是两个应用之间的线路、设备,需要跨越的网络往往是固定的。在我们的互联网上,每时每刻都有大量的应用在互发消息。而这些应用要复用同样的基础建设——网线、路由器、网关、基站等。网络层没有连接这个概念。你可以把网络层理解成是一个巨大的物流公司。不断从传输层接收数据,然后进行打包,每一个包是一个 IP 封包。然后这个物流公司,负责 IP 封包的收发。所以,是很多很多的传输层在共用底下同一个网络层,这就是网络层的多路复用。总结一下。应用层的多路复用,如多个请求使用同一个信道并行的传输,实际上是传输层提供的多路复用能力。传输层的多路复用,比如多个 TCP 连接复用一条线路,实际上是网络层在提供多路复用能力。你可以把网络层想象成一个不断收发包裹的机器,在网络层中并没有连接这个概念,所以网络层天然就是支持多路复用的。

多路复用的意义

在工作当中,我们经常会使用到多路复用的能力。多路复用让多个信号(例如:请求/返回等)共用一个信道(例如:一个 TCP 连接),那么在这个信道上,信息密度就会增加。在密度增加的同时,通过并行发送信号的方式,可以减少阻塞。比如说应用层的 HTTP 协议,浏览器打开的时候就会往服务器发送很多个请求,多个请求混合在一起,复用相同连接,数据紧密且互相隔离(不互相阻塞)。同理,服务之间的远程调用、消息队列,这些也经常需要多路复用。
下面是一个简单的基于nio的多路复用代码示例:

import java.nio.channels.*;
import java.util.*;

public class NioServer {
    private Selector selector;
    private ByteBuffer buffer = ByteBuffer.allocate(1024);

    public void start() throws Exception {
        // 创建一个Selector
        selector = Selector.open();

        // 创建一个ServerSocketChannel并绑定到本地端口
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress("localhost", 8888));

        // 将ServerSocketChannel注册到Selector上并设置为接收连接请求
        serverSocketChannel.configureBlocking(false);
        SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 循环等待连接
        while (true) {
            // 阻塞直到有一个通道准备好了I/O操作
            selector.select();

            // 获取已经准备好了I/O操作的通道的SelectionKey集合
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectedKeys.iterator();

            // 遍历SelectionKey集合处理I/O操作
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();

                // 如果是接收连接请求
                if (key.isAcceptable()) {
                    // 接收连接并将新创建的SocketChannel注册到Selector上并设置为读取数据
                    ServerSocketChannel serverSocket = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = serverSocket.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }

                // 如果是读取数据请求并有数据可读
                if (key.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();

                    // 读取数据
                    buffer.clear();
                    int numRead = socketChannel.read(buffer);

                    if (numRead == -1) {
                        // 连接关闭
                        key.cancel();
                        socketChannel.close();
                    } else {
                        // 处理数据
                        buffer.flip();
                        byte[] bytes = new byte[numRead];
                        buffer.get(bytes);
                        String message = new String(bytes, "UTF-8");
                        System.out.println("Received message: " + message);
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        new NioServer().start();
    }
}

上述代码实现了一个简单的Server,通过NIO的Selector实现了多路复用,能够同时处理多个连接的I/O操作。具体过程如下:

  • 创建Selector,并将ServerSocketChannel注册到Selector上并设置为接收连接请求。
  • 进入循环,阻塞等待有通道准备好了I/O操作。
  • 获取已经准备好了I/O操作的通道的SelectionKey集合。
  • 遍历SelectionKey集合处理I/O操作。
  • 如果是接收连接请求,接收连接并将新创建的SocketChannel注册到Selector上并设置为读取数据。
  • 如果是读取数据请求并有数据可读,读取数据并处理数据。

总结

多路复用是怎么回事?
1.
提升吞吐量。多一个信号被紧密编排在一起(例如:TCP 多路复用节省了多次连接的数
据),这样网络不容易空载。
2.
多个信号间隔离。信号间并行传输,并且隔离,不会互相影响。

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

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

相关文章

HTTPS(面试高频必须掌握)

目录 一、HTTPS背景 二、HTTPS 的工作过程 1. 对称加密 2.非对称加密 3. HTTPS 基本工作过程 3.1 使用对称密钥 3.2 引入非对称密钥&#xff08;面试高频问题&#xff09; 3.3 黑客的手段 3.4 引入证书 3.5 捋一捋 3.6 SSL/TLS 三、HTTP 与 HTTPS 区别&#xff08;…

强化学习的应用领域和案例

你好&#xff0c;我是zhenguo(郭震) 今天总结强化学习第四篇&#xff1a;强化学习的应用领域 第一&#xff1a;游戏领域。 强化学习在游戏领域有很多应用&#xff0c;如围棋、象棋、扑克等游戏的AI对战。 例如&#xff0c;AlphaGo使用强化学习技术&#xff0c;在围棋比赛中击败…

要做存储业务,我解析了一个项目的源码

最近在做存储相关的业务&#xff0c;更具体的来说是存储相关的研发&#xff0c;于是就上网查了一下相关的资料&#xff0c;思虑再三打算从最简单的 Json 数据交换格式开始研究。 JSON是独立于编程语言的数据交换格式&#xff0c;几乎所有与网络开发相关的语言都有JSON函数库&am…

chatgpt赋能Python-python_figsize

Python figsize&#xff1a;图形大小的更改 在Python数据可视化中&#xff0c;通过更改图形的大小可以使得图形更易于阅读和理解。绘图函数的“figsize”参数可以让您控制图形的大小。本文将探讨figsize的含义、使用示例以及如何根据您的需要精确调整图形大小。 什么是figsiz…

【CSAPP】虚拟内存(VM)

&#x1f4ad; 写在前面&#xff1a;本文将学习《深入理解计算机系统》虚拟内存部分&#xff0c;CSAPP 是计算机科学经典教材《Computer Systems: A Programmers Perspective》的缩写&#xff0c;该教材由Randal E. Bryant和David R. OHallaron 合著。 &#x1f4dc; 本章目录…

【Python】判断语句 ④ ( 判断语句嵌套 )

文章目录 一、判断语句嵌套1、语法说明2、代码示例 一、判断语句嵌套 1、语法说明 在 Python 的开发场景中 , 除了 单个条件判定 : if 条件判定 , if else 条件判定 ;多个并列条件判定 : if elif else 条件判定 ; 之外 , 还有 满足 前置条件判定 后 进行 第二次条件判定 的开…

C#,码海拾贝(21)——线性方程组求解的全选主元高斯消去法之C#源代码,《C#数值计算算法编程》源代码升级改进版

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static class LEquations { /// <summary> /…

chatgpt赋能Python-python_geany

了解Python Geany: 一种强大且高效的Python IDE 介绍 Python Geany是一种非常流行的Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;是由Geany团队开发的。它是一种跨平台的开发工具&#xff0c;可在Windows、Linux和macOS等不同平台上运行。Python Geany提供了支…

Linux常用命令——host命令

在线Linux命令查询工具 host 常用的分析域名查询工具 补充说明 host命令是常用的分析域名查询工具&#xff0c;可以用来测试域名系统工作是否正常。 语法 host(选项)(参数)选项 -a&#xff1a;显示详细的DNS信息&#xff1b; -c<类型>&#xff1a;指定查询类型&am…

小白畅玩免费支持ChatGPT3和4,一键定制自己专属AI

AI爆炸时代。你不用AI&#xff0c;别人就会用AI,当别人用AI,为自己给工作生活赋能时候。生活自在&#xff0c;工作高效&#xff0c;AI正在潜移默化改变我们生活 基于OPEN AI平台 轻松让AI 为你的生活赋能. 总之我现在生活已经离不开AI&#xff0c;帮助了。 不管是工作上问题…

第四范式涂威威:企业专属大模型技术需闭环数据、思维链学习、高落地效率...

‍ 近日&#xff0c;以“智行天下 能动未来”为主题的第七届世界智能大会隆重举办&#xff0c;第四范式副总裁、主任科学家涂威威出席高峰会&#xff0c;与中国工程院院士邬江兴、德国弗劳恩霍夫电子纳米系统研究所所长Harald Kuhn、高通公司中国区董事长孟樸等院士及企业代表&…

chatgpt赋能Python-python_for_in遍历列表

Python for-in循环遍历列表&#xff1a;最简单易用的方法 Python是最流行的编程语言之一&#xff0c;也是许多开发人员的首选工具。其中&#xff0c;for循环是Python最重要的控制结构之一&#xff0c; for-in循环是其中最常用的形式之一。在本文章中&#xff0c;我们将重点介绍…

做流量卡代理,看看人家是怎么赚钱的?

这两年来&#xff0c;流量卡市场可谓是一片欣欣向荣&#xff0c;三大运营商也推出了多款热门套餐。 ​ 作为上网的主要方式&#xff0c;流量卡在这两年可谓是“风光无限”&#xff0c;上至60岁老人&#xff0c;下至16岁的学生都在使用&#xff0c;就连小编的亲戚朋友也都在网上…

chatgpt赋能Python-python_gi

Python-GI: 一个强大的Python库 Python-GI是一个用于Python的开源库&#xff0c;它提供了一个统一的接口来访问底层的系统库。这个库的目的是方便Python开发人员使用底层操作系统或系统库的底层功能。Python-GI是GNOME桌面环境的一部分&#xff0c;它为Python开发人员提供了访…

因果

数字化转型已经喊了很多年了&#xff0c;但是很多人仍然不明白数字化转型是怎么回事&#xff0c;为啥要转。很多人甚至以为数字化转型就是个营销噱头&#xff0c;还有人跟着瞎起哄什么互联网红利消失、中国供给侧和消费侧人口红利消失等等。 我不讲&#xff0c;很多人都不知道。…

字节跳动开源其云原生数据仓库 ByConity

动手点关注 干货不迷路 ‍ ‍项目简介 ByConity 是字节跳动开源的云原生数据仓库&#xff0c;它采用计算-存储分离的架构&#xff0c;支持多个关键功能特性&#xff0c;如计算存储分离、弹性扩缩容、租户资源隔离和数据读写的强一致性等。通过利用主流的 OLAP 引擎优化&#xf…

吴恩达 x OpenAI Prompt Engineering教程中文笔记

Datawhale干货 作者&#xff1a;刘俊君&#xff0c;Datawhale成员 完整课程&#xff1a;《吴恩达ChatGPT最新课程》 &#x1f433;Reasons & Importance Important for research, discoveries, and advancement 对研究、发现和进步很重要 Accelerate the scientific resea…

案例15:Java餐厅外卖管理系统设计与实现开题报告

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

一步步教你安装RabbitMQ Server在Ubuntu上,并让其支持远程访问!

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 转载自cpolar内网穿透的文章&#xff1a;无公网IP&…

针对自主泊车的多相机视觉惯导同时定位与建图方案

文章&#xff1a;Multi-Camera Visual-Inertial Simultaneous Localization and Mapping for Autonomous Valet Parking 作者&#xff1a;Marcus Abate, Ariel Schwartz, Xue Iuan Wong, Wangdong Luo, Rotem Littman, Marc Klinger, Lars Kuhnert, Douglas Blue, Luca Carlone…