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

Java网络编程原理与实践--从Socket到BIO再到NIO

文章目录

  • Java网络编程原理与实践--从Socket到BIO再到NIO
    • Socket基本架构
    • Socket 基本使用
      • 简单一次发送接收
        • 客户端
        • 服务端
      • 字节流方式简单发送接收
        • 客户端
        • 服务端
      • 双向通信
        • 客户端
        • 服务端
      • 多次接收消息
        • 客户端
        • 服务端
    • Socket写法的问题
    • BIO
      • 简单流程
      • BIO写法
        • 客户端
        • 服务端
      • BIO的问题
    • NIO
      • 简述
      • Buffer
      • Channel(通道)
      • Selector(选择器)
        • 基本介绍
        • 使用实例

Java网络编程原理与实践–从Socket到BIO再到NIO

Socket基本架构

图来源:https://zhuanlan.zhihu.com/p/462497498
既然是网络的东西肯定得放个网络架构图,这张图不多说,感兴趣可以去链接详细看一下
在这里插入图片描述

Socket 基本使用

转自:https://blog.csdn.net/a78270528/article/details/80318571

简单一次发送接收

客户端
package Scoket.client;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;/**** 字符流方式*/
public class Client {public static void main(String[] args) {try {// 服务器的主机和端口String serverHost = "127.0.0.1";int serverPort = 6443;// 创建Socket对象,连接到服务器Socket socket = new Socket(serverHost, serverPort);// 获取输入流和输出流BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter output = new PrintWriter(socket.getOutputStream(), true);// 发送数据给服务器String messageToSend = "Hello, Server!";output.println(messageToSend);// 接收服务器的响应数据String dataReceived = input.readLine();System.out.println("Received from server: " + dataReceived);// 关闭连接socket.close();} catch (Exception e) {e.printStackTrace();}}
}
服务端
package Scoket.client;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) {try {// 本地主机和端口String serverHost = "127.0.0.1";int serverPort = 6443;// 创建ServerSocket对象,绑定地址和端口ServerSocket serverSocket = new ServerSocket(serverPort);System.out.println("Server listening on " + serverHost + ":" + serverPort);// 接受客户端连接Socket clientSocket = serverSocket.accept();System.out.println("Accepted connection from " + clientSocket.getInetAddress());// 获取输入流和输出流BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true);// 接收客户端发送的数据String dataReceived = input.readLine();System.out.println("Received from client: " + dataReceived);// 发送响应给客户端String messageToSend = "Hello, Client!";output.println(messageToSend);// 关闭连接clientSocket.close();serverSocket.close();} catch (Exception e) {e.printStackTrace();}}
}

如果进行debug会发现,服务端代码总共卡主两次:
1、 Socket clientSocket = serverSocket.accept(); 这里会监听端口,等待客户端请求建立连接,实际上是进行三次握手
2、 String dataReceived = input.readLine(); 这里是等待客户端发送数据,接收到数据会进行下一步
这两步骤需要注意,因为这是后面BIO和NIO的优化点

字节流方式简单发送接收

使用字节流处理,这可能使得处理字符串数据稍显繁琐。如果你的通信数据是文本,可能使用字符流更为方便。
但是数据更可控一些,下面简单罗列

客户端
package Scoket.client;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;/*** 字节流方式*/
public class Client1 {public static void main(String[] args) {try {String host = "127.0.0.1";int port = 6443;Socket socket = new Socket(host, port);OutputStream outputStream = socket.getOutputStream();String message = "message, 你好";socket.getOutputStream().write(message.getBytes(StandardCharsets.UTF_8));outputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
服务端
package Scoket.client;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server1 {public static void main(String[] args) {try {int port = 6443;ServerSocket serverSocket = new ServerSocket(port);System.out.println("等待连接");Socket accept = serverSocket.accept();System.out.println("完成连接,等待传输数据");InputStream inputStream = accept.getInputStream();byte[] bytes = new byte[1024];int len;StringBuilder sb = new StringBuilder();while ((len = inputStream.read(bytes)) != -1){sb.append(new String(bytes, 0, len, "UTF-8"));}System.out.println("get message:" + sb);inputStream.close();accept.close();serverSocket.close();} catch (IOException e) {e.printStackTrace();}}
}

双向通信

客户端
package Scoket.client;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class Client2 {public static void main(String[] args) {try {String host = "127.0.0.1";int port = 8443;Socket socket = new Socket(host, port);OutputStream outputStream = socket.getOutputStream();outputStream.write("我是客户,接受一下我的消息".getBytes(StandardCharsets.UTF_8));socket.shutdownOutput();InputStream inputStream = socket.getInputStream();byte[] bytes = new byte[1024];int len;StringBuilder stringBuilder = new StringBuilder();while ((len = inputStream.read(bytes)) != -1){stringBuilder.append(new String(bytes, 0, len, "UTF-8"));}System.out.println("get message:" + stringBuilder);inputStream.close();outputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
服务端
package Scoket.client;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class Server2 {public static void main(String[] args) {try {int port = 8443;ServerSocket serverSocket = new ServerSocket(port);Socket socket = serverSocket.accept();InputStream inputStream = socket.getInputStream();byte[] bytes = new byte[1024];int len ;StringBuilder sb = new StringBuilder();while ((len = inputStream.read(bytes)) != -1){sb.append(new String(bytes, 0, len, "UTF-8"));}System.out.println("server2 get Message:" + sb);OutputStream outputStream = socket.getOutputStream();outputStream.write("我是服务器".getBytes(StandardCharsets.UTF_8));inputStream.close();outputStream.close();socket.close();serverSocket.close();} catch (IOException e) {e.printStackTrace();}}
}

多次接收消息

客户端
package Scoket.client;import java.io.OutputStream;
import java.net.Socket;public class Client3 {public static void main(String args[]) throws Exception {// 要连接的服务端IP地址和端口String host = "127.0.0.1";int port = 8444;// 与服务端建立连接Socket socket = new Socket(host, port);// 建立连接后获得输出流OutputStream outputStream = socket.getOutputStream();String message = "你好  yiwangzhibujian";//首先需要计算得知消息的长度byte[] sendBytes = message.getBytes("UTF-8");//然后将消息的长度优先发送出去outputStream.write(sendBytes.length >>8);outputStream.write(sendBytes.length);//然后将消息再次发送出去outputStream.write(sendBytes);outputStream.flush();//==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法message = "第二条消息";sendBytes = message.getBytes("UTF-8");outputStream.write(sendBytes.length >>8);outputStream.write(sendBytes.length);outputStream.write(sendBytes);outputStream.flush();//==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法message = "the third message!";sendBytes = message.getBytes("UTF-8");outputStream.write(sendBytes.length >>8);outputStream.write(sendBytes.length);outputStream.write(sendBytes);    outputStream.close();socket.close();}
}
服务端
package Scoket.client;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server3 {public static void main(String[] args) {try {int port = 8444;ServerSocket serverSocket = new ServerSocket(port);Socket accept = serverSocket.accept();InputStream inputStream = accept.getInputStream();byte[] bytes;while (true){int first = inputStream.read();if(first == -1){break;}int second = inputStream.read();int len = (first << 8) +second;bytes = new byte[len];inputStream.read(bytes);System.out.println("Server3 get message:" + new String(bytes, "UTF-8"));}} catch (IOException e) {e.printStackTrace();}}
}

Socket写法的问题

上面的代码有些很大的问题
1、阻塞式 I/O: 这是最大的缺点之一。在 accept()、readLine() 等方法调用时,程序会被阻塞,等待客户端连接或数据到来。这可能导致服务器在处理多个客户端时性能下降。
2、单线程处理: 服务器采用单线程处理客户端连接。这意味着一次只能处理一个客户端连接,如果有大量的客户端同时连接,性能会受到影响。
3、不适用于高并发: 由于采用单线程处理方式,不适合高并发环境。在高并发情况下,建议考虑使用多线程或异步 I/O 模型。
4、异常处理不足: 缺少一些异常处理,例如,在 accept()、readLine() 中可能会抛出异常,而在示例中并未捕获和处理这些异常。
针对1、2可以采用BIO方式
针对1、2、3可以采用NIO
接下来将会优化代码分别介绍BIO和NIO

BIO

简单流程

服务器启动一个ServerSocket。
客户端启动一个Socket对服务器进行通信,默认情况下,服务器端需要对每一个客户端建立一个线程与之通信。
客户端发出请求后,先咨询服务器是否有线程相应,如果没有则会等待,或者被拒绝。
如果有响应,客户端线程会等待请求结束后,再继续执行。

BIO写法

客户端
package Scoket.client;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class BIOClient{public static void main(String[] args) {try {Socket socket = new Socket("127.0.0.1", 6666);OutputStream outputStream = socket.getOutputStream();outputStream.write("hi, i am client".getBytes(StandardCharsets.UTF_8));outputStream.flush();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
服务端

转自:https://juejin.cn/post/6924670437867651080

package Scoket.client;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class BIOServer {public static void main(String[] args) throws IOException {// 创建线程池ExecutorService executorService = Executors.newCachedThreadPool();// 创建ServerSocket并且监听6666端口ServerSocket serverSocket = new ServerSocket(6666);while (true) {// 监听---一直等待客户端连接Socket socket = serverSocket.accept();// 连接来了之后,启用一个线程去执行里面的方法executorService.execute(() -> {try {// 获取客户端发送过来的输入流InputStream inputStream = socket.getInputStream();byte[] bytes = new byte[1024];int read = inputStream.read(bytes);// 读取发送过来的信息并打印if (read != -1) {System.out.println(new String(bytes, 0, read));}} catch (IOException e) {e.printStackTrace();} finally {// 断开通讯try {socket.close();} catch (IOException e) {e.printStackTrace();}}});}}
}

BIO的问题

上述写法主要是在服务端接受到一个客户端连接时,就开启一个线程,然后新建一个连接专门处理这个服务
可以看下accept代码

    public Socket accept() throws IOException {if (this.isClosed()) {throw new SocketException("Socket is closed");} else if (!this.isBound()) {throw new SocketException("Socket is not bound yet");} else {Socket s = new Socket((SocketImpl)null);this.implAccept(s);return s;}}

可以看到,每次accept就会新建一个Socket
因此会有如下问题:
每个请求都需要创建独立的线程,与对应的客户端进行数据读,业务处理,然后再数据写。
当并发数较大时,需要创建大量的线程来处理连接,系统资源占用较大。
连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在读操作上,造成线程资源浪费。

基于上面的问题产生了NIO

NIO

简述

Java NIO全称java non-blocking IO,是指JDK提供的新API。从JDK1.4开始,提供了一系列改进的输入/输出的新特性,被统称为NIO(所以也可称为New IO),是同步非阻塞的。
NIO相关类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写。
NIO有三大核心部分:
Channel(通道)
Buffer(缓冲区)
Selector(选择器)
NIO是面向缓冲区的。数据读取到一个它的稍后处理的缓冲区,需要时可以在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络。
Java NIO的非阻塞模式,是一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变得可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
通俗理解:NIO是可以做到用一个线程来处理多个操作的。假设有10000个请求过来,根据实际情况,可以分配50或者100个线程来处理。不像之前的阻塞IO那样,非得分配10000个。
HTTP2.0使用了多路复用的技术,做到了同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
在这里插入图片描述

Buffer

Buffer(缓冲区):缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个容器对象(含数组),该对象提供了一组方法,可以更轻松的使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。Channel提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由Buffer。
在使用Buffer进行数据读写的时候,主要是通过底层的这个数组来储存数据,但是具体的控制数据读写,是通过父类Buffer中的以下参数来控制的:

属性描述
Capacity容量,即可以容纳的最大数据量。在缓冲区被创建时被确定并且不能改变
Limit示缓冲区的当前终点,不能对缓冲区超过limit的位置进行读写操作,且limit是可以修改的
Position位置,下一个要被读/写的元素的索引,每次读写缓冲区数据时都会改变position的值,为下次读写做准备
Mark标记

一共有7个类直接继承了Buffer类,这7个子类分别是除了boolean外的其他7中数据类型的Buffer类。
在这七个子类中,都有一个相应数据类型的数组,比如IntBuffer中就有一个int类型的数组:
final int[] hb;
在ByteBuffer类中就有一个byte类型的数组:
final byte[] hb;
实例:

package Scoket.client;import java.nio.IntBuffer;public class Buffer {public static void main(String[] args) {// 创建一个IntBuffer对象实例,分配容量为5IntBuffer buffer = IntBuffer.allocate(5);for (int i = 0; i < buffer.capacity(); i++) {// 每次循环为buffer塞一个int类型的数值,经过5次循环后,buffer中应该有0、2、4、6、8这5个数buffer.put(i * 2);}// 当要将buffer从写入转换到读取的时候,需要调用flip()方法// flip()方法是将limit指向position的位置,并且再将position置0// 表示从头再读到调用flip()方法的地方buffer.flip();// hasRemaining()方法表示是否还有剩余的元素可读取// 里面是通过position < limit判断是否有剩余的元素while (buffer.hasRemaining()) {System.out.println(buffer.get());}// 这时将position的位置设置成1,limit的位置设置成4buffer.position(1);buffer.limit(4);// 因为不能读取超过limit的元素,并且从position位置开始读取,所以这里将会输出2、4、6while (buffer.hasRemaining()) {System.out.println(buffer.get());}}
}

Channel(通道)

NIO的通道类似于流,但两者之间有所区别:
通道可以同时进行读写,而流只能读或者只能写
通道可以实现异步读写数据
通道可以从缓冲区读取数据,也可以写数据到缓冲区
BIO的stream是单向的,例如FileInputStream对象只能进行读取数据的操作,而NIO中的通道(Channel)是双向的,可以读操作,也可以写操作。
Channel在NIO中是一个接口。
常用的Channel类有:FileChannel、DatagramChannel、ServerSocketChannel、SocketChannel。FileChannel用于文件的数据读写,DatagramChannel用于UDP的数据读写,ServerSocketChannel和SocketChannel用于TCP的数据读写。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class Channel {public static void main(String[] args) throws Exception {// 从桌面上随机取一张图片进行复制操作// 获取原图片和被复制图片路径的流FileInputStream fileInputStream = new FileInputStream("/src/main/resources/img.png");FileOutputStream fileOutputStream = new FileOutputStream("/src/main/resources/img_1.png");// 通过流的getChannel()方法获取两个通道FileChannel fileInputStreamChannel = fileInputStream.getChannel();FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();// 创建一个字节类型的缓冲区,并为其分配1024长度ByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 每次读取图片的字节到缓冲区,当读返回-1时,表示读完了while (fileInputStreamChannel.read(byteBuffer) > -1) {// 调用flip()方法,从读的状态变为写的状态byteBuffer.flip();// 复制,将缓冲区中的数据写入到管道中fileOutputStreamChannel.write(byteBuffer);// 将缓冲区清空,以便于下一次读取byteBuffer.clear();}// 关闭Closeable对象fileOutputStreamChannel.close();fileInputStreamChannel.close();fileOutputStream.close();fileInputStream.close();}
}

Selector(选择器)

基本介绍

Java的NIO,用非阻塞的IO方式。可以用一个线程,处理多个的客户端连接,就会使用到Selector(选择器)。
Selector能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取时间然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求。
只有在连接通道真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每一个连接都创建一个线程,不用去维护多个线程。避免了多个线程之间的上下文切换导致的开销
SelectionKey为Selector中,有一个Channel注册了,就会生成一个SelectionKey对象,在同步非阻塞中,Selector可以通过SelectionKey找到相应的Channel并处理。
SelectionKey在Selector和Channel的注册关系中一共分为四种:

Int OP_ACCEPT:有新的网络连接可以accept,值为16(1<<4)
int OP_CONNECT:代表连接已经建立,值为8(1<<3)
int OP_WRITE:代表写操作,值为4(1<<2)
int OP_READ:代表读操作,值为1(1<<0)

使用实例

客户端:

package Scoket.client;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;public class NioClient {public static void main(String[] args) throws IOException {// 连接服务器SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 6443));// 发送数据String message = "Hello, Server!";ByteBuffer buffer = ByteBuffer.wrap(message.getBytes("UTF-8"));socketChannel.write(buffer);System.out.println("Sent to server: " + message);// 关闭连接socketChannel.close();}
}

服务端

package Scoket.client;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NioServer {public static void main(String[] args) throws IOException {// 打开 SelectorSelector selector = Selector.open();// 打开 ServerSocketChannel,监听客户端连接ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(6443));// 设置为非阻塞模式serverSocketChannel.configureBlocking(false);// 注册接受连接事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("Server listening on port 6443");while (true) {// 阻塞直到有就绪事件发生int readyChannels = selector.select();if (readyChannels == 0) {continue;}// 获取就绪事件的 SelectionKey 集合Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {// 有新的连接handleAccept(key, selector);} else if (key.isReadable()) {// 有数据可读handleRead(key);}keyIterator.remove();}}}private static void handleAccept(SelectionKey key, Selector selector) throws IOException {ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();SocketChannel socketChannel = serverSocketChannel.accept();socketChannel.configureBlocking(false);// 注册读事件socketChannel.register(selector, SelectionKey.OP_READ);System.out.println("Accepted connection from: " + socketChannel.getRemoteAddress());}private static void handleRead(SelectionKey key) throws IOException {SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = socketChannel.read(buffer);if (bytesRead > 0) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);System.out.println("Received from client: " + new String(data, "UTF-8"));// 在这里可以添加业务逻辑,然后将响应数据写入到 SocketChannel// ...// 关闭连接socketChannel.close();}}
}

参考源:
https://zhuanlan.zhihu.com/p/462497498
https://blog.csdn.net/a78270528/article/details/80318571
https://juejin.cn/post/6924670437867651080
https://juejin.cn/post/6925046428213608456

相关文章:

Java网络编程原理与实践--从Socket到BIO再到NIO

文章目录 Java网络编程原理与实践--从Socket到BIO再到NIOSocket基本架构Socket 基本使用简单一次发送接收客户端服务端 字节流方式简单发送接收客户端服务端 双向通信客户端服务端 多次接收消息客户端服务端 Socket写法的问题BIO简单流程BIO写法客户端服务端 BIO的问题 NIO简述…...

ARM GIC(三) gicv2架构

ARM的cpu,特别是cortex-A系列的CPU,目前都是多core的cpu,因此对于多core的cpu的中断管理,就不能像单core那样简单去管理,由此arm定义了GICv2架构,来支持多核cpu的中断管理 一、gicv2架构 GICv2,支持最大8个core。其框图如下图所示: 在gicv2中,gic由两个大模块组成: …...

第4章Netty第二节入门案例+channel,future,promise介绍

需求 开发一个简单的服务器端和客户端 客户端向服务器端发送 hello, world服务器仅接收&#xff0c;不返回 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.39.Final</version> </d…...

【论文笔记】3D Gaussian Splatting for Real-Time Radiance Field Rendering

原文链接&#xff1a;https://arxiv.org/abs/2308.04079 1. 引言 网孔和点是最常见的3D场景表达&#xff0c;因其是显式的且适合基于GPU/CUDA的快速栅格化。神经辐射场&#xff08;NeRF&#xff09;则建立连续的场景表达便于优化&#xff0c;但渲染时的随机采样耗时且引入噪声…...

【生物信息学】层次聚类过程

文章目录 一、理论二、实践过程1过程2 一、理论 层次聚类是一种基于树状结构的聚类方法&#xff0c;它试图通过在不同层次上逐步合并或分裂数据集来构建聚类结构。这个树状结构通常被称为“树状图”&#xff08;dendrogram&#xff09;&#xff0c;其中每个节点代表一个数据点或…...

变分自动编码器【03/3】:使用 Docker 和 Bash 脚本进行超参数调整

一、说明 在深入研究第 1 部分中的介绍和实现&#xff0c;并在第 2 部分中探索训练过程之后&#xff0c;我们现在将重点转向在第 3 部分中通过超参数调整来优化模型的性能。要访问本系列的完整代码&#xff0c;请访问我们的 GitHub 存储库在GitHub - asokraju/ImageAutoEncoder…...

KnowLM知识抽取大模型

文章目录 KnowLM项目介绍KnowLM项目的动机ChatGPT存在的问题 基于LLama的知识抽取的智析大模型数据集构建及训练过程预训练数据集构建预训练训练过程指令微调数据集构建 指令微调训练过程开源的数据集及模型局限性信息抽取Prompt 部署环境配置模型下载预训练模型使用LoRA模型使…...

MySQL数据库 索引

目录 索引概述 索引结构 二叉树 B-Tree BTree Hash 索引分类 索引语法 慢查询日志 索引概述 索引 (index&#xff09;是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种…...

ES 错误码

2xx状态码&#xff08;如200&#xff09;表示请求成功处理&#xff0c;并且不需要重试。 400状态码表示客户端发送了无效的请求&#xff0c;例如请求的语法有误或缺少必需的参数。在这种情况下&#xff0c;重试相同的请求很可能会导致相同的错误。因此&#xff0c;应该先检查并…...

听GPT 讲Rust源代码--src/tools(18)

File: rust/src/tools/rust-analyzer/crates/ide-ssr/src/from_comment.rs 在Rust源代码中的from_comment.rs文件位于Rust分析器&#xff08;rust-analyzer&#xff09;工具的ide-ssr库中&#xff0c;它的作用是将注释转换为Rust代码。 具体来说&#xff0c;该文件实现了从注…...

如何实现设备远程控制?

在工业自动化领域&#xff0c;设备远程控制是一项非常重要的技术。它使得设备可以在远离现场的情况下进行远程操作和维护&#xff0c;大大提高了设备的可用性和效率。 设备远程控制的应用场景有哪些&#xff1f; 远程故障排除&#xff1a;当设备出现故障时&#xff0c;工程师…...

百度侯震宇详解:大模型将如何重构云计算?

12月20日&#xff0c;在2023百度云智大会智算大会上&#xff0c;百度集团副总裁侯震宇以“大模型重构云计算”为主题发表演讲。他强调&#xff0c;AI原生时代&#xff0c;面向大模型的基础设施体系需要全面重构&#xff0c;为构建繁荣的AI原生生态筑牢底座。 侯震宇表示&…...

[Java]FileOutputStream的换行/续写/一次性写出一个字符串的方法

1.续写&#xff1a;FileOutputStream这个io流中的write方法默认情况下是覆盖写入的&#xff0c;如果需要追加写入&#xff0c;需要添加一个参数true 2.虽然write只能一个字符一个字符写入 但是我们可以把想输入的字符串放在str 再将str转化成byte数组 import java.io.FileOutp…...

VM进行TCP/IP通信

OK就变成这样 vm充当服务端的话也是差不多的操作 点击连接 这里我把端口号换掉了因为可能被占用报错了&#xff0c;如果有报错可以尝试尝试换个端口号 注&#xff1a; 还有一个点在工作中要是充当服务器&#xff0c;要去网络这边看下他的ip地址 拉到最后面...

剑指Offer 队列栈题目集合

目录 用两个栈实现队列 用两个栈实现队列 刷题链接&#xff1a; https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6 题目描述 思路一&#xff1a; 使用两个栈来实现队列的功能。栈 1 用于存储入队的元素&#xff0c;而栈 2 用于存储出队的元素。 1.push…...

grafana基本使用

一、安装grafana 1.下载 官网下载地址&#xff1a; https://grafana.com/grafana/download官网包的下载地址&#xff1a; yum install -y https://dl.grafana.com/enterprise/release/grafana-enterprise-10.2.2-1.x86_64.rpm官网下载速度非常慢&#xff0c;这里选择清华大…...

备份至关重要!如何解决iCloud的上次备份无法完成的问题

将iPhone和iPad备份到iCloud对于在设备发生故障或丢失时确保数据安全至关重要。但iOS用户有时会收到一条令人不安的消息&#xff0c;“上次备份无法完成。”下面我们来看看可能导致此问题的原因&#xff0c;如何解决此问题&#xff0c;并使你的iCloud备份再次顺利运行。 这些故…...

【项目问题解决】% sql注入问题

目录 【项目问题解决】% sql注入问题 1.问题描述2.问题原因3.解决思路4.解决方案1.前端限制传入特殊字符2.后端拦截特殊字符-正则表达式3.后端拦截特殊字符-拦截器 5.总结6.参考 文章所属专区 项目问题解决 1.问题描述 在处理接口入参的一些sql注入问题&#xff0c;虽然通过M…...

B/S医院手术麻醉临床管理系统源码 手术申请、手术安排

手术麻醉系统概述 手术室是医院各个科室工作交叉汇集的一个重要中心&#xff0c;在时间、空间、设备、药物、材料、人员调配的科学管理、高效运作、安全质控、绩效考核&#xff0c;都十分重要。手术麻醉管理系统&#xff08;Operation Anesthesia Management System&#xff0…...

解锁高效工作!5款优秀工时管理软件推荐

工时管理&#xff0c;一直是让许多企业和团队头疼的问题。传统的纸质工时表、复杂的电子表格&#xff0c;不仅操作繁琐&#xff0c;还容易出错。幸好&#xff0c;随着科技的进步&#xff0c;我们迎来了工时管理软件的春天。今天&#xff0c;就让我们一起走进这个新时代&#xf…...

ICLR 2024 高分论文 | Step-Back Prompting 使大语言模型通过抽象进行推理

文章目录 一、前言二、主要内容三、总结🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 ICLR 2024 高分论文:《Step-Back Prompting Enables Reasoning Via Abstraction in Large Language Models》 论文地址:https://openreview.net/forum?id=3bq3jsvcQ1 …...

边缘计算有哪些常用场景?TSINGSEE边缘AI视频分析技术行业解决方案

随着ChatGPT生成式人工智能的爆发&#xff0c;AI技术在业界又掀起一波新浪潮。值得关注的是&#xff0c;边缘AI智能也在AI人工智能技术进步的基础上得到了快速发展。IDC跟踪报告数据显示&#xff0c;2021年我国的边缘计算服务器整体市场规模达到33.1亿美元&#xff0c;预计2020…...

配置BGP的基本示例

目录 BGP简介 BGP定义 配置BGP目的 受益 实验 实验拓扑 ​编辑 组网需求 配置思路 配置步骤 配置各接口所属的VLAN 配置各Vlanif的ip地址 配置IBGP连接 配置EBGP 查看BGP对等体的连接状态 配置SwitchA发布路由10.1.0.0/16 配置BGP引入直连路由 BGP简介 BGP定义 …...

Flask解决接口跨域问题

1、什么是跨域CROS CORS&#xff08;Cross-Origin Resource Sharing&#xff0c;跨域资源共享&#xff09;是一种浏览器安全策略&#xff0c;用于控制在一个网页应用中如何让一个域的Web页面能够请求另一个域的资源。在Web开发中&#xff0c;由于同源策略&#xff08;Same-Ori…...

数据恢复工具推荐!这3款堪称删除文件恢复大师!

“快看看我&#xff01;经常都会莫名奇妙丢失各种电脑文件&#xff0c;但是又无法通过简单的方法找回重要的数据&#xff0c;有没有什么简单的操作可以帮助我快速恢复数据的呀&#xff1f;非常感谢&#xff01;” 在我们的日常生活中&#xff0c;无论是工作还是学习&#xff0c…...

论文笔记 | ICLR 2023 ReAct:通过整合推理和行动来增强语言模型

文章目录 一、前言二、主要内容三、总结🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 ICLR 2023 | Accept: notable-top-5%:《ReAct: Synergizing Reasoning and Acting in Language Models》 一句话总结:ReAct 方法在问答任务中通过提示大语言模型生成与任…...

CSS:元素显示模式与背景

CSS&#xff1a;元素显示模式与背景 元素显示模式什么是元素显示模式块级元素 block行内元素 inline行内块元素 inline-block元素显示模式对比元素显示模式转换 display 背景背景颜色 background-color背景图片 background-image背景平铺 background-repeat背景图片位置 backgr…...

K8S 为什么关闭 SELinux 和交换内存

在学习搭建 K8S 环境和使用 K8S 时&#xff0c;所有教程必然会提到的事情就是关闭节点的 SELinux 和交换内存&#xff0c;如同自然规律一样。 那么为什么会有这样的要求呢&#xff1f; 交换内存 计算机的物理内存是有限的&#xff0c;而进程对内存的使用是不确定的&#xff…...

7. ASP.NET Core Blazor 官网文档

官方文档地址&#xff1a;https://learn.microsoft.com/zh-cn/aspnet/core/blazor/?viewaspnetcore-8.0 Blazor 是一种 .NET 前端 Web 框架&#xff0c;在单个编程模型中同时支持服务器端呈现和客户端交互性&#xff1a; 使用 C# 创建丰富的交互式 UI。共享使用 .NET 编写的…...

xrandr

xrandr xrandr 是用于与 X RandR 扩展进行交互的命令行工具。它允许对 X server 进行实时配置&#xff08;即无需重新启动即可使配置生效&#xff09;&#xff0c;xrandr 提供了显示模式&#xff08;如分辨率、刷新率等&#xff09;的自动检测&#xff0c;以及动态配置输出&am…...

重庆建立公司网站/企业网站seo优化

详解Java异常Throwable、Error、Exception、RuntimeException的区别 在Java中&#xff0c;根据错误性质将运行错误分为两类&#xff1a;错误和异常。在Java程序的执行过程中&#xff0c;如果出现了异常事件&#xff0c;就会生成一个异常对象。生成的异常对象将传递Java运行时系…...

php做的网站好不好/西安百度竞价推广

配置范例站点站点序号域名目录1www.heytool.com/www/html/www.heytool.com2bbs.heytool.com/www/html/bbs.heytool.com 修改nginx 配置文件&#xff1a;# vi nginx.confuser nobody nobody; # 运行 nginx 的所属组和所有者 Nginx 启动关闭# /usr/local/nginx-1.0.6/sbin/ngin…...

虫虫wap建站源码/seo文章是什么

** 问题描述&#xff1a;**将一个2k2k单元格的棋盘用四种L型的图形进行完全覆盖(不能覆盖红色格子&#xff0c;不能发生重复覆盖)。** 思考&#xff1a;**1)如何能够让计算机实现这种算法&#xff1f;2)棋盘的大小为什么要为2k2k的单元格大小&#xff1f;任意的大小可以吗&…...

做定制商品的网站/新闻类软文

1.(1)建立一个名为JEWRY的文件夹&#xff0c;并在其中建立一个新的子文件夹JAK&#xff1b;(2)将C&#xff1a;\\TABLE文件夹删除&#xff1b;(3)将C&#xff1a;\\UNION\\TEAM文件夹中的文件MARK.FOX删除&#xff1b;(4)将C&#xff1a;\\TAM\\UPIN文件夹中文件MAIN.PRG拷贝到…...

有哪些做司考真题的网站/今日国内新闻10则

基本介绍 开发者可以使用云开发快速开发小程序、小游戏、公众号网页等&#xff0c;并且原生打通微信开放能力。 发布小程序需要使用云开发。 开发者无需搭建服务器&#xff0c;可免鉴权直接使用平台提供的 API 进行业务开发。 配有云端数据库&#xff0c;与传统数据库相比操…...

wordpress nginx cos html cache/网址和网站的区别

JSON的定义&#xff1a; 一种轻量级的数据交换格式&#xff0c;具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案&#xff08;有点类似于正则表达式&#xff0c;获得了当今大部分语言的支持&#xff09;&#xff0c;从而可以在不同平台间进行数据交换…...