音视频学习(三十六):websocket协议总结

概述

项目描述
标准RFC 6455
使用端口默认 80(ws),443(wss)
基于协议TCP
特性全双工、低开销、持久连接、可穿透代理

特点

  • 全双工通信: WebSocket 允许客户端和服务器之间建立一个持久的连接,并且数据可以在两个方向上同时传输。这与传统的 HTTP 请求-响应模型不同,HTTP 每次通信都需要建立新的连接,效率较低。
  • 低延迟: 由于连接是持久的,避免了重复建立连接的开销,WebSocket 在实时通信场景下具有显著的低延迟优势。
  • 兼容性: WebSocket 通过 HTTP 握手进行升级,因此可以在标准的 HTTP 端口(80 和 443)上工作,并兼容 HTTP 代理和中间件,这使得它在 Web 环境中具有良好的兼容性。
  • 轻量级协议: 相较于 HTTP,WebSocket 协议头更小,传输数据时的开销更低。

工作原理

1. 建立连接(握手阶段)

WebSocket 连接的建立使用 HTTP 协议进行握手,然后升级为 WebSocket 协议。

请求(客户端 → 服务端):

GET /chat HTTP/1.1
Host: example.com:80
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13

响应(服务端 → 客户端):

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

Sec-WebSocket-Accept 是服务端基于客户端的 Sec-WebSocket-Key 和魔法字符串计算得到的 SHA1 后 Base64 值,用于验证合法性。

关键字段说明:

字段说明
Upgrade: websocket请求升级为 WebSocket
Connection: Upgrade必须和 Upgrade 一起使用
Sec-WebSocket-Key客户端生成的随机值,用于服务端验证
Sec-WebSocket-Version当前协议版本,一般为 13

2. 数据传输阶段

握手成功后,TCP 连接升级为 WebSocket,开始使用 WebSocket 帧格式传输数据:

WebSocket 数据帧格式:

字段说明
FIN是否为消息最后一帧
RSV1-3一般为 0
Opcode操作码(0x1=文本,0x2=二进制,0x8=关闭,0x9=ping,0xA=pong)
MASK是否有掩码(客户端必须是1)
Payload length数据长度(<=125,126, 127为扩展)
Masking-key客户端发送时存在,用于解码 Payload
Payload data真实数据

数据帧

结构

  0                   1                   2                   30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-------+-+-------------+-------------------------------+|F|R|R|R| opcode|M| Payload len |    Extended payload length    ||I|S|S|S|  (4)  |A|     (7)     |             (16/64)           ||N|V|V|V|       |S|             |   (if payload len==126/127)   || |1|2|3|       |K|             |                               |+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +|     Extended payload length continued, if payload len == 127  |+ - - - - - - - - - - - - - - - +-------------------------------+|                               |Masking-key, if MASK set to 1  |+-------------------------------+-------------------------------+| Masking-key (continued)       |          Payload Data         |+-------------------------------- - - - - - - - - - - - - - - - +:                     Payload Data continued ...                :+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +|                     Payload Data continued ...                |+---------------------------------------------------------------+

字段说明

字段位数说明
FIN1 bit是否为消息最后一帧(1 = 最后一帧)
RSV1-33 bits通常为 0,扩展协议用
Opcode4 bits帧类型,如文本、二进制、ping、pong、关闭等
MASK1 bit是否有掩码(客户端必须为 1,服务端必须为 0)
Payload Length7 bits数据长度: 0-125 表示实际长度 126 表示后跟 16 位扩展长度 127 表示后跟 64 位扩展长度
Extended Payload Length可选当 Payload Length 为 126 或 127 时出现
Masking Key32 bits客户端发出时必须有,用于解码 Payload
Payload Data可变实际的数据内容,若有掩码则是经过掩码异或的

Opcode

Opcode (4 bits)含义
0x0continuation(延续帧)
0x1text(文本帧,UTF-8 编码)
0x2binary(二进制帧)
0x8close(关闭连接)
0x9ping(心跳请求)
0xApong(心跳响应)

Payload 长度表示规则

Payload Len描述
0 ~ 125长度就是值本身
126后接 2 字节 扩展长度(16 位)
127后接 8 字节 扩展长度(64 位)

