简单实现基于UDP与TCP的回显服务器
目录
- 前言
- UDP 版的回显服务器
- 需要用到的 api
- 服务端
- 客户端
- UDP 版本的字典客户端和字典服务器
- TCP 版的回显服务器
- 需要用到的 api
- 服务器
- 客户端
- 对服务器进行改进(使用线程池)
- TCP 版本的字典客户端和字典服务器
前言
我们写网络程序, 主要编写的是应用层代码.
真正要发送这个数据, 还需要上层协议调用下层协议, 也就是应用层调用传输层.
传输层给应用层提供了一组 api, 统称为 socket api, 系统给程序提供的 api 是C 风格的, JDK 针对这些 api 进行封装, 封装成 Java 风格的 api.
提供的 socket api 主要是这两组 :
- 基于 UDP 的 api
- 基于 TCP 的 api
因为 UDP 与 TCP 的协议差别很大, 所以这两组 api 差别也很大.
那这两个协议都有啥特点呢?
UDP :
- 无连接 (使用 UDP 的双方不需要刻意保存对端的相关信息)
- 不可靠传输 (消息发送完了就行, 不关注结果)
- 面向数据报 (以一个 UDP 数据报为基本单位)
- 全双工 (一条路径, 双向通信)
TCP :
- 有连接 (使用 TCP 的双方要刻意保存对端的相关信息)
- 可靠传输 (发送消息后, 知道对方是否接收到)
- 面向字节流 (以字节为传输的基本单位, 读写方式非常灵活)
- 全双工 (一条路径, 双向通信)
UDP 版的回显服务器
需要用到的 api
- DatagramSocket API
DatagramSocket 是 UDP Socket,用于发送和接收UDP数据报。
主要用到的构造方法 :
DatagramSocket()
创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(intport)
创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)
主要用到的方法 :
void receive(DatagramPacket p)
从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacketp)
从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()
关闭此数据报套接字
- DatagramPacket API
DatagramPacket是UDP Socket发送和接收的数据报.
主要用到的构造方法 :
DatagramPacket(byte[] buf, int length)
构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数 length)
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)
构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从offset到指定长度(第三个参数length)。address指定目的主机的IP和端口号
主要用到的方法 :
InetAddress getAddress()
从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址.
int getPort()
从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获
取接收端主机端口号
byte[] getData()
获取数据报中的数据
构造UDP发送数据报时,需要传入 SocketAddress ,该对象可以使用InetSocketAddress 来创建.
服务端
public class UdpEchoServer {//首先定义一个 socket 对象, 通过 socket 对象来发送读取信息private DatagramSocket socket = null;//绑定一个端口, 如果绑定的端口被别的进程占用了, 这里就会报错.//同一个主机上, 一个端口只能被一个进程绑定.public UdpEchoServer(int port) throws SocketException {//构造时, 指定要绑定的端口号.socket = new DatagramSocket(port);}//启动服务器的主逻辑public void start() throws IOException {System.out.println("服务器启动!!!");//因为服务器是要时刻读取客户端信息的, 所以使用while循环来重复读取并处理信息.while(true) {//每次循环都只做三件事// 1.读取请求并解析// 下面这是构造一个数据包, 就可以理解为一个餐盘, 这个餐盘里指定要放入的数据类型及大小// 空的餐盘构建好了就得装东西了DatagramPacket requestPacket = new DatagramPacket(new byte[666], 666); // 1kb=1024byte, UDP最多发送64kb(包含UDP首部8byte)// 通过 socket 对象来接收信息(也就是填充餐盘)socket.receive(requestPacket); //如果没接收到信息就会阻塞等待// 为了方便我们处理这个请求, 将数据包转为 StringString request = new String(requestPacket.getData(),0, requestPacket.getLength());// 2.根据请求来计算响应(这里直接返回了)String response = process(request);// 3.把响应结果写回客户端// 根据 response 来构造一个 DatagramPacket// 和之前构造不同, 本次构造相当于将餐盘填满, 注意还要指定发送给谁// requestPacket.getSocketAddress()是获取客户端的IP和端口号(填充的 requestPacket 就包含了客户端的IP和地址)DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestPacket.getSocketAddress());// 把结果发送给客户端socket.send(responsePacket);//打印一下客户端的IP和端口号, 还有请求和响应System.out.printf("[%s : %d] req: %s, resp: %s\n", requestPacket.getAddress().toString(),requestPacket.getPort(), request, response);}}//根据请求计算响应public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer echoServer = new UdpEchoServer(8888);echoServer.start();}
}
客户端
public class UdpEchoClient {//客户端也需要 socket 对象来进行数据交互private DatagramSocket socket = null;private String serverIP;private int serverPort;//构造客户端时, 还需要知道服务器在哪, 才能去获取服务public UdpEchoClient(String serverIP, int serverPort) throws SocketException {//不同与服务器, 这里没有关联端口, 不代表不需要关联端口//而是系统会自动为客户端分配个空闲的端口socket = new DatagramSocket();this.serverIP = serverIP;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("启动客户端!!!");//通过 Scanner 来读取用户输入Scanner scanner = new Scanner(System.in);while(true) {// 1.先从控制台读取一个字符串// 打印一个提示符, 提示用户输入System.out.print("-> ");String request = scanner.next();// 2.把字符串构造成 UDP packet, 并进行发送// InetAddress.getByName() 确定主机的IP地址DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIP), serverPort);socket.send(requestPacket);// 3.客户端尝试读取服务器返回的响应DatagramPacket responsePacket = new DatagramPacket(new byte[666],666);socket.receive(responsePacket);String response = new String(responsePacket.getData(),0,responsePacket.getLength());System.out.printf("req: %s, resp: %s\n", request,response);}}public static void main(String[] args) throws IOException {UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",8888);udpEchoClient.start();}
}
启动看看效果 :
客户端 :
服务端 :
UDP 版本的字典客户端和字典服务器
要想实现单词查找功能, 首先要有一个数据结构来对单词进行存储, 一般用哈希表来存储, key 来存储单词, value 存储单词意思.
其实客户端都是一样的, 只是服务器根据请求, 返回的响应不一样了.
所以我们主要就是重写 process 方法.
服务端 :
public class UdpDictServer extends UdpEchoServer{private HashMap<String,String> dict = new HashMap<>();public UdpDictServer(int port) throws SocketException {super(port);dict.put("pen","笔");dict.put("dog","狗");dict.put("cat","猫");//...可以无限添加, 其实网上的翻译词典什么的,就是样本比这个大}@Overridepublic String process(String request) {return dict.getOrDefault(request,"未找到该单词.");}public static void main(String[] args) throws IOException {UdpDictServer udpDictServer = new UdpDictServer(8888);udpDictServer.start();}
}
客户端 :
服务端 :
TCP 版的回显服务器
需要用到的 api
- ServerSocket API
ServerSocket 是创建TCP服务端 Socket 的 API (给服务器用的)
ServerSocket 一定要绑定具体端口号. (服务器得绑定的端口号才能提供服务)
主要用到的构造方法 :
ServerSocket(int port)
创建一个服务端流套接字Socket,并绑定到指定端口.
主要用到的方法 :
Socket accept()
开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端 Socket 对象,并基于该Socket建立与客户端的连接,否则阻塞等待.
void close()
关闭此套接字 (大多情况下, ServerSocket 的生命周期都会跟随整个程序, 所以不调 close 也问题不大)
accept 就是接受的意思.
客户端主动发起连接, 服务端被动接受连接.
其实 tcp 的连接是在内核就完成了的, 这里的 accept 是应用层层面的接受, 并返回一个 Socket 对象, 通过这个对象就可以与客户端进行交互了.
- Socket API
Socket 即会给服务端用, 也会给客户端用.
不管是客户端还是服务端Socket,都是双方建立连接以后,保存对端信息,用来与对方收发数据的。
Socket 和 DatagramSocket 类似, 都是构造的时候指定一个具体的端口, 让服务器绑定该端口.
主要用到的构造方法 :
Socket(String host, int port)
两个参数表示 ip 和 端口号, TCP是有连接的, 在客户端 new Socket 时, 就会尝试和指定 ip 端口的目标建立连接.
主要用到的方法 :
InetAddress getInetAddress()
返回套接字所连接的地址
InputStream getInputStream()
返回此套接字的输入流
OutputStream getOutputStream()
返回此套接字的输出流
void close()
关闭此套接字
TCP 是面向字节流的, 所以我们可以通过上述字节流对象进行数据传输.
从 InputStream 读数据, 就相当于从网卡接收.
往 OutputStream 写数据, 就相当于从网卡发送.
服务器
public class TcpEchoServer {// serverSocket 就是外场拉客的小哥哥// serverSocket 只有一个.private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {// 服务器不止是对一个客户端进行服务// 加上 while 循环, 是让服务器随时可以获取到新的客户端的请求连接while(true) {// clientSocket 就是内场服务的小姐姐.// clientSocket 会给每个客户端都分配一个.(可以通过它来获取客户端的信息)Socket clientSocket = serverSocket.accept();// 我们对多客户端的交互应该是并行的// 所以创建线程来对每个客户端进行响应Thread t = new Thread(() -> {try {// 该方法就是对客户端进行交互了processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}});t.start();}}private void processConnection(Socket clientSocket) throws IOException {// 提醒客户端已上线.System.out.printf("[%s : %d] 客户端已上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());// 将输入,输出流放入 try() 中, 可以不用考虑资源释放.// 通过 clientSocket 获得输入, 输出流.try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {// 因为 tcp 是面向字节流的, 所以为了方便读取, 给输入流套一个外壳// Scanner 是面向字符流.Scanner scanner = new Scanner(inputStream);// 同样的, 为了方便写入, 给输出流套一个壳// PrintWriter 是面向字符流PrintWriter printWriter = new PrintWriter(outputStream);// 因为服务器与客户端交互不是一次就完了, 所以得加个循环while(true) {// 判断是否还有数据在输入流中,如果没有了就认为客户端下线了,退出循环if(!scanner.hasNext()) {System.out.printf("[%s : %d] 客户端已下线!\n",clientSocket.getInetAddress(),clientSocket.getPort());break;}// 通过 scanner 读取网卡(客户端的请求)String request = scanner.next();// 通过请求计算响应String response = process(request);// 将响应写入缓存区, 当缓存区满了 就会写入网卡// 因为 Scanner 读取是不会读空格和回车的// 所以写入的时候要加换行, 以便客户端区分请求和响应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 {// 因为 clientSocket 在客户端下线后就没用了,所以要释放// serverSocket 之所以不要释放, 是因为它的生命周期伴随整个程序// 程序结束, 它自然被释放了clientSocket.close();}}//计算响应public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(8080);tcpEchoServer.start();}
}
客户端
public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIP, int port) throws IOException {// 这个操作相当于让客户端和服务器建立 tcp 连接.// 这里的连接连上了, 服务器的 accept 就会返回.socket = new Socket(serverIP,port);}public void start() {// 这个 scanner 是用来读取用户输入内容的Scanner scanner = new Scanner(System.in);try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {PrintWriter printWriter = new PrintWriter(outputStream);// 这里的 scannerFromSocket 是用来读取网卡(服务器响应)Scanner scannerFromSocket = new Scanner(inputStream);// 通过循环来对服务器进行多次请求while(true) {// 提示用户输入System.out.printf("-> ");// 读取键盘输入String request = scanner.next();// 将键盘输入写入缓存, 当缓存满了就自动刷新 并写入网卡// 注意带回车, 不然服务器读不到空白符,会一直读printWriter.println(request);// 手动刷新缓存, 将数据写入网卡printWriter.flush();// 读取服务器写入网卡的响应String response = scannerFromSocket.next();System.out.printf("req: %s resp: %s\n", request,response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1", 8080);tcpEchoClient.start();}
}
服务端 :
客户端 :
当然了, 我们还可以多启动几个客户端, 与服务器进行交互.
服务端 :
对服务器进行改进(使用线程池)
这里主要是修改 start 方法里的线程创建, 就单独拿出来修改 :
public void start() throws IOException {while(true) {ExecutorService executorService = Executors.newCachedThreadPool();Socket clientSocket = serverSocket.accept();executorService.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}}});}}
效果还是一样的.
TCP 版本的字典客户端和字典服务器
其实和 UDP 版的基本一样, 只需要对服务端进行修改 :
public class TcpDictServer extends TcpEchoServer{private HashMap<String,String> dict = new HashMap<>();public TcpDictServer(int port) throws IOException {super(port);dict.put("pen","笔");dict.put("dog","狗");dict.put("cat","猫");}public String process(String request) {return dict.getOrDefault(request,"未找到该单词");}public static void main(String[] args) throws IOException {TcpDictServer tcpDictServer = new TcpDictServer(8080);tcpDictServer.start();}
}
相关文章:

