【小沐学前端】Node.js实现基于Protobuf协议的WebSocket通信

文章目录

  • 1、简介
    • 1.1 Node
    • 1.2 WebSocket
    • 1.3 Protobuf
  • 2、安装
    • 2.1 Node
    • 2.2 WebSocket
      • 2.2.1 nodejs-websocket
      • 2.2.2 ws
    • 2.3 Protobuf
  • 3、代码测试
    • 3.1 例子1:websocket(html)
      • 3.1.1 客户端:yxy_wsclient1.html
      • 3.1.2 客户端:yxy_wsclient1_2.html
    • 3.2 例子2:websocket(js)
      • 3.2.1 服务端:yxy_wsserver2.js
      • 3.2.2 客户端:yxy_wsclient2.js
    • 3.3 例子3:websocket(js+html)
      • 3.3.1 服务端:yxy_wsserver3.js
      • 3.3.2 客户端:yxy_wsclient3.html
      • 3.3.3 客户端:yxy_wsclient3_2.html
      • 3.3.4 客户端:yxy_wsclient3_3.html
    • 3.4 例子4:websocket(js+proto)
      • 3.4.1 服务端:yxy_wsserver4.js
      • 3.4.2 客户端:yxy_wsclient4.js
    • 3.5 例子5:websocket(js+express)
      • 3.5.1 服务端:yxy_wsserver5.js
      • 3.5.2 客户端:yxy_wsclient5.html
  • 结语

1、简介

1.1 Node

Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型,让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。
在这里插入图片描述
简单的说 Node.js 就是运行在服务端的 JavaScript。

Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台。

Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境,基于 Google 的 V8 引擎,V8 引擎执行 Javascript 的速度非常快,性能非常好。

1.2 WebSocket

https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

WebSocket是一个长连接,客户端可以给服务端发送消息,服务端也可以给客户端发送消息,这便是全双工通信。

WebSocket是html5规范中的一个部分,它借鉴了socket这种思想,为web应用程序客户端和服务端之间(注意是客户端服务端)提供了一种全双工通信机制。同时,它又是一种新的应用层协议,WebSocket协议是为了提供web应用程序和服务端全双工通信而专门制定的一种应用层协议,通常它表示为:ws://echo.websocket.org/?encoding=text HTTP/1.1。通俗的讲,WebSocket 是一种新的网络通信协议,现在浏览器端很多高级功能都需要用到它。
在这里插入图片描述

WebSockets 是一种先进的技术。它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此 API,你可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。

WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455,后由 RFC 7936 补充规范。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

1.3 Protobuf

Google Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
https://github.com/protocolbuffers/protobuf
在这里插入图片描述
Protobuf (Protocol Buffers) 是谷歌开发的一款无关平台,无关语言,可扩展,轻量级高效的序列化结构的数据格式,用于将自定义数据结构序列化成字节流,和将字节流反序列化为数据结构。所以很适合做数据存储和为不同语言,不同应用之间互相通信的数据交换格式,只要实现相同的协议格式,即后缀为proto文件被编译成不同的语言版本,加入各自的项目中,这样不同的语言可以解析其它语言通过Protobuf序列化的数据。
在这里插入图片描述

2、安装

2.1 Node

https://nodejs.org/en

在这里插入图片描述

2.2 WebSocket

下面给出了WebSocket数据帧的统一格式。

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 ...                |
+---------------------------------------------------------------+

2.2.1 nodejs-websocket

https://www.npmjs.com/package/nodejs-websocket

用于 websocket 服务器和客户端的 nodejs 模块

安装库nodejs-websocket:

npm i nodejs-websocket

查看库nodejs-websocket 的当前本地安装版本:

npm ls nodejs-websocket -g

在这里插入图片描述

  • 入门示例
var ws = require("nodejs-websocket")// Scream server example: "hi" -> "HI!!!"
var server = ws.createServer(function (conn) {console.log("New connection")conn.on("text", function (str) {console.log("Received "+str)conn.sendText(str.toUpperCase()+"!!!")})conn.on("close", function (code, reason) {console.log("Connection closed")})
}).listen(8001)

2.2.2 ws

https://www.npmjs.com/package/ws

ws: a Node.js WebSocket library
ws 是一个简单易用、速度快、经过全面测试的 WebSocket 客户端和 服务器实现。