掩码(Masking)

  • 客户端必须使用掩码,服务端不能。
  • Masking key 为 4 字节,掩码算法:
decoded_data[i] = encoded_data[i] XOR masking_key[i % 4]

websocket安全连接(WSS)

握手流程

Client (Browser / App)|| 1. 建立 TCP 连接到 wss://host:443|| 2. 启动 TLS 握手  ⇨(证书验证、密钥协商)|| 3. TLS 握手成功,进入加密通道|| 4. 发送 WebSocket Upgrade 请求(加密的 HTTP 请求)|    GET /chat HTTP/1.1|    Host: example.com|    Upgrade: websocket|    Connection: Upgrade|    Sec-WebSocket-Key: xxxxx==|    ...|| 5. 服务器返回 101 Switching Protocols 响应|    + Sec-WebSocket-Accept 校验|| 6. 握手完成,开始加密的数据帧传输(Frame)

关键步骤

TCP + TLS 握手

  • 使用标准的 HTTPS 流程建立 TLS 连接
  • 客户端会校验证书(支持 SNI、可校验 SAN 域名);
  • TLS 会协商对称加密算法、握手密钥、会话密钥;
  • 完成后进入 加密通信通道

发送加密的 HTTP WebSocket 升级请求

  • 浏览器或客户端发送 Upgrade: websocket 的请求;
  • 这实际上是一个 加密的 HTTP 请求,例如:
GET /ws HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

服务器响应并完成握手

  • 服务器返回 HTTP 101 状态码,表示协议切换成功:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Accept 是服务器根据客户端的 key 生成的 SHA1+Base64 值,防止伪造连接。

安全特性

特性描述
加密通信所有 WebSocket 帧通过 TLS 加密传输
证书认证可使用 CA 证书,防止 MITM 攻击
与 HTTPS 共端口可与 HTTPS 共用 443 端口,适合反向代理
防止劫持中间人无法篡改握手数据和帧内容
支持 HSTS / CSP 等浏览器安全机制

websocket示例

ws

客户端

// WsClient.h
#pragma once#include <uwebsockets/App.h>
#include <iostream>
#include <string>
#include <functional>class WsClient {
public:using OnMessageHandler = std::function<void(const std::string_view&)>;using OnOpenHandler = std::function<void()>;using OnCloseHandler = std::function<void()>;WsClient(const std::string& url): url_(url) {}void setOnOpen(OnOpenHandler handler) { onOpen_ = handler; }void setOnMessage(OnMessageHandler handler) { onMessage_ = handler; }void setOnClose(OnCloseHandler handler) { onClose_ = handler; }void run() {uWS::App().connect(url_, {}, {.open = [this](auto *ws) {ws_ = ws;if (onOpen_) onOpen_();},.message = [this](auto * /*ws*/, std::string_view msg, uWS::OpCode /*opCode*/) {if (onMessage_) onMessage_(msg);},.close = [this](auto * /*ws*/, int /*code*/, std::string_view /*msg*/) {if (onClose_) onClose_();},.error = [this](auto * /*ws*/, std::error_code ec) {std::cerr << "Connection error: " << ec.message() << std::endl;}}).run();}void send(const std::string& message) {if (ws_) {ws_->send(message, uWS::OpCode::TEXT);}}void close() {if (ws_) {ws_->close();}}private:std::string url_;uWS::WebSocket<false, true>* ws_ = nullptr;OnOpenHandler onOpen_;OnMessageHandler onMessage_;OnCloseHandler onClose_;
};

服务端