简单实现基于UDP与TCP的回显服务器
目录 前言UDP 版的回显服务器需要用到的 api服务端客户端UDP 版本的字典客户端和字典服务器 TCP 版的回显服务器需要用到的 api服务器客户端对服务器进行改进(使用线程池)TCP 版本的字典客户端和字典服务器 前言 我们写网络程序, 主要编写的是应用层代码. 真正要发送这个数据,…...

家用洗地机有什么推荐的吗?家用洗地机哪款好
洗地机是创新、高效的清洁工具,其具有高性能的清洁能力和卓越的操作体验。与传统的清洁工具相比,洗地机可以迅速而彻底地打扫地面,降低清洁时间和人力成本,让我们在工作之余不用花费大量的时间和精力去打扫卫生,下面就…...

深度学习与文本聚类:一篇全面的介绍与实践指南
❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...

AP5153 线性降压恒流驱动芯片 2.5A
AP5153 是一种 PWM 调光的、低压 差的 LED 线性降压恒流驱动器。 AP5153 仅需要外接一个电阻和一个 NMOS 管就可以构成一个完整的 LED 恒 流驱动电路, 调节该外接电阻就可以调节 输出电流,输出电流可调范围为 20mA 到 3.0A。 AP5153 还可以通过在 DIM…...

