当前位置: 首页 > article >正文

网络原理 | TCP与UDP协议的区别以及回显服务器的实现

目录

TCP与UDP协议的区别

基于 UDP 协议实现回显服务器 

UDP Socket 编程常用 Api

UDP 服务器

UDP 客户端

基于 TCP 协议实现回显服务器

TCP Socket 编程常用 Api

TCP 服务器

TCP 客户端 

TCP 服务端常见的 bug 

客户端发送数据后,没有响应

服务器仅支持与一个客户端建立连接 


TCP与UDP协议的区别

        传输控制协议(TCP)与 用户数据报协议(UDP)是传输层两个重要的协议,二者互补共存,共同支撑互联网的多层次传输需求。

 二者的区别如下:

        · TCP 协议是有连接的、可靠传输、面向字节流、全双工

        · UDP 协议是无连接的、不可靠传输、面向数据报、全双工

        其中有/无连接是指:如果通信双方保存了通信对端的信息,就相当于是有连接;如果不保存对端的信息,就是无连接。 

        可靠传输/不可靠传输:此处的可靠不是指 100% 能到达对方,而是指“尽可能”确保数据的传输,而“不可靠”则意味着完全不保证数据是否能成功到达对方。TCP 通过一些内置机制(确认应答机制、重传机制等)保证了可靠传输,UDP则没有可靠性机制。

        面向字节流/面向数据报:TCP 是面向字节流的,TCP 的传输过程就和文件流/水流是一样的;而 UDP 是面向数据报的,其传输数据的基本单位是数据报,一次发送/接收必须发送/接收完整的数据报。

        全双工/半双工:全双工是指一个通信链路既可以发送数据也可以接收数据(双向通信),半双工是指一个通信链路只能发送/接收数据(单向通信)。

TCP 和 UDP 的选择以及适用场景

· 当数据准确性 > 传输延迟时(例如软件更新下载、文件传输、网页浏览等场景),选择 TCP。

        因为 TCP 能够保证数据的可靠传输,通过确认应答、重传机制等手段确保数据的完整性和准确性,适用于对数据传输准确性要求较高的应用。

· 当实时性 > 数据完整性时(例如多人游戏同步、在线视频会议、实时语音通话等场景),选择 UDP。

        UDP适用于对实时性要求较高的场景,虽然它不保证数据的完整性,但能减少延迟,确保数据传输的实时性。特别是在实时通信中,丢失少量数据包对用户体验的影响相对较小,而过高的延迟可能影响整体体验。

基于 UDP 协议实现回显服务器 

UDP Socket 编程常用 Api

· DatagramSocket:是一种用于网络通信的套接字对象,代表了操作系统中一个特定类型的“文件”资源。可以将其理解为操作系统对网络设备(如网卡)的一种抽象表示,就像操作系统将硬盘、键盘等设备抽象为文件一样,DatagramSocket 抽象了网络数据的发送与接收通道。它专门用于通过 UDP(用户数据报协议) 发送和接收数据报(Datagram),支持无连接、不可靠但高效的通信方式。通过 DatagramSocket,应用程序能够将数据以数据报的形式发送到目标地址,同时也能接收来自网络上其他节点的数据报,实现轻量级的网络通信。

· DatagramSocket的构造方法包括以下两种形式:

        DatagramSocket():创建一个 UDP 数据报套接字的 Socket,绑定到本机任意一个随机端口(通常用于客户端)

        DatagramSocket(int port):创建一个 UDP 数据报套接字的 Socket,绑定到本机指定的端口(通常用于服务端)

· DatagramSocket类下的方法:

        void receive(DatagramPacket p):从套接字接收数据报,如果没有接收到数据报就会阻塞等待

        void send(DatagramPacket p):从套接字发送数据报,不会阻塞等待,直接发送

        void close():关闭此数据报套接字

 · DatagramPacket:是 UDP Socket 发送/接收的数据报,其构造方法包括:

        DatagramPacket(byte[] buf, int length):构造⼀个DatagramPacket以⽤来接收数据报,接收的数据保存在字节数组(第⼀个参数buf)中,接收指定长度(第⼆个参数length)

        DatagramPacket(byte[] buf, int offset, int length, SocketAddress address):构造⼀个DatagramPacket以⽤来发送数据报,发送的数据为字节数组(第⼀个参数buf)中,从0到指定长度(第⼆个参数length)。address指定⽬的主机的 IP 和端口号。