或者安装库ws:

npm i ws

查看库ws的当前本地安装版本:

npm ls ws -g

在这里插入图片描述

2.3 Protobuf

https://github.com/protobufjs/protobuf.js/

Protocol Buffers for JavaScript (& TypeScript).

在这里插入图片描述
安装库protobufjs :

npm install protobufjs [--save --save-prefix=~]
npm install protobufjs-cli [--save --save-prefix=~]

查看库protobufjs 的当前本地安装版本:

npm ls protobufjs -g

在这里插入图片描述

3、代码测试

3.1 例子1:websocket(html)

3.1.1 客户端:yxy_wsclient1.html

  • yxy_wsclient1.html
var ws = new WebSocket("wss://echo.websocket.org");ws.onopen = function(evt) { console.log("Connection open ..."); ws.send("Hello WebSockets!");
};ws.onmessage = function(evt) {console.log( "Received Message: " + evt.data);ws.close();
};ws.onclose = function(evt) {console.log("Connection closed.");
};

3.1.2 客户端:yxy_wsclient1_2.html

  • yxy_wsclient1.html
// Create WebSocket connection.
const socket = new WebSocket("ws://localhost:8080");// Connection opened
socket.addEventListener("open", function (event) {socket.send("Hello Server!");
});// Listen for messages
socket.addEventListener("message", function (event) {console.log("Message from server ", event.data);
});

3.2 例子2:websocket(js)

3.2.1 服务端:yxy_wsserver2.js

const WebSocket = require('ws');//引入模块const wss = new WebSocket.Server({ port: 8080 });//创建一个WebSocketServer的实例,监听端口8080wss.on('connection', function connection(ws) {ws.on('message', function incoming(message) {console.log('received: %s', message);ws.send('Hi Client');});//当收到消息时,在控制台打印出来,并回复一条信息});

3.2.2 客户端:yxy_wsclient2.js

const WebSocket = require('ws');const ws = new WebSocket('ws://localhost:8080');ws.on('open', function open() {ws.send('Hi Server');
});//在连接创建完成后发送一条信息ws.on('message', function incoming(data) {console.log(data);
});//当收到消息时,在控制台打印出来

3.3 例子3:websocket(js+html)

3.3.1 服务端:yxy_wsserver3.js

  • yxy_wsserver3.js
var ws = require("nodejs-websocket")
var PORT = 3000var server = ws.createServer(function (conn) {console.log("New connection")conn.on("text", function (str) {console.log("Received "+str)conn.sendText(str.toUpperCase()+"!!!")})conn.on("close", function (code, reason) {console.log("Connection closed")})conn.on("error",function(err){console.log('handler error')console.log(err)})
}).listen(PORT)console.log('websocket server listening on port ' + PORT)
  • 运行结果如下:
    在这里插入图片描述

3.3.2 客户端:yxy_wsclient3.html

  • yxy_wsclient3.html
<html>
<head><meta charset="utf-8"/><title>websocket</title>
</head>
<body><h1>Echo test</h1><input id="sendTxt" type="text"/><button id="sendBtn">发送</button><div id="recv"></div><script type="text/javascript">// var websocket = new WebSocket("ws://echo.websocket.org/");var websocket = new WebSocket("ws://127.0.0.1:3000");websocket.onopen = function(){console.log('websocket open');document.getElementById('recv').innerHTML = 'Connected';}websocket.onclose = function(){console.log('websocket close');}websocket.onmessage = function(event){console.log(event.data);document.getElementById('recv').innerHTML = event.data;}document.getElementById('sendBtn').onclick = function(){var txt = document.getElementById('sendTxt').value;websocket.send(txt);}</script>
</body>
  • 运行结果如下:
    在这里插入图片描述

3.3.3 客户端:yxy_wsclient3_2.html

  • yxy_wsclient3_2.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WenSocket</title><style>div{width: 200px;height: 200px;border:1px solid;margin-top: 5px;}</style>