Unity物理系统脚本编程(下)
一、修改物理材质 Unity对物体表面材料的性质做了件化处理,仅有5种常用属性: Dynamic Friction(动态摩擦系数)Static Friction(静态摩擦系数)Bounciness(弹性系数)Friction Combine…...

容器技术的发展
容器技术的发展 近年来,随着计算机硬件、网络以及云计算等技术的迅速发展,云原生的概念也越来越受到业界人士的广泛关注,越来越多的应用场景开始拥抱云原生,其中容器技术的发展起着至关重要的作用。本章将介绍容器技术的基础知识…...

Python Flask request中常见存储参数的介绍
Python Flask request中常见存储参数的介绍 首先从flask模块中导入请求对象: from flask import requestrequest.form 通过method属性可以操作当前请求方法,通过使用form属性处理表单数据(本质也是得到一个字典,如果传输的是字…...

php+vue网盘系统的设计与实现
该网盘系统的开发和设计根据用户的实际情况出发,对系统的需求进行了详细的分析,然后进行系统的整体设计,最后通过测试使得系统设计的更加完整,可以实现系统中所有的功能,在开始编写论文之前亲自到图书馆借阅php书籍&am…...

[前端]深浅拷贝
一、回顾变量类型 基础类型 boolean(bool) number string null undefined 引用类型 object function array 基本类型与引用类型的存储 基本类型一般存储在 栈 (栈小) 栈一旦确认 大小就固定 可能会造成溢出栈一般是先进后出用于存储…...

文章纠错免费软件-文字校对软件免费下载
自动校对稿件的软件 自动校对稿件的软件是一种基于自然语言处理(Natural Language Processing, NLP)和机器学习(Machine Learning)技术的工具,可以较为准确地检测和纠正文本中出现的语法、拼写、标点符号以及其他笔误…...

【Redis】Redis缓存雪崩、缓存穿透、缓存击穿(热key问题)
目录 一、缓存穿透 1、概念 2、解决办法 1.缓存空对象 2.布隆过滤 二、缓存雪崩 1、概念 2、解决办法 1.给key设置随机的过期时间TTL 2.业务添加多级缓存 3.利用集群提供服务可用性 4.缓存业务添加降级限流 三、缓存击穿 1、概念 2、解决办法 1.互斥锁 2.逻辑…...

为什么很多程序员喜欢linux系统?
a> Linux哪些行业在运用? Linux系统运用极其广泛,不少用户只知道windows,是因为,Linux的运用主要是在企业端。现在科技极其发达,我们手机在手,就能干很多事情,只需点一点屏幕,轻松…...

Bean 作用域和生命周期
✏️作者:银河罐头 📋系列专栏:JavaEE 🌲“种一棵树最好的时间是十年前,其次是现在” 目录 lombok的使用案例引入作用域定义singleton单例作用域prototype原型作用域(多例作用域)request请求作用域session会话作用域ap…...

PMP考试常见13个固定套路
一、变更批准之后 变更批准后要做三件事: 1、在变更日志中记录 2、通知相关干系人 3、更新项目管理计划 二、风险的情景题 1、先判断风险识别了,还是风险发生了。 2、若是风险识别,按风险管理程序走; 3、若是风险发生,则应采取应急措施…...

Leecode101 ——对称二叉树
对称二叉树:Leecode 101 leecode 101 对称二叉树 根据题目描述,首先想清楚,对称二叉树要比较的是哪两个节点。对于二叉树是否对称,要比较的是根节点的左子树与根节点的右子树是不是相互翻转的,其实也就是比较两个树,…...

JVM学习随笔03——Java堆中new一个对象的步骤
目录 一、进行类加载 二、堆中分配内存 1、怎么输出GC日志: 2、内存分配的两种方式: 3、内存分配过程中并发控制的两种方式: 三、内存空间初始化 四、对象头初始化(对象头包含哪些信息?) 五、执行构…...

虹科方案 | CEMEX 使用HK-Edgility 智能边缘计算平台简化其企业 WAN 管理和运营
一、应对价值 130 亿美元的跨国企业的网络挑战 “我们选择 Edgility 是因为其卓越的管理和协调功能,它为我们提供了一个端到端的工具集,可以经济高效地部署和管理我们边缘设备的生命周期。” —— Fernando Garcia -Villaraco Casero, CEMEX 全球IT 战略…...

rk3568 系统移植和编译
1。 硬件问题 尽量根据原版 evb 开发版 pcb 进行布线和移植,切记不可自行走线。 emmc 和 ddr4 选型都有要求的,按照硬件手册进行设计 2。软件问题 2.1 目前固件系统选用1.3.2 版本进行设计 解压后运行 .repo/repo/repo sync -c 更新代码 2.2 ubo…...

深度解析C++异常处理机制:分类、处理方式、常见错误及11新增功能
C 基础知识 八 异常处理 上篇 一、基础1. 异常的概念2. 异常的分类2.1 内置异常2.2 自定义异常 3. 异常的处理方式3.1 try-catch 语句3.2 throw 语句3.3 noexcept 修饰符3.4 finally 语句块 二、 异常处理机制1 try-catch 语句块2 异常处理流程3 标准异常类 三、 抛出异常1 thr…...

FPGA时序约束(四)主时钟、虚拟时钟和时钟特性的约束
系列文章目录 FPGA时序约束(一)基本概念入门及简单语法 FPGA时序约束(二)利用Quartus18对Altera进行时序约束 FPGA时序约束(三)时序约束基本路径的深入分析 文章目录 系列文章目录前言主时钟约束跨时钟域…...

JNI开发
文件结构(选中的为生成的) CMake构建不需要执行命令,会自动生成so文件打包进apk Android mk构建需要执行命令生成so文件,再打包进apk。命令如下。 # 在jni目录下执行 # 生成com_demo_cppproject_OtherNdkTest.h头文件 javac -h .…...

JAVA有哪些特点?
JAVA有以下特点: 综上所述,Java作为一种先进的面向对象编程语言,具有简单、可移植、健壮、高性能、多线程、动态性、跨平台、开放性和安全性等众多特点,已经成为广泛使用的编程语言之一。 简单易学:JAVA语言的语法与C语…...

使用读写锁提高并发
我们想要的是:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待。 ReadWriteLock ReadWriteLock的作用: 只允许一个线程写入(其他线程既不能写入也不能读取);没有写入时…...

使用@PropertySource加载配置文件
1.PropertySource和PropertySources注解 1.1.PropertySource注解概述 PropertySource注解是Spring 3.1开始引入的配置类注解。通过**PropertySource注解可以将properties配置文件中的key/value存储到Spring的Environment中,Environment接口提供了方法去读取配置文…...

事务及分布式事务解决方案
基础概念 1.1.事务 事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败。 1.2.本地事务 在计算机系统中,更多的是通过关系型数据库来控制事务,利用数据库本身的事务特性来实现&a…...

【思科、华为、华三、锐捷网络设备巡检命令】
华三 screen-1ength disable 取消分页 displayversion 查看版本 displayclock 查看日期时钟 displayfan 查看风扇状态 displaypower 查看电源信息 displaycpu-usage 查看CPU利用率 displaymemory 查看内存利用率 display environment 查看温度信息 display device 查看设备信息…...

代码随想录算法训练营第五十二天
代码随想录算法训练营第五十二天| 300.最长递增子序列,674. 最长连续递增序列,718. 最长重复子数组 300.最长递增子序列674. 最长连续递增序列718. 最长重复子数组 300.最长递增子序列 题目链接:最长递增子序列 这里是不用处理if nums[i] &l…...

【Linux网络】传输层中UDP和TCP协议
文章目录 1、再谈端口号2、UDP协议3、TCP协议3.1 TCP协议段格式3.2 TCP的三次握手和四次挥手(连接管理机制)3.3 TCP的滑动窗口3.4 TCP的流量控制3.5 拥塞控制3.6 延迟应答和捎带应答3.7 面向字节流和粘包问题3.8 TCP总结 1、再谈端口号 端口号port标识一…...

工具︱ Web3加密浏览器Brave有什么特别之处?
使用浏览器来上网访问和获取各种信息和资源已经成为传统互联网民的普遍活动,下一代互联网协议Web3的核心特点是去中心化,即不依赖于中心化的服务器和数据中心,而是通过分布式的网络节点来实现数据存储和传输。 浏览器承载着信息网络与用户需求…...

绝对不能错过这份沃尔玛实用插件工具大全
龙哥最近发现很多跨境卖家都比较少运营沃尔玛这个平台。沃尔玛除了是世界500强之外,它的线上商城也弄得很好。它的电商平台主要是售卖自营的,然后你也可以入驻来卖自己的产品,就像是我们国内的京东一样。今天龙哥就给大家分享一些沃尔玛专用插…...