· DatagramPacket类下的方法:

        InetAddress getAddress():从接收的数据报中,获取发送端主机 IP 地址;或从发送的数据报中,获取接收端主机 IP 地址

        int getPort():从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号

        byte[] getData():获取数据报中的数据

        回显服务器需要实现两个程序:UDP 服务器和 UDP 客户端,主动发起通信的一方称为客户端,被动接收的一方的是服务器。

UDP 服务器

package network;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;/*** Created with IntelliJ IDEA.* Description: 回显服务器* 客户端发啥样的请求,服务器就返回啥样的响应* User: Li_yizYa* Date: 2025/5/13* Time: 15:29*/
public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}/*** 通过 start 启动服务器的核心流程*/public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 此处通过 “死循环” 不停的处理客户端的请求.// 1. 读取客户端的请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// 上述收到的数据,是二进制 byte[] 的形式体现的,后续代码如果要进行打印之类的处理操作// 需要转成字符串才好处理String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 根据请求计算响应,由于此处是回显服务器,响应就是请求String response = process(request);// 3. 把响应写回到客户端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);// 4. 打印日志System.out.printf("[%s:%d] req=%s, resp=%s\n", requestPacket.getAddress(), requestPacket.getPort(),request, response);}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

UDP 客户端

package network;import java.io.IOException;
import java.net.*;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: Li_yizYa* Date: 2025/5/13* Time: 15:29*/
public class UdpEchoClient {DatagramSocket socket = null;private String serverIP;private int serverPort;public UdpEchoClient(String serverIP, int serverPort) throws IOException {socket = new DatagramSocket();this.serverIP = serverIP;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("启动客户端");Scanner scanner = new Scanner(System.in);while (true) {// 1. 从控制台读取到用户的输入System.out.print("-> ");String request = scanner.next();// 2. 构造一个 UDP 请求,发送给服务器DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(this.serverIP), this.serverPort);socket.send(requestPacket);// 3. 从服务器读取到响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);String response = new String(responsePacket.getData(), 0, responsePacket.getLength());// 4. 把响应打印到控制台上System.out.println(response);}}public static void main(String[] args) throws IOException {// 127.0.0.1 特殊 IP,环回 IP// 如果客户端和服务器在同一个主机上,就使用这个 IPUdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);client.start();}
}

基于 TCP 协议实现回显服务器

TCP Socket 编程常用 Api

        在TCP Socket编程中,核心类是 ServerSocket(专门给服务器使用的 Socket 对象)和 Socket(既会给客户端使用,又会给服务器使用)。由于 TCP 协议是面向字节流的,其数据的基本传输单位就是 byte,因此不需要像 UDP 协议那样定义一个类来表示 “数据报” 对象。

· ServerSocket:是创建 TCP 服务器 Socket 的 Api,其构造方法为:

        ServerSocket(int port):创建⼀个服务端流套接字Socket,并绑定到指定端口

· ServerSocket 类下常用的方法:

        Socket accept():开始监听指定端口(创建时绑定的端口),有客户端连接后,返回⼀个服务端 Socket 对象,并基于该 Socket 建立与客户端的连接,否则阻塞等待

        void close():关闭此套接字

 · Socket:其是客户端 Socket,或服务端接收到客户端建立连接(accept方法)的请求后,返回的服务端 Socket。不管是客户端还是服务端 Socket,都是双方建立连接以后,保存的对端信息,及时用来与对方收发数据的。其构造方法为:

        Socket(String host, int port):创建⼀个客户端流套接字 Socket,并与对应 IP 的主机 上,对应端口的进程建立连接。

· Socket 类下的方法:

        InetAddress getInetAddress():返回套接字所在的地址

        InputStream getInputStream():返回此套接字的输入流