</head>
<body><input type="text" placeholder="请输入内容"><button>提交</button><div></div><script>const input = document.querySelector('input')const button = document.querySelector('button')const div = document.querySelector('div')//创建WebSocket实例// const socket = new WebSocket("ws://echo.websocket.org")const socket = new WebSocket("ws://127.0.0.1:3000")//监听服务是否链接socket.addEventListener('open',()=>{div.innerHTML = "服务链接成功"})//button触发点击事件,将input框中的内容发送至websocket//查看websocket是否接收到数据:chrome F12打开控制台》Network》WS》echo.websocket.org》messagesbutton.addEventListener('click',()=>{const value = input.valuesocket.send(value)})// 将接收到的数据插入到div中socket.addEventListener('message',(e)=>{console.log(e)div.innerHTML = e.data})</script>
</body>
</html>
  • 运行结果如下:
    在这里插入图片描述

3.3.4 客户端:yxy_wsclient3_3.html

  • yxy_wsclient3_3.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket</title><style></style>
</head>
<body><input type="text" placeholder="请输入内容"><button>提交</button><div></div><script>const input = document.querySelector('input')const button = document.querySelector('button')const div = document.querySelector('div')const socket = new WebSocket('ws://127.0.0.1:3000')socket.addEventListener('open',()=>{div.innerText = "欢迎来到聊天室"})button.addEventListener('click',()=>{const value = input.valuesocket.send(value)input.value = ''})socket.addEventListener('message',(e)=>{//div.innerText = e.data //这种方法会覆盖原先的数据const dv = document.createElement('div')dv.innerText = e.datadiv.appendChild(dv)})</script>
</body>
</html>

在这里插入图片描述

3.4 例子4:websocket(js+proto)

WebSocket是HTML5新增的协议,它的目的是在浏览器和服务器之间建立一个不受限的双向通信的通道,比如说,服务器可以在任意时刻发送消息给浏览器。任何一方都可以主动发消息给对方。

HTTP协议是一个请求-响应协议,请求必须先由浏览器发给服务器,服务器才能响应这个请求,再把数据发送给浏览器。换句话说,浏览器不主动请求,服务器是没法主动发数据给浏览器的。

WebSocket并不是全新的协议,而是利用了HTTP协议来建立连接。

安装ws库:

npm i ws
  • user.proto
syntax = "proto3";
package yxy;message Login {required string name = 1;required string pwd = 2;
}
message Address{string province = 1;string city = 2;string country = 3;
}

3.4.1 服务端:yxy_wsserver4.js

  • yxy_wsserver4.js

const protobuf = require("protobufjs");
const PORT = 3000;
const HOST = '127.0.0.1';protobuf.load("./user.proto", (err, root) => {if (err) throw err;const LoginMessage = root.lookupType("yxy.Login");const WebSocket = require('ws')const WebSocketServer = WebSocket.Server;const wss =new WebSocketServer({port:PORT})//如果有WebSocket请求接入,wss对象可以响应connection事件来处理这个WebSocket:wss.on('connection',function(ws){  //在connection事件中,回调函数会传入一个WebSocket的实例,表示这个WebSocket连接。console.log(`[SERVER] connection()`);ws.on('message',function(message){console.log(`[SERVER] Received:${message}`);// 解码数据 const payload = LoginMessage.decode(message);// 在这里处理消息console.log(payload);// 编码响应 const responseData = LoginMessage.encode({name: "杨小羊",pwd: "111111"}).finish();const msg = responseData.toString();ws.send(`ECHO:${msg}` ,(err)=>{if(err){console.log(`[SERVER] error:${err}`);}})})})
});
  • 运行结果如下:
    在这里插入图片描述

3.4.2 客户端:yxy_wsclient4.js

  • yxy_wsclient4.js
const protobuf = require("protobufjs");
const PORT = 3000;
const HOST = '127.0.0.1';protobuf.load("./user.proto", (err, root) => {if (err) throw err;const LoginMessage = root.lookupType("yxy.Login");const WebSocket = require('ws')let ws = new WebSocket('ws://localhost:3000');// 打开WebSocket连接后立刻发送一条消息:ws.on('open', function () {console.log(`[CLIENT] open()`);//每隔一秒向服务器发送消息,以便后面每隔一秒收到消息setInterval(function(){// 编码数据 const data = LoginMessage.encode({name: "爱看书的小沐",pwd: "222222"}).finish();// 将数据写到连接 ws.send(data);console.log(`[CLIENT] Send: ${data}`);},1000)});// 响应收到的消息:ws.on('message', function (message) {console.log(`[CLIENT] Received: ${message}`);const loginResponse = LoginMessage.decode(message);console.log(loginResponse);})
});
  • 运行结果如下:
    在这里插入图片描述

3.5 例子5:websocket(js+express)

3.5.1 服务端:yxy_wsserver5.js

  • yxy_wsserver5.js
var app = require('express')();
var server = require('http').Server(app);
var WebSocket = require('ws');var wss = new WebSocket.Server({port: 8080
});wss.on('connection', function connection(ws) {console.log('server: receive connection.');ws.on('message', function incoming(message) {console.log('server: received: %s', message);});ws.send('world');
});app.get('/', function (req, res) {res.sendfile(__dirname + '/index.html');
});app.listen(3000);

在这里插入图片描述

3.5.2 客户端:yxy_wsclient5.html

  • yxy_wsclient5.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket</title><style></style>
</head><body><script>var ws = new WebSocket('ws://localhost:8080');ws.onopen = function () {console.log('ws onopen');ws.send('from client: hello');};ws.onmessage = function (e) {console.log('ws onmessage');console.log('from server: ' + e.data);};
</script></body>
</html>

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

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

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

相关文章

【踩坑日记】Docker elasticsearch too many open files问题处理

项目场景&#xff1a; 使用单机ES作为日志存储数据库&#xff0c;每日生成一个日期索引&#xff0c;由于每日的数据量可能较大&#xff0c;有时候需要进行磁盘扩容操作&#xff0c;本次问题记录还未找到根本的触发原因&#xff0c;后续找到原因后再进行记录 问题描述 每日创建…

利用mAP计算yolo精确度

当将yolo算法移植部署在嵌入式设备上&#xff0c;为了验证算法的准确率。将模型测试的结果保存为txt文件&#xff08;每一个txt文件&#xff0c;对应一个图片&#xff09;。此外&#xff0c;需要将数据集中的标签由[x,y,w,h]转为[x1,y1,x2,y2]。最后&#xff0c;运行验证代码 …

【redisson学习笔记】

1)clone项目 git clone https://github.com/redisson/redisson.git本来想直接用maven编译源码&#xff0c; 却发现各种错误&#xff0c;主要是maven的编译插件版本问题。 2)然后用maven包方式引入 <dependencies><dependency><groupId>org.redisson</gr…

Secureboot从入门到精通

关键词&#xff1a;trustzone视频、tee视频、ATF视频、secureboot视频、安全启动视频、selinux视频&#xff0c;cache视频、mmu视频&#xff0c;armv8视频、armv9视频 FF-A视频、密码学视频、RME/CCA视频、学习资料下载、免费学习资料、免费 周贺贺&#xff0c;baron&#xff0…

把握现在,热爱生活

博客主页&#xff1a;https://tomcat.blog.csdn.net 博主昵称&#xff1a;农民工老王 主要领域&#xff1a;Java、Linux、K8S 期待大家的关注&#x1f496;点赞&#x1f44d;收藏⭐留言&#x1f4ac; 目录 厨艺房价琐事计划随想 今年的中秋国庆假期放8天&#xff0c;比春节假期…

【RuoYi项目分析】网关的AuthFilter完成“认证”,注意是认证而不是权限

文章目录 1. 功能介绍2. AuthFilter的配置3. AuthFilter实现分析4. 资料参考 过滤器的功能是检验经过网关的每一个请求&#xff0c;检查 token 中的信息是否有效。 注意是“认证检查”&#xff0c;而不是“权限” 1. 功能介绍 1、在用户完成登录后&#xff0c;程序会把用户相关…

Centos7配置firewalld防火墙规则

这里写自定义目录标题 欢迎使用Markdown编辑器一、简单介绍二、特点和功能2.1、区域&#xff08;Zone&#xff09;2.2、运行时和永久配置2.3、服务和端口2.4、动态更新2.5、连接跟踪2.6、D-Bus接口 三、设置规则3.1、启动防火墙服务3.2、新建防火墙规则的服务&#xff0c;添加端…

分布式链路追踪--SkyWalking7.0.0+es7.0.0

分布式链路追踪–SkyWalking ​ 微服务的出现&#xff0c;的确解决了一些业务痛点&#xff0c;但是也造成了新的问题比如随着调用链的拉长&#xff0c;如果想要知道请求为什么这么慢&#xff0c;这个请求到底经历了哪些环节&#xff0c;又依赖了哪些东西&#xff0c;在微服务架…

亲测可用国产GPT人工智能

分享一些靠谱、可用、可以白嫖的GPT大模型。配合大模型&#xff0c;工作效率都会极大提升。 清华大学ChatGLM 官网&#xff1a; 智谱清言中国版对话语言模型&#xff0c;与GLM大模型进行对话。https://chatglm.cn/开源的、支持中英双语的1300亿参数的对话语言模型&#xff0…

【MATLAB】字体美化和乱码

文章目录 前言首先说说说字体美化乱码到底是怎么导致的&#xff1f;1 字体导致的乱码2 编码导致的乱码总结 前言 最近打开MATLAB&#xff0c;又发现了一个问题&#xff1a;编辑器中的中文输入在命令行或者说终端输出竟然是乱码&#xff0c;然后赶紧翻阅了一下此前的博客以及未发…

使用VBA实现快速模糊查询数据

实例需求&#xff1a;基础数据保存在Database工作表中&#xff0c;如下图所示。 基础数据有37个字段&#xff0c;上图仅展示部分字段内容&#xff0c;下图中黄色字段为需要提取的数据字段。 在Search工作表B1单元格输入查询关键字Title和Genre字段中搜索关键字&#xff0c;包…

【数据结构--八大排序】之归并排序

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

目标检测YOLO实战应用案例100讲-基于端到端的自动驾驶道路环境目标检测

目录 前言 国内外研究现状 目标检测算法研究现状 骨干网络研究现状

Armv9 Cortex-A720的L2 memory system 和 L2 Cache

9 L2 memory system Cortex-A720核心的L2内存系统通过CPU bridge连接core与DynamIQ Shared Unit-120,其中包括私有的L2缓存。 L2缓存是统一的,每个Cortex-A720核心在一个集群中都有私有的L2缓存。 L2内存系统包括使用虚拟地址(VA)和程序计数器(PC)的数据预取引擎。不同…

Kolmogorov-Smirnov正态性检验

Kolmogorov-Smirnov正态性检验是一种统计方法&#xff0c;用于检验数据集是否服从正态分布。其基本原理和用途如下&#xff1a; 基本原理&#xff1a; 假设检验&#xff1a;Kolmogorov-Smirnov检验基于一个假设&#xff0c;即待检验的数据集服从特定的理论正态分布。计算累积…

【2023研电赛】华东赛区一等奖:电动叉车永磁同步电机MTPA及弱磁控制研究

本文为2023年第十八届中国研究生电子设计华东赛区一等奖竞赛作品分享&#xff0c;参加极术社区的【有奖活动】分享2023研电赛作品扩大影响力&#xff0c;更有丰富电子礼品等你来领&#xff01;&#xff0c;分享2023研电赛作品扩大影响力&#xff0c;更有丰富电子礼品等你来领&a…

Kakfa高效读写数据

1.概述 无论 kafka 作为 MQ 也好&#xff0c;作为存储层也罢&#xff0c;无非就是两个功能&#xff1a;一是 Producer 生产的数据存到 broker&#xff0c;二是 Consumer 从 broker 读取数据。那 Kafka 的快也就体现在读写两个方面了&#xff0c;本文也是从这两个方面去剖析Kafk…

nodejs+vue健身服务应用elementui

第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性&#xff1a;技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性&#xff1a; 11 3.3性能分析 11 3.4系统操作流程 12 3.4.1管理员登录流程 12 3.4.2信息添加流程 12 3.4.3信息删除流程 13 第四章 系统设计与…

数据结构与算法-(7)---栈的应用-(3)表达式转换

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

华为云云耀云服务器 L 实例评测:快速建站的新选择,初创企业和开发者的理想之选

华为云云耀云服务器 L 实例评测&#xff1a;快速建站的新选择&#xff0c;初创企业和开发者的理想之选 文章目录 华为云云耀云服务器 L 实例评测&#xff1a;快速建站的新选择&#xff0c;初创企业和开发者的理想之选导语&#xff1a;摘要&#xff1a; 正文产品概述部署简易性步…