回显服务器的制作方法
文章目录
- 客户端和服务器
- TCP和UDP的特点
- UDP socket api的使用
- DatagramSocket
- DatagramPacket
- InetSocketAddress API
- 做一个简单的回显服务器
- UDP版本的回显服务器
- TCP版本的回显服务器
客户端和服务器
在网络中,主动发起通信的一方是客户端,被动接受的这一方叫做服务器。
- 客户端给服务器发送的数据是请求(request)
- 服务器给客户端返回的数据叫响应(response)
客户端和服务器的交互有多种模式
- 一问一答: 一个请求对应一个响应 。多在网站开发中用到
- 一问多答:一个请求对应多个相应。主要涉及“下载”的场景中
- 多问一答:多个请求队对应一个响应 。涉及到“上传”的场景中
- 多问多答:多个请求对应多个响应。用到“远程控制”和“远程桌面”中
TCP和UDP的特点
要想进行网络编程,需要使用系统的api,本质上是传输层提供的。传输层用到的协议主要是TCP和UDP。这两个协议的差别挺大,所提供的api也有一定的差别。先从本质上看看TCP和UDP的特点有哪些差别。
- TCP的特点是 有连接,可靠传输,面向字节流,全双工。
- UDP的特点是 无连接,不可靠传输,面向数据报,全双工。
有连接/无连接
举个例子,打电话,需要对方同意后才能打通电话,打电话的过程需要对方确认接听或者不接听,连接的特点就是双方都能认同,而无连接的规则向发微信,自己只管发送,不用在意对方是否同意接收。同理,计算机中的网络连接,就是通信双方,各自保存对方的信息,客户端就有一些数据结构,记录了谁是自己的服务器,服务器也有一些数据结构,记录了谁是自己的客户端。可靠传输/不可靠传输
网络上存在异常情况是非常多的,无论使用什么硬件技术都无法100%保证数据能从A发送到B。此处所说的可靠传输是指尽可能的完成数据传输,即不管数据有没有传输到,A都能清楚的知道。面向字节流/面向数据报
此处提到的字节流和文件中的字节流是一样的。网络中传输数据的基本单位就是字节。
面向数据报:每次传输的基本单位是一个数据报(有一系列字节构成的)特定的结构。全双工/半双工
一个信道可以双向通信,是全双工。只能单向通信是半双工。
UDP socket api的使用
socket api的中文意思是"网络编程套接字",操作系统中有一类文件叫socket文件,它抽象了网卡这样的硬件设备,而进行网络通信最核心的硬件设备就是网卡,通过网卡发送数据就是写socket文件,通过网卡接收数据就是读socket文件。在UDP中,核心的api有两个类,分别是DatagramSocket和DatagramPacket。下面看看这两个类的使用和注意事项。
DatagramSocket
这个类的作用主要是对soclet文件的读写,也就是借助网卡发送接收数据。接收发送接收数据的单位就是DatagramSocket.。
datagramSocket的构造方法
DatagramSocket的方法
DatagramPacket
UDP是面向数据报的,每次发送接收数据的基本单位,就是一个udp数据报,此时表示了一个UDP数据报
DatagramPacket的构造方法
DatagramPacket方法
InetSocketAddress API
做一个简单的回显服务器
UDP版本的回显服务器
回显服务器是客户端发送什么请求,服务器就返回什么响应。做这个服务器的目的是学习UDP socket
api的使用和理解网络编程中客户端和服务器的基本工作流程
服务器的基本逻辑
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}// 服务器的启动逻辑.public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 每次循环, 就是处理一个请求-响应过程.// 1. 读取请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// 读到的字节数组, 转成 String 方便后续的逻辑处理.String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 根据请求计算响应 (对于 回显服务器来说, 这一步啥都不用做)String response = process(request);// 3. 把响应返回到客户端.// 构造一个 DatagramPacket 作为响应对象DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);// 打印日志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 server = new UdpEchoServer(9090);server.start();}
}
首先创建DatagramSocket对象,接下来要使用socket对象来操作网卡。在创建对象的时候需要手动指定端口。在网络编程中,服务器一般需要手动指定端口,而客户端一般不需要。一个主机的一个端口只能被一个进程绑定,而一个进程可以绑定多个端口。
一个服务器一般都是24时运行的,直接使用while(true)可以不用退出。很多时候要重启一个服务器可以直接杀死进程。
此处 receive就从网卡能读取到一个 UDP 数据报就被放到了 requestPacket 对象中其中 UDP 数据报的载荷部分就被放到 requestPacket 内置的字节数组中了。另外报头部分,也会被 requestPacket 的其他属性保存。除了 UDP 报头之外,还有其他信息,比如收到的数据源 IP 是啥
通过 requestPacket 还能知道数据从哪里来的(源 ip 源端口)基于字节数组构造出 String字节数组里面保存的内容也不一定就是二进制数据,也可能是文本数据把文本数据交给 String 来保存,恰到好处~~
这里得到的长度是 requestPacket 中的有效长度,不一定是 40964096 是最大长度。一定是要使用有效长度来构造这里的 String使用最大长度就会生成一个非常长的 String 后半部分都是空白。通过process()方法构造响应,这是一个回显服务器,直接返回请求就可以。
通过requestPacket.getSocketAddress())获得对应客户端的ip和端口。是把请求的源ip和源端口作为响应的目的ip和目的端口。
总结
- 上述代码中,可以看到,UDP 是无连接的通信 UDP socket 自身不保存对端的IP 和端口.而是在每个数据报中有一个~.另外代码中也没有“建立连接”"接受连接”操作
- 不可靠传输,代码中体现不到的.
- 面向数据报,send和receive 都是以 DatagramPacket 为单位
- 全双工:一个 socket 既可以发送又可以接收
客户端的基本逻辑
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;// 此处 ip 使用的字符串, 点分十进制风格. "192.168.2.100"public UdpEchoClient(String serverIp, int serverPort) throws SocketException {//请求的目的IP和目的端口this.serverIp = serverIp;this.serverPort = serverPort;socket = new DatagramSocket();}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while (true) {// 要做四个事情System.out.print("-> "); // 表示提示用户接下来要输入内容.// 2. 从控制台读取要发送的请求数据.if (!scanner.hasNext()) {break;}String request = scanner.next();// 3. 构造请求并发送.DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 4. 读取服务器的响应.DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 5. 把响应显示到控制台上.String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);client.start();}
}
三种DatagramSocket对象的构造方法
网络通信的基本流程
- 服务器启动.启动之后,立即进入 while 循,执行到 receive,进入阻塞,此时没有任何客户端发来请求呢。
- 客户端启动.启动之后,立即进入 while 循环,执行到 hasNext 这里进入阻塞,此时用户没有在控制台输入任何内容
- 用户在客户端的控制台中输入字符串,按下回车此时 hasNext 阻塞解除,next 会返回刚才输入的内容基于用户输入的内容,构造出一个 DatagramPacket 对象,并进行 send 。send执行完毕之后,继续执行到
reeive 操作,等待服务器返回的响应数据此时服务器还没返回响应呢,这里也会阻塞)- 服务器收到请求之后,就会从 receive 的阻塞中返回返回之后,就会根据读到的 DataqramPacket 对象,构造 String request, 通过 process 方法构造一个 String response再根据 response 构造一个
DatagramPacket表示响应对象, 再通过 send 来进行发送给客户端。执行这个过程中,客户端也始终在阻塞等待- 客户端从 receive 中返回执行.就能够得到服务器返回的响应并且打印倒控制台上于此同时,服务器进入下一次循环,也要进入到第二次的 receive 阳塞等待下个请求了
TCP版本的回显服务器
tcp中的长短连接
TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:
- 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
- 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。
对比以上长短连接,两者区别如下:
- 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
- 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
- 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于 客户端与服务端通信频繁的场景,如聊天室,实时游戏等服务器的处理逻辑。
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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;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("服务器启动!");ExecutorService pool = Executors.newCachedThreadPool();while (true) {// 通过 accept 方法来 "接听电话", 然后才能进行通信Socket clientSocket = serverSocket.accept();
// Thread t = new Thread(() -> {
// processConnection(clientSocket);
// });
// t.start();pool.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}// 通过这个方法来处理一次连接. 连接建立的过程中就会涉及到多次的请求响应交互.private void processConnection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());// 循环的读取客户端的请求并返回响应.try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {while (true) {Scanner scanner = new Scanner(inputStream);if (!scanner.hasNext()) {// 读取完毕. 客户端断开连接, 就会产生读取完毕.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}// 1. 读取请求并解析. 这里注意隐藏的约定. next 读的时候要读到空白符才会结束.// 因此就要求客户端发来的请求必须带有空白符结尾. 比如 \n 或者空格.String request = scanner.next();// 2. 根据请求计算响应String response = process(request);// 3. 把响应返回给客户端// 通过这种方式可以写回, 但是这种方式不方便给返回的响应中添加 \n// outputStream.write(response.getBytes(), 0, response.getBytes().length);// 也可以给 outputStream 套上一层, 完成更方便的写入.PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress(), clientSocket.getPort(),request, response);}} catch (IOException e) {throw new RuntimeException(e);} finally {try {clientSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}
- 在服务器代码中,ServerSocket是创建服务端Socket的api。Socket是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket.
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。- 当客户端发送请求的时候,内核就会发起建立连接的请求,服务器的内核会配合客户端的工作来建立连接,而内核的连接不是决定性的,还需要应用程序把这个连接接受,通过accept方法来接受连接。accept方法方法是会阻塞等待的,当没有客户端发起请求的时候此时就会阻塞。
- 上面的操作也表现出Tcp是有连接的。
- Tcp是面向字节流的。这里的字节流和文件中的字节流完全一致。使用和文件操作一样的类和方法来针对Tcp Socket的读和写。
- InputStream是往网卡上读数据,OutputStream是往网卡上写数据。
客户端的处理逻辑
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {// 此处可以把这里的 ip 和 port 直接传给 socket 对象.// 由于 tcp 是有连接的. 因此 socket 里面就会保存好这俩信息.// 因此此处 TcpEchoClient 类就不必保存.socket = new Socket(serverIp, serverPort);}public void start() {System.out.println("客户端启动!");try (InputStream inputStream = socket.getInputStream()) {try (OutputStream outputStream = socket.getOutputStream()) {Scanner scannerConsole = new Scanner(System.in);Scanner scannerNetwork = new Scanner(inputStream);PrintWriter writer = new PrintWriter(outputStream);while (true) {// 这里的流程和 UDP 的客户端类似.// 1. 从控制台读取输入的字符串System.out.print("-> ");if (!scannerConsole.hasNext()) {break;}String request = scannerConsole.next();// 2. 把请求发给服务器. 这里需要使用 println 来发送. 为了让发送的请求末尾带有 \n// 这里是和服务器的 scanner.next 呼应的.writer.println(request);// 通过这个 flush 主动刷新缓冲区, 确保数据真的发出去了.writer.flush();// 3. 从服务器读取响应. 这里也是和服务器返回响应的逻辑对应.String response = scannerNetwork.next();// 4. 把响应显示出来System.out.println(response);}}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();}
}
在TCP回显服务器中,需要注意下面几种情况
- 在上面代码中,PrintWriter中内置了缓冲区,IO操作都是很低效的,为了让低效的操作少一些,会引入一个缓冲区,先把写入网卡的数据王道缓冲区中,等达到一定的数量在一次发送出去,但如果发送的数据太少,缓冲区没有满,可能导致数据发送不出去,使用flush方法可以冲刷缓冲区,确保每条消息都能发送出去。
- ServerSocket在整个程序中,只有唯一一个对象,并且这个对象的生命周期伴随着整个程序,这个对象无法提前关闭,只有程序结束,随着进程的销毁一起结束。而clientSocket是每个客户端一个,随着客户端越来越多,如果不释放可能会占满文件描述符表。需要使用close方法关闭。
- 解决多个客户端向一个服务器发送请求的问题
上面的问题核心思路就是使用多线程,单个线程无法及给客户端提供服务,又能快速调用第二次accept,使用多线程,主线程就负责执行accept,其他线程就负责给客户端提供服务。如果客户端比较多就会频繁的创建销毁线程,就可以使用线程池解决频繁创建销毁线程的问题。
相关文章:

回显服务器的制作方法
文章目录 客户端和服务器TCP和UDP的特点UDP socket api的使用DatagramSocketDatagramPacketInetSocketAddress API 做一个简单的回显服务器UDP版本的回显服务器TCP版本的回显服务器 客户端和服务器 在网络中,主动发起通信的一方是客户端,被动接受的这一方…...

w28DVWA-csrf实例
DVWA-csrf实例 low级别 修改密码:修改的密码通过get请求,暴露在url上。 写一个简单的html文件,里面伪装修改密码的文字,代码如下: <html><body><a href"http://dvwa:7001/vulnerabilities/csr…...
子网络划分与互通,上网行为审计
网络环境需求:在办公网络环境中,由于公司部门的划分,以及服务器、电脑、手机等设备类型,一般都需要划分多个网段,便于进行网络管理,并提升网络通信效率。各个子网段管理员控制设备的接入,子网段之间需要进行局域网通信,发送消息和文件,通常使用飞秋。服务器网段,禁止…...
如何快速删除node_module依赖包
利用npm:输入 npm install rimraf -g rimraf node_modules...
async/await 的用法
一、async和await定义 async 是异步的意思,而 await 是等待的意思,await 用于等待一个异步任务执行完成的结果。 1.async/await 是一种编写异步代码的新方法(以前是采用回调和 promise)。 2. async/await 是建立在 promise 的基础…...

JAVA面试汇总总结更新中ing
本人面试积累面试题 基础RocketMQSpring登录技能操作线程事务微服务JVMKAFKAMYSQLRedislinux 基础 1.面向对象的三个特征 封装,继承,多态,有时候也会加上抽象。 2.多态的好处 允许不同类对象对同一消息做出响应,即同一消息可以根…...

vue-利用属性(v-if)控制表单(el-form-item)显示/隐藏
表单控制属性 v-if 示例: 通过switch组件作为开关,控制表单的显示与隐藏 <el-form-item label"创建数据集"><el-switch v-model"selectFormVisible"></el-switch></el-form-item><el-form-item label&…...

数据结构-邻接矩阵
介绍 邻接矩阵,是表示图的一种常见方式,具体表现为一个记录了各顶点连接情况的呈正方形的矩阵。 假设一共有以下顶点,其连接关系如图所示 那么,怎么表示它们之间的连接关系呢? 我们发现,各条边所连接的都…...

基于CNN-GRU-Attention的时间序列回归预测matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 CNN(卷积神经网络)部分 4.2 GRU(门控循环单元)部分 4.3 Attention机制部分 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版…...

Docker部署Halo容器并结合内网穿透实现公网访问本地个人博客
文章目录 1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤:1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 本文主要介绍如何在CentOS 7系统使…...
纯css实现文字左右循环滚动播放效果
思路:由两个span模块组成,第一个为空的span内容,为的是实现第二个span内容缓慢出现的效果。 代码如下: <div class"scrollingStyle"><span class"first-marquee"></span><span class&q…...

【Java EE初阶二十二】https的简单理解
1. 初识https 当前网络上,主要都是 HTTPS 了,很少能见到 HTTP.实际上 HTTPS 也是基于 HTTP.只不过 HTTPS 在 HTTP 的基础之上, 引入了"加密"机制;引入 HTTPS 防止你的数据被黑客篡改 ; HTTPS 就是一个重要的保护措施.之所以能够安全, 最关键的…...
系统学习Python——装饰器:类装饰器-[跟踪对象接口:基础知识]
分类目录:《系统学习Python》总目录 文章《系统学习Python——装饰器:类装饰器-[单例类:基础知识]》的单例示例阐明了如何使用类装饰器来管理一个类的所有实例。类装饰器的另一个常用场景是为每个生成的实例扩展接口。类装饰器基本上可以在实…...
go-redis 使用 redis 6.0.14 版本错误: consider implementing encoding.BinaryMarshaler
使用方法 err : bp.data.redis.Get(ctx, policyKey).Scan(&result)起初在 redis 5.x.x 版本并没有遇到错误,但是在切换 redis 实例之后就出现了错误(他们之间只是版本不同)。 修复方法 看错误日志的描述,大概含义就是需要我们…...

计网 - 域名解析的工作流程
文章目录 Pre引言1. DNS是什么2. 域名结构3. 域名解析的工作流程4. 常见的DNS记录类型5. DNS安全6. 未来的发展趋势 Pre 计网 - DNS 域名解析系统 引言 在我们日常使用互联网时,经常会输入各种域名来访问网站、发送电子邮件或连接其他网络服务。然而,我…...

普中51单片机学习(EEPROM)
EEPROM IIC串行总线的组成及工作原理 I2C总线的数据传送 数据位的有效性规定 I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许…...
智能风控体系之供应链业务模式
供应链金融是一种针对中小企业的新型融资模式,将资金流有效整合到供应链管理的过程中,既为供应链各环节企业提供贸易资金服务,又为供应链弱势企业提供新型贷款融资服务,以核心客户为依托,以真实贸易背景为前提…...
最少停车数(C 语言)
题目描述 特定大小的停车场,数组cars[]表示,其中1表示有车,0表示没车。车辆大小不一,小车占一个车位(长度1),货车占两个车位(长度2),卡车占三个车位…...

MAC M1安装vmware和centos7虚拟机并配置静态ip
一、下载vmware和centos7镜像 1、VMWare Fusion 官网的下载地址是:下载地址 下载好之后注册需要秘钥,在官网注册后使用免费的个人秘钥 2、centos7 下载地址: https://biosyxh.cn:5001/sharing/pAlcCGNJf 二、虚拟机安装 直接将下…...

java 课程签到管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目
一、源码特点 java 课程签到管理系统是一套完善的java web信息管理系统 采用serlvetdaobean,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发࿰…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...

一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...