// WsServer.h
#pragma once#include <uwebsockets/App.h>
#include <iostream>
#include <functional>
#include <string_view>class WsServer {
public:using OnMessageHandler = std::function<void(const std::string_view&, uWS::WebSocket<false, true>*)>;using OnOpenHandler = std::function<void(uWS::WebSocket<false, true>*)>;using OnCloseHandler = std::function<void(uWS::WebSocket<false, true>*)>;WsServer(int port): port_(port) {}void setOnOpen(OnOpenHandler handler) { onOpen_ = handler; }void setOnMessage(OnMessageHandler handler) { onMessage_ = handler; }void setOnClose(OnCloseHandler handler) { onClose_ = handler; }void run() {uWS::App().ws<false>("/*", {.open = [this](auto *ws) {if (onOpen_) onOpen_(ws);},.message = [this](auto *ws, std::string_view msg, uWS::OpCode opCode) {if (onMessage_) onMessage_(msg, ws);},.close = [this](auto *ws, int /*code*/, std::string_view /*msg*/) {if (onClose_) onClose_(ws);}}).listen(port_, [this](auto *listen_socket) {if (listen_socket) {std::cout << "WsServer listening on port " << port_ << std::endl;} else {std::cerr << "Failed to listen on port " << port_ << std::endl;}}).run();}private:int port_;OnOpenHandler onOpen_;OnMessageHandler onMessage_;OnCloseHandler onClose_;
};

wss

客户端

#pragma once#include <uwebsockets/App.h>
#include <iostream>
#include <string>
#include <functional>class WsClientTLS {
public:using OnMessageHandler = std::function<void(const std::string_view&)>;using OnOpenHandler = std::function<void()>;using OnCloseHandler = std::function<void()>;WsClientTLS(const std::string& url): url_(url) {}void setOnOpen(OnOpenHandler handler) { onOpen_ = handler; }void setOnMessage(OnMessageHandler handler) { onMessage_ = handler; }void setOnClose(OnCloseHandler handler) { onClose_ = handler; }void run() {uWS::App().connect(url_, {}, {.open = [this](auto *ws) {ws_ = ws;if (onOpen_) onOpen_();},.message = [this](auto * /*ws*/, std::string_view msg, uWS::OpCode /*opCode*/) {if (onMessage_) onMessage_(msg);},.close = [this](auto * /*ws*/, int /*code*/, std::string_view /*msg*/) {if (onClose_) onClose_();},.error = [this](auto * /*ws*/, std::error_code ec) {std::cerr << "Connection error: " << ec.message() << std::endl;}}).run();}void send(const std::string& message) {if (ws_) {ws_->send(message, uWS::OpCode::TEXT);}}void close() {if (ws_) {ws_->close();}}private:std::string url_;uWS::WebSocket<true, true>* ws_ = nullptr;OnOpenHandler onOpen_;OnMessageHandler onMessage_;OnCloseHandler onClose_;
};

服务端