        OutputStream getOutputStream():返回此套接字的输出流

TCP 服务器

package network;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description: TCP回显服务器* 客户端发啥样的请求,服务器就返回啥样的响应* User: Li_yizYa* Date: 2025/5/21* Time: 20:19*/
public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器");while (true) {Socket clientSocket = serverSocket.accept();Thread t = new Thread(() -> {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});t.start();}}// 针对一个连接,提供处理逻辑private void processConnection(Socket clientSocket) throws IOException {// 先打印一下客户端信息System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());// TCP 是全双工的通信,一个 socket 对象,既可以读,也可以写// 获取到 socket 中持有的流对象try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {// 使用 Scanner 包装一下 inputStream,就可以更方便的读取这里的请求数据了while (true) {// 1. 读取请求并解析Scanner scanner = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);if (!scanner.hasNext()) {// 如果 scanner 无法读取出数据,说明客户端关闭了连接,导致服务器这边读取到 “末尾”break;}String request = scanner.next();// 2. 根据请求计算响应String response = process(request);// 3. 把响应写回给客户端// 此处可以按照字节数组来写,也可以右另外一种写法// outputStream.write(response.getBytes());printWriter.println(response);printWriter.flush();// 打印日志System.out.printf("[%s:%d] req=%s; resp=%s\n", clientSocket.getInetAddress(),clientSocket.getPort(), request, response);}} catch (IOException e) {e.printStackTrace();} finally {System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());clientSocket.close();}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}

TCP 客户端 

package network;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: Li_yizYa* Date: 2025/5/21* Time: 20:20*/
public class TcpEchoClient {private Socket socket = null;/*** 构造方法* @param serverIp 服务器 Ip* @param serverPort 服务器端口号*/public TcpEchoClient(String serverIp, int serverPort) throws IOException {socket = new Socket(serverIp, serverPort);}public void start() {System.out.println("客户端启动");try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);Scanner scannerIn = new Scanner(System.in);PrintWriter printWriter = new PrintWriter(outputStream);while (true) {// 1. 从控制台读取数据System.out.print("-> ");String request = scannerIn.next();// 2. 把请求发给服务器printWriter.println(request);// 引入 flush(冲刷) 操作,主动刷新缓冲区printWriter.flush();// 3. 从服务器读取响应if (!scanner.hasNext()) {break;}String response = scanner.next();// 4. 打印响应结果System.out.println(response);}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();}
}

TCP 服务端常见的 bug 

客户端发送数据后,没有响应

 在客户端中,我们通过下面的方式给服务端发送请求:

// 2. 把请求发给服务器
printWriter.println(request);

        之所以这里没有响应,是因为其实客户端的数据并没有发送出去,因为 PrintWriter 这个类以及 IO 流中的很多类,都是自带缓冲区的,引入缓冲区之后,进行 写入数据操作 时,不会立即触发 IO,而是先将其放在内存缓冲区中,等缓冲区数据到达一定数量后,才会统一发送。而上述的问题,其实就是因为数据比较少,并未触发发送操作。因此,我们通过引入 flush 操作就可以解决该问题:

// 引入 flush(冲刷) 操作,主动刷新缓冲区
printWriter.flush();

服务器仅支持与一个客户端建立连接 

        对于该问题,引入多线程操作修改服务器代码中的 start 方法即可,每有一个客户端请求建立与服务器的连接,就创建一个线程来专门处理与该客户端之间的数据发送/接收,具体代码如下:

    public void start() throws IOException {System.out.println("启动服务器");while (true) {Socket clientSocket = serverSocket.accept();Thread t = new Thread(() -> {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});t.start();}}

相关文章:

网络原理 | TCP与UDP协议的区别以及回显服务器的实现

目录 TCP与UDP协议的区别 基于 UDP 协议实现回显服务器 UDP Socket 编程常用 Api UDP 服务器 UDP 客户端 基于 TCP 协议实现回显服务器 TCP Socket 编程常用 Api TCP 服务器 TCP 客户端 TCP 服务端常见的 bug 客户端发送数据后,没有响应 服务器仅支持…...

IP动态伪装开关

IP动态伪装开关 在OpenWrt系统中,IP动态伪装(IP Masquerading)是一种网络地址转换(NAT)技术,用于在私有网络和公共网络之间转换IP地址。它通常用于允许多个设备共享单个公共IP地址访问互联网。以下是关于O…...

【Unity3D】将自动生成的脚本包含到C#工程文件中

我们知道,在用C#开发中,通过vs编辑器新建的脚本,会自动包含到vs工程中,而通过外部创建,比如复制别的工程或代码创建的C#脚本不会包含到vs工程。 在我们的日常开发中,通常会自动创建C#脚本,特别…...

解决leetcode第3509题.最大化交错和为K的子序列乘积

3509.最大化交错和为K的子序列乘积 难度:困难 问题描述: 给你一个整数数组nums和两个整数k与limit,你的任务是找到一个非空的子序列,满足以下条件: 它的交错和等于k。 在乘积不超过limit的前提下,最大…...

【Python 深度学习】1D~3D iou计算

一维iou 二维 import numpy as npdef iou_1d(set_a, set_b):# 获得集合A和B的边界 x1, x2 set_ay1, y2 set_b# 计算交集的上下界low max(x1,y1)high - min(x2, y2)# 计算交集if high - low < 0:inter 0else:inter high - low# 计算并集union (x2 -x1) (y2 - y1) - in…...

java23

1.美化界面 添加背景图片 所以我们添加背景图片要放在后面添加 添加图片边框 绝对路径&#xff1a; 相对(模块)路径&#xff1a; 第一个是绝对路径&#xff0c;第二个是相对路径&#xff0c;但是斜杠的方向不对 总结&#xff1a; 2.图片移动 先实现KeyListener接口&#xf…...

嵌入式工程师常用软件

1、 Git Git 是公司常用的版本管理工具&#xff0c;人人都要会。在线的 git 教程可以参考菜鸟教程&#xff1a; https://www.runoob.com/git/git-tutorial.html 电子书教程请在搜索栏搜索&#xff1a; git Git 教程很多&#xff0c;常用的命令如下&#xff0c;这些命令可…...

LitCTF2025 WEB

星愿信箱 使用的是python&#xff0c;那么大概率是ssti注入 测试{{5*5}} 发现需要包含文字&#xff0c;那么添加文字 可以看到被waf过滤了&#xff0c;直接抓包查看参数上fenjing 可以看到这里是json格式&#xff0c;其实fenjing也是支持json格式的 https://github.com/Marv…...

Redisson WatchDog会一直续期吗?

取决于加锁的方式。 Lock 方法有2种形式&#xff0c;如果指定了leaseTime &#xff08;且不为-1&#xff09;&#xff0c; 不会启用watchDog机制. 如果没有指定leaseTime&#xff0c; 则会启动watchDog机制&#xff0c;且会一直续期&#xff0c;除非线程宕调或者续期失败。 p…...

Linux 下VS Code 的使用

这里以创建helloworld 为例。 Step 0:准备工作&#xff1a; Install Visual Studio Code. Install the C extension for VS Code. You can install the C/C extension by searching for c in the Extensions view (CtrlShiftX). Step 1: 创建工作目录 helloworld&#xff0…...

Android开发namespace奇葩bug

Android开发namespace奇葩bug namespace "com.yibanxxx.yiban"buildFeatures {buildConfig true}namespace 对应你的module的清单下的package...

watchEffect

在处理复杂异步逻辑时&#xff0c;Vue 3 的 watchEffect 相比传统的 watch 具有以下优势&#xff1a; 1. 自动追踪依赖 watchEffect 会自动收集其回调中使用的所有响应式依赖&#xff0c;无需手动指定监听源&#xff1a; import { ref, watchEffect } from vue;const count …...

Qt 布局管理器的层级关系

1、HomeWidget.h头文件&#xff1a; #ifndef HOMEWIDGET_H #define HOMEWIDGET_H#include <QWidget> #include <QPushButton> #include <QVBoxLayout> #include <QHBoxLayout>class HomeWidget : public QWidget {Q_OBJECTpublic:HomeWidget(QWidget …...

Android 之 kotlin 语言学习笔记一

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/learn?hlzh-cn 1、变量声明 Kotlin 使用两个不同的关键字&#xff08;即 val 和 var&#xff09;来声明变量。 val 用于值从不更改的变量。使用 val 声明的变量无法重新赋值。var 用于值可以更改的变量…...

maven模块化开发

使用方法 将项目安装到本地仓库 mvn install 的作用 运行 mvn install 时&#xff0c;Maven 会执行项目的整个构建生命周期&#xff08;包括 compile、test、package 等阶段&#xff09;&#xff0c;最终将构建的 artifact 安装到本地仓库&#xff08;默认路径为 ~/.m2/repos…...

为什么要使用stream流

总的来说就是 它支持链式调用&#xff0c;方便 不会修改原始数据源&#xff0c;而是生成一个新的流或结果 中间操作不会立即执行&#xff0c;只有在终端操作触发时才会真正执行 注意事项 无状态操作&#xff1a;Stream 操作应该是无状态的&#xff0c;不要依赖外部变量的状…...

语义分割的image

假设图像的尺寸为 3x3&#xff0c;并且是 RGB 图像&#xff08;有 3 个通道&#xff09;。每个通道的像素值范围为 [0, 1]&#xff0c;我们将构造一个 batch_size 2 的图像批次。 Image: tensor([[[[0.1347, 0.4583, 0.7102], # 第一张图像的红色通道[0.1774, 0.0328, 0.308…...

云原生安全之网络IP协议:从基础到实践指南

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 IP协议&#xff08;Internet Protocol&#xff09;是互联网通信的核心协议族之一&#xff0c;负责在设备间传递数据包。其核心特性包括&…...

C++——QT 文件操作类

QFile 概述 QFile是Qt框架中用于文件操作的类&#xff08;位于QtCore模块&#xff09;&#xff0c;继承自 QIODevice&#xff0c;提供文件的读写、状态查询和路径管理功能。它与 QTextStream、QDataStream 配合使用&#xff0c;可简化文本和二进制数据的处理&#xff0c;并具备…...

【排错】kylinLinx环境python读json文件报错UTF-8 BOM

kylin Linux环境python读json文件报错UTF-8 BOM 报错描述&#xff1a; windows环境下,python代码读取json文件正常&#xff0c;但是sftp到linux环境下 报错信息&#xff1a; json.decoder.JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column …...

[spring] spring 框架、IOC和AOP思想

目录 传统Javaweb开发的困惑 loC、DI和AOP思想提出 Spring框架的诞生 传统Javaweb开发的困惑 问题一&#xff1a;层与层之间紧密耦合在了一起&#xff0c;接口与具体实现紧密耦合在了一起 解决思路&#xff1a;程序代码中不要手动new对象&#xff0c;第三方根据要求为程序提…...

LInux—shell编程

一、Shell 编程核心特性 解释型语言 无需编译&#xff0c;直接由 bash、sh 等解释器逐行执行。 类似 PHP 的解释执行&#xff0c;不同于 C 的编译型。 系统命令集成 可直接调用 Linux 命令&#xff08;如 ls、grep、awk&#xff09;&#xff0c;实现系统管理自动化。 与 C/…...

尚硅谷redis7 37-39 redis持久化之AOF简介

37 redis持久化之AOF简介 AOF 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工…...

GitLab 备份所有仓库(自动克隆)

一、准备工作 1. 环境要求 已安装 Git&#xff08;版本 2.10&#xff09;本地磁盘空间充足&#xff08;根据仓库总大小预估&#xff09;已配置 SSH 密钥到 GitLab&#xff08;推荐方式&#xff09; 2. 获取 GitLab API 访问权限 登录 GitLab&#xff0c;点击右上角头像 → …...

[浏览器]缓存策略机制详解

在做页面性能优化的时候&#xff0c;有一个点容易被忽略&#xff0c;那就是资源缓存优化。 浏览器里缓存策略分为强缓存&#xff0c;协商缓存以及不缓存&#xff0c;每个缓存策略都有其适用的优化场景。 下面为大家详解何为强缓存&#xff0c;协商缓存 先说结论强缓>协商&g…...

Vue修饰符全解析

目录 一、事件修饰符 二、按键修饰符 三、系统修饰键 四、表单修饰符 五、鼠标修饰符 六、特殊修饰符 七、自定义修饰符 使用建议 一、事件修饰符 <!-- 阻止冒泡 --> <button click.stop"handleClick">点击测试</button><!-- 阻止默认行…...

OpenCV CUDA 模块图像过滤-----创建一个计算图像导数的滤波器函数createDerivFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::createDerivFilter 是 OpenCV CUDA 模块中的一个工厂函数&#xff0c;用于创建一个计算图像导数的滤波器。这个滤波器可以用来计算图像…...

计算机视觉与深度学习 | Python实现CEEMDAN-ABC-VMD-DBO-CNN-LSTM时间序列预测(完整源码和数据)

以下是一个结合CEEMDAN、ABC优化VMD、DBO优化CNN-LSTM的完整时间序列预测实现方案。该方案包含完整的数据生成、算法实现和模型构建代码。 完整实现代码 import numpy as np import pandas as pd from PyEMD import CEEMDAN from vmdpy import VMD from sklearn.preprocessing…...

AWS関連職種向け:日本語面接QA集

1. 自己紹介&#xff08;じこしょうかい&#xff09; Q&#xff1a;簡単に自己紹介をお願いします。 A&#xff1a; はい、〇〇と申します。これまで約4年間、主にAWSを基盤としたインフラ設計・構築・運用に従事してまいりました。VPCやEC2、RDS、S3などの基本サービスの設計…...

【Macos】安装前端环境rust+node环境

Macos 安装前端环境 1、findar 新建目录 projects 2、安装brew 使用中科大镜像, 手动配置path 3、brew install git 4、 git clone githttp://10.10.9.201/software/dreame_sorting_app.git 5、安装vscode/hbuilderx/node 6、rustup切换镜像并安装https://rsproxy.cn/#getStart…...