#pragma once#include <uwebsockets/App.h>
#include <iostream>
#include <functional>
#include <string_view>class WsServerTLS {
public:using OnMessageHandler = std::function<void(const std::string_view&, uWS::WebSocket<true, true>*)>;using OnOpenHandler = std::function<void(uWS::WebSocket<true, true>*)>;using OnCloseHandler = std::function<void(uWS::WebSocket<true, true>*)>;WsServerTLS(int port, const std::string& certFile, const std::string& keyFile): port_(port), certFile_(certFile), keyFile_(keyFile) {}void setOnOpen(OnOpenHandler handler) { onOpen_ = handler; }void setOnMessage(OnMessageHandler handler) { onMessage_ = handler; }void setOnClose(OnCloseHandler handler) { onClose_ = handler; }void run() {uWS::App().sslContextOptions(SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 // 禁用旧协议).ws<true>("/*", {.open = [this](auto *ws) {if (onOpen_) onOpen_(ws);},.message = [this](auto *ws, std::string_view msg, uWS::OpCode opCode) {if (onMessage_) onMessage_(msg, ws);},.close = [this](auto *ws, int /*code*/, std::string_view /*msg*/) {if (onClose_) onClose_(ws);}}).listen(port_, uWS::SocketOptions {.cert_file_name = certFile_.c_str(),.key_file_name = keyFile_.c_str()}, [this](auto *listen_socket) {if (listen_socket) {std::cout << "TLS WsServer listening on port " << port_ << std::endl;} else {std::cerr << "Failed to listen on port " << port_ << std::endl;}}).run();}private:int port_;std::string certFile_;std::string keyFile_;OnOpenHandler onOpen_;OnMessageHandler onMessage_;OnCloseHandler onClose_;
};

websocket-flv

FLV (Flash Video) 是一种流媒体封装格式,主要用于在 Adobe Flash Player 中播放视频。虽然 Flash 已经逐渐被淘汰,但 FLV 格式因其 简单、易于解析 的特点,仍在一些直播场景中被广泛使用,尤其是在基于 WebSocket 的实时传输中。

工作原理

当通过 WebSocket 传输 FLV 数据时,通常的工作流程如下:

  1. 服务器生成 FLV 数据流: 媒体服务器(如 Nginx-RTMP-Module, SRS 等)接收到原始音视频流(例如 RTMP 推流),将其实时封装成 FLV 格式。
  2. WebSocket 连接建立: 客户端(通常是 Web 浏览器中的 JavaScript 播放器)通过 WebSocket 握手与服务器建立连接。
  3. FLV 数据通过 WebSocket 推送: 服务器将实时生成的 FLV 数据(包括 FLV 头、Metadata 和音视频 Tag)通过已建立的 WebSocket 连接持续地推送到客户端。
  4. 客户端解析和播放: 客户端的 JavaScript 播放器(例如 flv.js)接收到 FLV 数据后,解析其中的音视频 Tag,并利用 Media Source Extensions (MSE) API 将音视频数据喂给 HTML <video> 标签进行播放。

优缺点

优点

  • 实现简单: FLV 格式本身相对简单,解析起来比较容易,因此基于 WebSocket-FLV 的实现相对直观。
  • 低延迟: 结合 WebSocket 的实时性,WebSocket-FLV 可以实现较低的直播延迟。
  • 兼容性: 对于支持 MSE 的现代浏览器,flv.js 等库可以很好地支持 FLV 播放。

缺点

  • Flash 遗产: FLV 格式与 Flash 关联较深,虽然现在通过 MSE 可以在浏览器中播放,但其“出身”仍然让一些开发者对其现代化程度有所疑虑。
  • 移动端原生支持欠佳: 对于 iOS 等移动端原生应用,通常不支持直接播放 FLV,需要进行转码或使用第三方播放器。

websocket-fmp4

fMP4 (fragmented MP4),即 分段 MP4,是一种将 MP4 文件分割成小段(fragments)的格式。每个分段都包含独立的音视频数据,并且可以独立解码和播放。这种分段特性使其非常适合流媒体传输,尤其是对于 HTTP Live Streaming (HLS)MPEG-DASH 这样的自适应流媒体技术。

当与 WebSocket 结合时,WebSocket-fMP4 意味着通过 WebSocket 连接传输分段的 MP4 数据。

工作原理

WebSocket-fMP4 的工作流程与 WebSocket-FLV 有些相似,但关键在于数据封装格式的不同:

  1. 服务器生成 fMP4 数据: 媒体服务器将原始音视频流实时转码并封装成 fMP4 格式。这通常涉及到生成 初始化片段 (Initialization Segment)(包含音视频轨道的元数据,如编码信息、时间尺度等)和后续的 媒体片段 (Media Segments)(包含实际的音视频数据)。
  2. WebSocket 连接建立: 客户端通过 WebSocket 握手与服务器建立连接。
  3. fMP4 数据通过 WebSocket 推送: 服务器首先发送初始化片段,然后持续地将实时生成的媒体片段通过 WebSocket 连接推送到客户端。
  4. 客户端解析和播放: 客户端的 JavaScript 播放器(如基于 MSE 的自定义播放器或 shaka-player, hls.js 等)接收到 fMP4 数据后,将初始化片段和媒体片段依次添加到 Media Source Buffer 中,由浏览器进行解码和播放。

优缺点

优点

  • 标准和通用性: fMP4 是 ISO 标准,与 MPEG-DASH 和 HLS 等主流流媒体协议兼容,因此具有更好的通用性和未来发展潜力。
  • 更好的兼容性: 现代浏览器通过 Media Source Extensions (MSE) 对 fMP4 有原生支持,可以实现更高效的硬件解码和播放。
  • 自适应码率流 (ABR) 潜力: fMP4 的分段特性使其更容易实现自适应码率切换,根据网络状况动态调整视频质量。尽管 WebSocket 本身不直接提供 ABR 机制,但基于 fMP4 的数据流可以为上层应用实现 ABR 提供基础。
  • Seek(快进/快退)支持: fMP4 的分段结构使得在流媒体中进行快进/快退操作更加容易和高效。

缺点

  • 实现复杂性: 相对于 FLV,fMP4 格式的封装更为复杂,涉及到 Box 结构、时间戳、序列号等,因此服务器端和客户端的实现会更复杂。
  • 初始延迟: 由于需要先传输初始化片段,可能会有微小的初始延迟。

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

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

相关文章

docker版本nacos的搭建

1.下载镜像2.拷贝出容器中对应的配置文件&#xff0c;logs&#xff0c;data&#xff0c;conf3.编写yaml配置文件version: 3.8 services:nacos-server:image: nacos/nacos-server:v2.4.0container_name: nacos-serverrestart: unless-stoppedports:- "8848:8848" # …

【机器学习深度学习】 如何解决“宏平均偏低 / 小类识别差”的问题?

目录 &#x1f9e9; 场景 一、先问清楚&#xff1a;小类差&#xff0c;到底差在哪&#xff1f; 二、对症下药&#xff1a;六大优化策略&#xff08;分类任务专用&#xff09; ✅ 1. 处理类别不平衡&#xff08;最常见&#xff09; ✅ 2. 优化数据质量 ✅ 3. 更强的模型结…

数据结构 --- 栈

栈 --- stack前言一、栈结构二、相关方法1.初始化2.入栈3.出栈4.判空5.获取栈顶元素6.获取栈大小7.销毁前言 栈是一个特殊的线性表&#xff0c;遵循一个先进后出的特性&#xff0c;即操作数据&#xff08;入栈&#xff0c;出栈&#xff09;只能从栈顶操作&#xff0c;栈底是一…

【uniapp】---- 在 HBuilderX 中使用 tailwindcss

1. 前言 接手了一个uniapp的微信小程序项目,因为在上一个 taro 的项目中使用的 tailwindcss,感觉比较方便,又不想动项目中原来的代码,因此就配置 tailwindcss,在新创建的子包中使用。 2. 分析 vue2 版本的 uni-app 内置的 webpack 版本为 4 , postcss 版本为 7, 所以还是…

Spring Boot + Easy Excel 自定义复杂样式导入导出

tips&#xff1a;能用模板就用模板&#xff0c;当模板不适用的情况下&#xff0c;再选择自定义生成 Excel。官网&#xff1a;https://easyexcel.opensource.alibaba.com安装<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</arti…

Spark从入门到实战:安装与使用全攻略

目录一、Spark 简介1.1 Spark 的概念1.2 Spark 的优势1.3 Spark 的应用场景二、安装前准备2.1 硬件要求2.2 软件要求2.3 下载 Spark三、Spark 安装步骤3.1 解压安装包3.2 配置环境变量3.3 配置 spark-env.sh3.4 配置 slaves 文件&#xff08;分布式模式&#xff09;3.5 启动 Sp…

Python 进程间的通信:原理剖析与项目实战

在 Python 编程中,当涉及多进程编程时,进程间的通信(Inter-Process Communication,简称 IPC)是一个重要的课题。多个进程在运行过程中,常常需要交换数据、传递状态或协同工作,这就离不开进程间通信机制。本文将深入讲解 Python 进程间通信的原理,并结合实际项目案例,展…

神经网络之BP算法

一、正向传播正向传播&#xff08;Forward Propagation&#xff09;是神经网络中数据从输入层流向输出层的过程。输入数据通过各层的权重和激活函数逐层计算&#xff0c;最终得到预测输出。数学表示&#xff1a; 对于第 ( l ) 层的神经元&#xff0c;其输出计算如下&#xff1a…

Ubuntu 版本号与别名对照表(部分精选)

Ubuntu 的别名遵循 形容词 动物名 的命名规则&#xff0c;且两个单词首字母相同&#xff0c;按字母表顺序循环使用&#xff08;从 Ubuntu 6.06 开始&#xff09;。 &#x1f4c5; Ubuntu 版本号与别名对照表&#xff08;部分精选&#xff09; 版本号别名 (开发代号)发布时间…

实验03-Spark批处理开发

使用Spark Shell探索RDD 启动并使用Scala Spark Shell 在终端窗口&#xff0c;启动Scala Spark shell&#xff1a; spark-shell --master local查看对象&#xff1a; scala> sc scala> spark输入spark.[TAB]然后可以看到所有可用的方法。 读并显示文本文件 查看文本…

【R语言】Can‘t subset elements that don‘t exist.

Error in select(): ℹ In argument: all_of(label_col). Caused by error in all_of(): ! Cant subset elements that dont exist. ✖ Element Label doesnt exist. Run rlang::last_trace() to see where the error occurred.原文中文解释涉及关键词Error in select()报错发生…

Spring的依赖注入(xml)

引入 首先先明白&#xff0c;依赖注入描述的是在容器中建立bean与bean之间的依赖关系&#xff0c;本质就是将一个类中和别的类解耦的方式&#xff0c;就是把别的类&#xff0c;写在成员变量位置&#xff0c;再对外提供可以给成员变量赋值的方法&#xff0c;外界就直接调用来给…

docker运行的一些常用命令

docker images 显示可以加载的镜像docker ps 显示运行的docker容器 加-a显示所有的容器docker run --name 容器名字 -d 镜像名字docker start 容器名/ID 开启容器docker stop 容器名/ID 关闭容器docker exec -it dock…

Django跨域

步骤 1&#xff1a;安装 django-cors-headerspip install django-cors-headers步骤 2&#xff1a;修改 Django 配置 在 settings.py 中添加&#xff1a;INSTALLED_APPS [...,"corsheaders", # 新增 ]MIDDLEWARE [...,"corsheaders.middleware.CorsMiddleware…

20250706-10-Docker快速入门(下)-Harbor镜像仓库_笔记

一、Harbor镜像仓库搭建与使用1. Harbor概述&#xfeff;&#xfeff;定义: 由VMWare公司开源的容器镜像仓库系统技术基础: 在Docker Registry基础上进行企业级扩展核心特性:提供管理用户界面(GUI)基于角色的访问控制(RBAC)支持&#xfeff;AD/LDAP\mathrm{AD}/\mathrm{LDAP}AD…

JavaScript之数组方法详解

JavaScript之数组方法详解一、数组的创建与基础特性1.1 数组的创建方式1.2 数组的核心特性二、修改原数组的方法2.1 添加/删除元素2.1.1 push()&#xff1a;尾部添加元素2.1.2 pop()&#xff1a;尾部删除元素2.1.3 unshift()&#xff1a;头部添加元素2.1.4 shift()&#xff1a;…

品牌增长困局突围:大模型时代,AI 如何帮我的品牌少走弯路?

AI时代对企业战略的冲击与机遇 在当今瞬息万变的商业环境中&#xff0c;大模型的崛起正以前所未有的力量重塑着各行各业的竞争格局。传统的市场营销、品牌传播模式正在被颠覆&#xff0c;消费者获取信息、认知品牌的方式发生了根本性变化。如果说过去十年是“互联网”的时代&am…

从单体到微服务:Spring Cloud 开篇与微服务设计

一、单体架构的核心痛点与微服务化目标 1. 单体架构的致命缺陷问题表现后果可维护性差百万行代码耦合&#xff0c;修改一处需全量测试迭代周期长&#xff0c;创新停滞扩展性受限无法按模块独立扩缩容&#xff08;如订单模块需扩容时&#xff0c;用户模块被迫一起扩容&#xff0…

篇二 OSI七层模型,TCP/IP四层模型,路由器与交换机原理

一 前言 本章节主要介绍OSI七层模型&#xff0c;TCP/IP四层模型划分&#xff0c;以及日常使用的路由器&#xff0c;交换机的一些基础知识 二 OSI 七层 OSI&#xff08;Open Systems Interconnection Model&#xff09;即开放式系统互联模型&#xff0c;是国际标准化组织提出的&…

【JavaSE面试篇】Java集合部分高频八股汇总

目录 概念 1. 说说Java中的集合&#xff1f; 2. Java中的线程安全的集合有什么&#xff1f; 3. Collections和Collection的区别&#xff1f; 4. 集合遍历的方法有哪些&#xff1f; List 5. 讲一下java里面list的几种实现&#xff0c;几种实现有什么不同&#xff1f; 6.…