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

Socket 读取数据

1. Socket 配置参数中添加

  1.1 读取 Socket 字节时的字节序

  1.2 读取数据时,单次读取最大缓存值

  1.3 从 Socket 读取数据时,遵从的数据包结构协议

  1.4 服务器返回数据的最大值,防止客户端内存溢出

  /*** @Description: Socket 配置参数*/public class IOSocketOptions {/*** 是否为调试模式,默认为 true*/private static boolean isDebug = true;/*** Socket 主机地址*/private SocketAddress socketAddress;/*** Socket 备用主机地址*/private SocketAddress backupAddress;/*** 写入 Socket 字节时的字节序*/private ByteOrder writeOrder;/*** 读取 Socket 字节时的字节序*/private ByteOrder readOrder;/*** 写数据时单个数据包的最大值 默认 100*/private int maxWriteBytes;/*** 读取数据时,单次读取最大缓存值,默认 50,数值越大效率越高,但是系统消耗也越大*/private int maxReadBytes;/*** 从 Socket 读取数据时,遵从的数据包结构协议,在业务层进行定义*/private IMessageProtocol messageProtocol;/*** 服务器返回数据的最大值 (单位Mb) ,防止客服端内存溢出*/private int maxResponseDataMb;/*** 连接超时时间(单位毫秒)*/private int connectTimeout;/*** 是否重连 Socket,默认为 true*/private boolean isReConnection;/*** Socket 重连管理器*/private AbsReConnection reConnectionManager;/*** Socket 工厂*/private SocketFactory socketFactory;/*** Socket 安全套接字协议相关配置*/private SocketSSLConfig socketSSLConfig;/*** IO 字节流的编码方式,默认 UTF-8*/private Charset charsetName;/*** 静态内部类*/public static class Builder {IOSocketOptions socketOptions;// 首先获取一个默认的配置public Builder() {this(getDefaultOptions());}public Builder(IOSocketOptions defaultOptions) {socketOptions = defaultOptions;}/*** 设置 Socket 主机地址** @param socketAddress* @return*/public Builder setSocketAddress(SocketAddress socketAddress) {socketOptions.socketAddress = socketAddress;return this;}/*** 设置 Socket 备用主机地址** @param backupAddress* @return*/public Builder setBackupAddress(SocketAddress backupAddress) {socketOptions.backupAddress = backupAddress;return this;}/*** 设置服务器返回数据的允许的最大值,单位兆/Mb** @param maxResponseDataMb* @return*/public Builder setMaxResponseDataMb(int maxResponseDataMb) {socketOptions.maxResponseDataMb = maxResponseDataMb;return this;}/*** 设置连接超时时间(单位毫秒)** @param connectTimeout* @return*/public Builder setConnectTimeout(int connectTimeout) {socketOptions.connectTimeout = connectTimeout;return this;}/*** 是否重连 Socket** @param reConnection* @return*/public Builder setReConnection(boolean reConnection) {socketOptions.isReConnection = reConnection;return this;}/*** 设置 Socket 重连管理器** @param reConnectionManager* @return*/public Builder setReConnectionManager(AbsReConnection reConnectionManager) {socketOptions.reConnectionManager = reConnectionManager;return this;}/*** 自定义创建 socket 工厂** @param socketFactory*/public Builder setSocketFactory(SocketFactory socketFactory) {socketOptions.socketFactory = socketFactory;return this;}/*** 安全套接字协议的配置** @param socketSSLConfig* @return*/public Builder setSocketSSLConfig(SocketSSLConfig socketSSLConfig) {socketOptions.socketSSLConfig = socketSSLConfig;return this;}/*** 设置 Socket 写字节时的字节序** @param writeOrder*/public Builder setWriteOrder(ByteOrder writeOrder) {socketOptions.writeOrder = writeOrder;return this;}/*** 设置 Socket 读取字节时的字节序** @param readOrder* @return*/public Builder setReadOrder(ByteOrder readOrder) {socketOptions.readOrder = readOrder;return this;}/*** 设置写数据时,单个数据包的最大值** @param maxWriteBytes* @return*/public Builder setMaxWriteBytes(int maxWriteBytes) {socketOptions.maxWriteBytes = maxWriteBytes;return this;}/*** 设置读取数据时,单次读取最大缓存值** @param maxReadBytes* @return*/public Builder setMaxReadBytes(int maxReadBytes) {socketOptions.maxReadBytes = maxReadBytes;return this;}/*** 设置读取数据的数据结构协议** @param messageProtocol*/public Builder setMessageProtocol(IMessageProtocol messageProtocol) {socketOptions.messageProtocol = messageProtocol;return this;}/*** 设置 IO 字节流的编码方式,默认 UTF-8** @param charsetName* @return*/public Builder setCharsetName(Charset charsetName) {socketOptions.charsetName = charsetName;return this;}public IOSocketOptions build() {return socketOptions;}}/*** 获取默认的配置*/public static IOSocketOptions getDefaultOptions() {IOSocketOptions options = new IOSocketOptions();options.socketAddress = null;options.backupAddress = null;options.isReConnection = true;// 是否重连主机,默认为 trueoptions.maxWriteBytes = 100;options.maxReadBytes = 50;options.writeOrder = ByteOrder.BIG_ENDIAN;// 大端序options.readOrder = ByteOrder.BIG_ENDIAN;// 大端序options.messageProtocol = null;// 默认数据包结构协议为 nulloptions.maxResponseDataMb = 5;// 默认接收最大值 5MBoptions.reConnectionManager = new DefaultReConnection(); // 默认 Socket 重连器options.connectTimeout = 10 * 1000; // 连接超时默认 5 秒options.socketFactory = null;options.socketSSLConfig = null;options.charsetName = StandardCharsets.UTF_8;return options;}public Charset getCharsetName() {return charsetName;}public boolean isIsDebug() {return isDebug;}public SocketAddress getSocketAddress() {return socketAddress;}public SocketAddress getBackupAddress() {return backupAddress;}public ByteOrder getWriteOrder() {return writeOrder;}public int getMaxWriteBytes() {return maxWriteBytes;}public ByteOrder getReadOrder() {return readOrder;}public int getMaxReadBytes() {return maxReadBytes;}public IMessageProtocol getMessageProtocol() {return messageProtocol;}public int getMaxResponseDataMb() {return maxResponseDataMb;}public int getConnectTimeout() {return connectTimeout;}public boolean isReConnection() {return isReConnection;}public AbsReConnection getReConnectionManager() {return reConnectionManager;}public SocketFactory getSocketFactory() {return socketFactory;}public SocketSSLConfig getSocketSSLConfig() {return socketSSLConfig;}public static void setIsDebug(boolean isDebug) {IOSocketOptions.isDebug = isDebug;}}

2. 定义读取到的数据实体类,OriginReadData.java

  /*** @Description: 读取到的数据*/public class OriginReadData implements Serializable {/*** 包头数据*/private byte[] headerData;/*** 包体数据*/private byte[] bodyData;public byte[] getHeaderData() {return headerData;}public void setHeaderData(byte[] headerData) {this.headerData = headerData;}public byte[] getBodyData() {return bodyData;}public void setBodyData(byte[] bodyData) {this.bodyData = bodyData;}/*** 获取数据体 body 的字符串** @return*/public String getBodyString() {//IOSocketOptions.getCharsetNamereturn new String(getBodyData(), StandardCharsets.UTF_8);}/*** 获取完整的数据,包括包头和包体** @return*/public byte[] getOriginDataBytes() {return Util.concatBytes(getHeaderData(), getBodyData());}}

3. 创建接口

  3.1 定义消息数据格式,IMessageProtocol.java

  /*** @Description: 消息数据格式*/public interface IMessageProtocol {/*** 获取包头的长度** @return*/int getHeaderLength();/*** 获取数据包体的长度,根据协议包体长度应该写在包头中,在读取数据时用到** @param header* @param byteOrder* @return*/int getBodyLength(byte[] header, ByteOrder byteOrder);/*** 根据协议打包消息格式,返回 byte 数组* @param sender* @return*/byte[] pack(byte[] sender);}

  3.2 添加 Socket 读取数据行为,IOAction.java

  /*** @Description: Socket 读取数据行为*/public interface IOAction {/*** 收到消息的响应*/String ACTION_READ_COMPLETE = "action_read_complete";}

  3.3 添加 Socket 行为监听接口,ISocketActionListener.java

  /*** @Description: Socket 行为监听接口*/public interface ISocketActionListener {/*** Socket 连接成功** @param socketAddress 主机地址*/void onSocketConnectSuccess(SocketAddress socketAddress);/*** Socket 连接失败** @param socketAddress   主机地址* @param isNeedReconnect 是否需要重新连接*/void onSocketConnectFail(SocketAddress socketAddress, boolean isNeedReconnect);/*** 断开 Socket 连接** @param socketAddress   主机地址* @param isNeedReconnect 是否需要重新连接*/void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect);/*** Socket 数据响应** @param socketAddress  主机地址* @param originReadData 读取到的数据为类格式*/void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData);/*** Socket 数据响应** @param socketAddress 主机地址* @param readData      读取到的数据为 String 类型*/void onSocketResponse(SocketAddress socketAddress, String readData);/*** Socket 数据响应** @param socketAddress 主机地址* @param readData      读取到的数据为 byte 数组类型*/void onSocketResponse(SocketAddress socketAddress, byte[] readData);}

4. 添加异常类

  4.1 可恢复 Socket 读取数据异常,ReadRecoverableException.java

  /*** @Description: 可恢复 Socket 读取数据异常*/public class ReadRecoverableException extends Exception {public ReadRecoverableException(String message) {super(message);}}

  4.2 不可修复的读取错误异常,ReadUnrecoverableException.java

  /*** @Description: 不可修复的读取错误*/public class ReadUnrecoverableException extends Exception {public ReadUnrecoverableException(String message) {super(message);}}

5. 实现 Socket 读取数据

  5.1 定义 Socket 读取数据接口 IReader.java

  /*** @Description: Socket 读数据接口*/public interface IReader<T> {/*** 打开数据的读取*/void openReader();/*** 读数据*/void read() throws Exception;/*** 关闭数据的读取*/void closeReader();/*** 设置参数** @param t*/void setOption(T t);}

  5.2 实现 Socket 读取数据接口

  /*** @Description: Socket 读数据*/public class IOReader implements IReader<IOSocketOptions> {/*** 输入流*/private InputStream inputStream;/*** 读取原始数据的缓存空间*/private ByteBuffer originBuffer;/*** Socket 连接管理器*/private IConnectionManager connectionManager;/*** Socket 行为分发器*/private ISocketActionDispatch actionDispatch;/*** Socket 配置参数*/private IOSocketOptions socketOptions;/*** 读数据时,余留数据的缓存*/private ByteBuffer remainingBuffer;/*** 读数据线程*/private Thread readerThread;/*** 是否停止线程*/private boolean stopThread;public IOReader(IConnectionManager connectionManager, ISocketActionDispatch actionDispatch) {this.connectionManager = connectionManager;this.socketOptions = connectionManager.getOptions();this.actionDispatch = actionDispatch;}@Overridepublic void openReader() {init();if (readerThread == null || !readerThread.isAlive()) {readerThread = new Thread(readerTask, "reader thread");stopThread = false;readerThread.start();}}//初始化private void init() {// 获取输入流inputStream = connectionManager.getInputStream();// 没有定义消息协议if (socketOptions != null && socketOptions.getMessageProtocol() == null) {originBuffer = ByteBuffer.allocate(1024 * 4);}}/*** 读取数据任务*/private Runnable readerTask = new Runnable() {@Overridepublic void run() {while (!stopThread) {try {read();} catch (Exception e) {LogUtil.e("读取数据异常.");e.printStackTrace();// 停止线程stopThread = true;release();}}}};@Overridepublic void read() throws IOException, ReadRecoverableException, ReadUnrecoverableException {OriginReadData originData = new OriginReadData();// 读取数据时,数据包结构协议IMessageProtocol messageProtocol = this.socketOptions.getMessageProtocol();// 消息协议为 null,则直接读取原始消息,不建议这样使用,因为会发生分包,黏包的问题if (messageProtocol == null) {readOriginDataFromStream(originData);return;}// 定义了消息协议体// 包头的长度int headerLength = messageProtocol.getHeaderLength();// 包头数据的 bufferByteBuffer headerBuffer = ByteBuffer.allocate(headerLength);// 设置读取数据时,byte 的字节序headerBuffer.order(socketOptions.getReadOrder());// 1.读取 Headerif (remainingBuffer != null) {  // 有余留数据// flip 方法: 一般从 ByteBuffer 读取数据前调用,将 limit 设置为当前 position,将 position 设置为 0,在读取数据时,limit 代表可读取数据的有效长度remainingBuffer.flip();// 读取余留数据的长度int length = Math.min(remainingBuffer.remaining(), headerLength);// 读取余留的数据headerBuffer.put(remainingBuffer.array(), 0, length);if (length < headerLength) { // 余留数据小于一个 Header// 剩余的数据置 nullremainingBuffer = null;// 从 stream 中读取剩余的 header 数据readHeaderFromSteam(headerBuffer, headerLength - length);} else {// 移动开始读取数据的指针remainingBuffer.position(headerLength);}} else {// 无余留数据// 从 Stream 读取一个完整的 header,capacity: 容量readHeaderFromSteam(headerBuffer, headerBuffer.capacity());}// 保存 headeroriginData.setHeaderData(headerBuffer.array());// 2.读取 bodyint bodyLength = messageProtocol.getBodyLength(originData.getHeaderData(), socketOptions.getReadOrder());if (bodyLength > 0) {if (bodyLength > socketOptions.getMaxResponseDataMb() * 1024 * 1024) {throw new ReadUnrecoverableException("服务器返回的单次数据超过了规定的最大值,可能你的 Socket 消息协议不对,一般消息格式为: " + "Header+Body,其中 Header 保存消息长度和类型等,Body 保存消息内容,请规范好你的协议.");}// 分配包体缓存空间ByteBuffer bodyBuffer = ByteBuffer.allocate(bodyLength);bodyBuffer.order(socketOptions.getReadOrder());// 有余留数据if (remainingBuffer != null) {// 余留数据缓存 包体取数据的起始点int bodyStartPosition = remainingBuffer.position();// 获取余留数据长度 与 包体长度 中 取小的值int length = Math.min(remainingBuffer.remaining(), bodyLength);// 读 length 大小的余留数据bodyBuffer.put(remainingBuffer.array(), bodyStartPosition, length);// 余留数据缓存移动 positionremainingBuffer.position(bodyStartPosition + length);//读取的余留数据刚好等于一个 bodyLengthif (length == bodyLength) {if (remainingBuffer.remaining() > 0) {// 创建临时数据缓存ByteBuffer temp = ByteBuffer.allocate(remainingBuffer.remaining());// 设置字节序temp.order(socketOptions.getReadOrder());// 添加余留数据剩下的数据temp.put(remainingBuffer.array(), remainingBuffer.position(), remainingBuffer.remaining());// 重新赋值余留数据缓存remainingBuffer = temp;} else {// 余留数据缓存已取完,则当前余留数据缓存置为 nullremainingBuffer = null;}// 保存 bodyoriginData.setBodyData(bodyBuffer.array());LogUtil.i("Socket 收到数据: " + originData.getBodyString());// 分发数据actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originData);// 读取结束return;} else {//余留数据缓存已取完,当前余留数据缓存置为 nullremainingBuffer = null;}}// 无余留或者有部分余留数据,则从 Stream 中读取readBodyFromStream(bodyBuffer);// body 保存到 originData 中originData.setBodyData(bodyBuffer.array());} else if (bodyLength == 0) { // 没有 body 数据originData.setBodyData(new byte[0]);if (remainingBuffer != null) { //有余留数据// 处理 body 包体时,判断是否有余留数据if (remainingBuffer.hasRemaining()) {//有余留数据// 创建临时数据缓存ByteBuffer temp = ByteBuffer.allocate(remainingBuffer.remaining());// 设置字节序temp.order(socketOptions.getReadOrder());// 添加余留数据剩下的数据temp.put(remainingBuffer.array(), remainingBuffer.position(), remainingBuffer.remaining());// 重新赋值余留数据缓存remainingBuffer = temp;} else { //余留数据缓存已取完,则当前余留数据缓存置为 nullremainingBuffer = null;}}} else {//if (bodyLength < 0)throw new ReadUnrecoverableException("数据 body 的长度不能小于0");}LogUtil.i("Socket 收到数据: " + originData.getBodyString());//分发数据actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originData);}/*** 读取包头的数据** @param headerBuffer 包头的数据缓存* @param readLength   包头的长度* @throws IOException* @throws ReadRecoverableException*/private void readHeaderFromSteam(ByteBuffer headerBuffer, int readLength) throws IOException, ReadRecoverableException {for (int i = 0; i < readLength; i++) {byte[] bytes = new byte[1];// 从输入流中读取数据,无数据时会阻塞int value = inputStream.read(bytes);// -1: 在读取文件中,表示读到了末尾,在 Socket 中表示一般因为服务器断开了连接if (value <= -1) {throw new ReadRecoverableException("读取数据失败,可能是因为 Socket 跟服务器断开了连接");}//存放包头数据headerBuffer.put(bytes);}}/*** 从 Stream 中读取数据,填满 byteBuffer,如果读取有多,则缓存在 remainingBuffer 中** @param byteBuffer 包体的数据缓存* @throws IOException* @throws ReadRecoverableException*/private void readBodyFromStream(ByteBuffer byteBuffer) throws IOException, ReadRecoverableException {// while 循环直到 byteBuffer 装满数据while (byteBuffer.hasRemaining()) {//从服务器单次读取的最大值byte[] bufferArray = new byte[socketOptions.getMaxReadBytes()];int len = inputStream.read(bufferArray);if (len <= -1) {throw new ReadRecoverableException("读取数据失败,可能是因为 Socket 跟服务器断开了连接");}//缓存中剩余多少数据int remaining = byteBuffer.remaining();// 从 Stream 读到的数据长度 大于 byteBuffer 的剩余空间时if (len > remaining) {byteBuffer.put(bufferArray, 0, remaining);// 将多余的数据保存到 remainingBuffer 中缓存,等下一次再读取remainingBuffer = ByteBuffer.allocate(len - remaining);remainingBuffer.order(socketOptions.getReadOrder());remainingBuffer.put(bufferArray, remaining, len - remaining);} else {// 从 stream 读取的数据小于或者等于 byteBuffer 的剩余空间时byteBuffer.put(bufferArray, 0, len);}}}/*** 当消息协议为 null 时,直接返回原始数据** @param readData* @throws IOException* @throws ReadRecoverableException*/private void readOriginDataFromStream(OriginReadData readData) throws IOException, ReadRecoverableException {//用全局 originBuffer 避免重复创建字节数组int len = inputStream.read(originBuffer.array());// no more dataif (len <= -1) {throw new ReadRecoverableException("读取数据失败,可能 Socket 跟服务器断开了连接");}//bytes 复制byte[] data = new byte[len];originBuffer.get(data, 0, len);readData.setBodyData(data);// Charset.forName("GBK")LogUtil.i("Socket 收到数据: " + readData.getBodyString());// 分发数据actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, readData);// 相当于把指针重新指向 position = 0originBuffer.clear();}@Overridepublic void setOption(IOSocketOptions socketOptions) {this.socketOptions = socketOptions;}@Overridepublic void closeReader() {try {// 关闭线程,释放资源shutDownThread();release();} catch (InterruptedException e) {e.printStackTrace();}}/*** 关闭读取数据线程*/private void shutDownThread() throws InterruptedException {if (readerThread != null && readerThread.isAlive() && !readerThread.isInterrupted()) {stopThread = true;// 中断线程readerThread.interrupt();readerThread.join();LogUtil.i("shutDownThread");}}/*** 释放资源*/private void release() {if (originBuffer != null) {originBuffer = null;}if (remainingBuffer != null) {remainingBuffer = null;}if (readerThread != null && !readerThread.isAlive()) {readerThread = null;}try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {e.printStackTrace();} finally {inputStream = null;}LogUtil.i("release");}}

6. 测试方法

    //测试按钮private void initView(View view) {SocketAddress socketAddress = new SocketAddress("192.168.1.52", 6688);TcpConnection tcpConnection = new TcpConnection(socketAddress);IOSocketOptions socketOptions = new IOSocketOptions.Builder().setSocketAddress(socketAddress).build();tcpConnection.setOptions(socketOptions);IOReader reader = new IOReader(tcpConnection, null);view.findViewById(R.id.but_connect).setOnClickListener(v -> tcpConnection.connect());view.findViewById(R.id.but_start).setOnClickListener(v -> reader.openReader());view.findViewById(R.id.but_stop).setOnClickListener(v -> reader.closeReader());}

相关文章:

Socket 读取数据

1. Socket 配置参数中添加 1.1 读取 Socket 字节时的字节序 1.2 读取数据时&#xff0c;单次读取最大缓存值 1.3 从 Socket 读取数据时&#xff0c;遵从的数据包结构协议 1.4 服务器返回数据的最大值&#xff0c;防止客户端内存溢出 /*** Description: Socket 配置参数*/public…...

小白的Git入门教程(一)

这是本人的git的入门过程仅供参考 先是在官网下载git版本下载链接&#xff0c;安装步骤可以搜索其他大神的文章然后就是创建一个属于你的git本地库首先是创建一个文件夹作为根目录&#xff0c;这里我创建了一个叫test_git文件夹紧接着便进去新建文件夹&#xff0c;点击这里的g…...

第一个Vue程序

第一个Vue程序 <body> <!--view层 变成了一个模板--> <div id"app">{{message}} </div><!--导入vue.js--> <script src"https://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.min.js"></script> <script>va…...

2023上学期学习计划

目前&#xff1a;根据答辩的情况来看&#xff0c;目前去项目组&#xff0c;着重写好算法是相对较优的打算&#xff0c;先将项目写好&#xff0c;之后着重提升算法水平&#xff0c;这学期主要啃《算法导论》与《大话数据结构》这俩本书&#xff0c;同时刷题量要达到160题 四月份…...

深入了解MySQL锁机制及应用场景

深入了解MySQL锁机制及应用场景锁的概述锁的分类锁的应用场景数据库事务管理多线程程序开发数据库的备份和恢复对于在线游戏等高并发应用场景锁的具体使用方法锁的应用实例总结锁的概述 MySQL锁是操作MySQL数据库时常用的一种机制。MySQL锁可以保证多个用户在同时执行读写操作…...

Java类和对象

目录 一、什么是面向对象&#xff1f; 二、类与对象的基本概念 1.类 2.对象 三、类的定义格式 四、类与对象的定义与使用 1.什么是实例化 2.实例化对象 3.类的使用 4.类与对象的说明 总结 一、什么是面向对象&#xff1f; 面向对象是一种现在最为流行的程序设计方法&a…...

aspnet053+sqlserver在线考试系统xns

目 录 基于.NET的考试系统 1 摘 要 3 前 言 4 第一章  系统概述 5 1.1 本课题的研究意义 5 1.2 本论文的目的及内容 5 第二章 在线考试系统概述 7 2.1 现行在线考试系统现状 7 2.2 电子管理平台的开发方法介绍 8 2.2.1 B/S体系结构 8 2…...

新一代大学英语(提高篇)

词汇题&#xff08;55道&#xff09; 1. You should carefully think over_____ the manager said at the meeting. A. that B. which C. what D. whose 1.选C,考察宾语从句连接词&#xff0c;主句谓语动词think over后面缺宾语&#xff0c;后面的宾语从句谓语动…...

阿里云OSS 203 Non-Authoritative Information问题解决

问题描述&#xff1a; 203 Non-Authoritative Information 问题分析&#xff1a; 1、跨域问题&#xff0c;阿里云OSS没有配置跨域规则。 解决办法请参考以下博客。 阿里云OSS No ‘Access-Control-Allow-Origin‘ header is present on the requested resource问题解决_旭东…...

【数据结构】你真的认识“”吗?它真的就只是“取地址”吗?或许你一直都在误解它。

我们有时候在看数据结构相关书籍时&#xff0c;经常会看到这样的写法&#xff1a; void StackInit(ST& ps) {assert(ps);ps.a NULL;ps.top 0;ps.capacity 0; } 注意&#xff0c;这里的&可不是表示取地址。如果你把它理解为取地址&#xff0c;那就在错误的路上狂奔&…...

[深入理解SSD 21] 固态硬盘GC机制 | GC 分类 | GC 过程 | GC 和 Trim 的关系

Hello 大家好&#xff0c; 我是元存储~主页&#xff1a;元存储的博客_CSDN博客-深入理解SSD:固态存储特性与实践,深入浅出SSD:固态存储原理与特性,深入理解Flash:闪存特性与实践领域博主前言SSD上已经被写入过的Page页在重新被写入之前&#xff0c;必须要将page页所在的block块…...

大数据未来发展怎么样?

就目前情况来看&#xff0c;大数据行业前景不错薪资待遇好&#xff0c;也有越来越多的人选择大数据行业&#xff0c;各大名企对于大数据人才需求不断上涨。 大数据从业领域很宽广&#xff0c;不管是科技领域还是食品产业&#xff0c;零售业等都是需要大数据人才进行大数据的处…...

【Linux】进程和线程间的区别与联系

带你轻松理解进程与线程的区别与联系&#xff1a; 进程线程定义资源分配和拥有的基本单位CPU调度的基本单位切换情况对应进程的CPU环境的保存以及新进程环境的设置保存和设置程序计数器&#xff0c;少量的寄存器&#xff0c;以及对应的线程栈切换者操作系统操作系统切换过程用…...

【C语言】变量和常量

目录 1. 变量 1.1 变量的分类 1.1.1 局部变量 1.1.2 全局变量 1.2 变量的使用——声明、赋值、初始化 1.3 变量的作用域和生命周期 1.3.1 作用域 1.3.2 生命周期 2. 常量 2.1 字面常量 2.2 常变量&#xff08;const常量&#xff09; 2.3 简单的宏&#xff08;对象式…...

蓝桥杯-卡片换位(BFS)

蓝桥杯-卡片换位 1、题目描述2、解题思路3、完整代码(AC)1、题目描述 你玩过华容道的游戏吗? 这是个类似的,但更简单的游戏。 看下面 3 x 2 的格子 +---+---+---+| A | * | * |+---+---+---+| B | | * |+---+---+---+在其中放 5 张牌,其中 A 代表关羽,B 代表张飞,* 代表士…...

霍夫曼编码 | 贪心算法 2

霍夫曼编码是一种无损数据压缩算法。其思想是为输入字符分配可变长度代码&#xff0c;分配代码的长度基于相应字符的频率。 分配给输入字符的可变长度代码是​​​​​​​前缀代码&#xff0c;意味着代码&#xff08;位序列&#xff09;的分配方式是分配给一个字符的代码不是…...

async 与 await

目录一、async函数二、await表达式三、async与await结合一、async函数 函数的返回值为promise对象promise对象的结果由async函数执行的返回值决定 async function main(){//1.如果返回的是一个非promise类型的数据&#xff0c;那么返回的就是成功的状态// return 521//2.如果…...

MYSQL语句

在 Navicat Premium 里面test_database数据库 &#xff0c;右击 “命令列界面..” 命令列界面 中 输入命令 查看所有的数据库 show databases; 选择数据库 -- use 数据库名; use test_database; 创建表 creat table 表名(字段名1 数据类型,字段名2 数据类型) -- 创建…...

C语言函数:内存函数memcpy()以及实现

C语言函数&#xff1a;内存函数memcpy() 引言&#xff1a; #define _CRT_SECURE_NO_WARNINGS#include <stdlib.h>int main() {int arr1[20] { 1,2,3,4,5,6,7,8,9 };int arr2[20] { 0 };strcpy(arr2, arr1);return 0; } strcpy函数&#xff1a;C语言函数&#xff1a;字…...

ArcGIS基础:栅格分区转矢量再裁剪面图层【重分类】【栅格转面】

如上所示&#xff0c;是一个原始的栅格数据&#xff08;DEM&#xff09;&#xff0c;本操作将其转为矢量要素并裁剪另外的面图层 右键属性查看数据类型&#xff0c;可以发现此栅格数据属于【浮点型】&#xff0c;这里需要注意的是&#xff1a;栅格转为矢量数据时&#xff0c;必…...

vue尚品汇商城项目-day02【11.对axios二次封装+12.接口统一管理】

文章目录11.对axios二次封装11.1为什么需要进行二次封装axios&#xff1f;11.2在项目当中经常有API文件夹【axios】12.接口统一管理12.1跨域问题12.2接口统一管理12.3不同请求方式的src/api/index.js说明本人其他相关文章链接11.对axios二次封装 安装命令&#xff1a;cnpm inst…...

并发编程-2

1.锁的分类 1.1 可重入锁、不可重入锁 Java中提供的synchronized&#xff0c;ReentrantLock&#xff0c;ReentrantReadWriteLock都是可重入锁。 1.1.1重入&#xff1a; 当前线程获取到A锁&#xff0c;在获取之后尝试再次获取A锁是可以直接拿到的。 1.1.2不可重入&#xff…...

万字解析Linux内核调试之动态追踪

文章介绍几种常用的内核动态追踪技术&#xff0c;对 ftrace、perf 及 eBPF 的使用方法进行案例说明。 1、什么是动态追踪 动态追踪技术&#xff0c;是通过探针机制来采集内核或者应用程序的运行信息&#xff0c;从而可以不用修改内核或应用程序的代码&#xff0c;就获得调试信…...

Spring Boot 各层作用与联系

目录 1 Entity 层 2 DAO 层 3 Service 层 4 Controller 层 Spring Boot 各层之间的联系&#xff1a; controller 层-----> service 层(接口->接口实现类) -----> dao 层的.mapper 文件 -----> 和 mapper 层里的.xml 文件对应 1 Entity 层 实体层&#xff0c;…...

苦中作乐---竞赛刷题(15分-20分题库)

&#xff08;一&#xff09;概述 &#xff08;Ⅰ&#xff09;彩票是幸运的 &#xff08;Ⅱ&#xff09;AI 英文问答程序 &#xff08; Ⅲ &#xff09; 胎压检测 &#xff08;二&#xff09;题目 Ⅰ 彩票的号码有 6 位数字&#xff0c;若一张彩票的前 3 位上的数之和等于后 3 …...

超详细,多图,PVE安装以及简单设置教程(个人记录)

前言: - 写这个的目的是因为本人健忘所以做个记录以便日后再折腾时查阅,。 - 本人笔拙如有选词&#xff0c;错字&#xff0c;语法&#xff0c;标点错误请忽视&#xff0c;大概率知道了也不会修改&#xff0c;本人能看懂就好。 - 内容仅适用于本人的使用环境&#xff0c;不同…...

茴子的写法:关于JAVA中的函数传递语法糖:lambda

解决的问题&#xff1a;Java中实现函数传递。 在Java编程的实践过程中&#xff0c;有一些场景&#xff0c;我们希望能够将函数传递进去&#xff0c;不同的函数实现代表着不同的策略&#xff0c;这在JDK8以前&#xff0c;需要定义一个接口&#xff0c;这个接口中定义这个函数方…...

动态规划刷题记录(2)

今天的三个题目属于模板题&#xff0c;可能将来会遇见它们的变形应用。 1、最长上升子序列问题 这道题目的关键就在于我们的状态定义&#xff0c;我们定义&#xff1a;f(i)表示长度为i的子序列的末尾最大值。意思就是&#xff0c;比如一个子序列为&#xff1a;1,4,5&#xff0…...

2023年广东省网络安全竞赛——Web 渗透测试解析(超级详细)

任务一:Web 渗透测试 任务环境说明: √ 服务器场景:Server03 √ 服务器场景操作系统:未知(关闭连接) 通过本地 PC 中的渗透测试平台 Kali 对靶机进行 WEB 渗透,找到页面内的文件上传漏洞并且尝试进行上传攻击,将文件上传成功后的页面回显字符串作为Flag 提交(如:…...

MI-SegNet阅读笔记

MI-SegNet: Mutual Information-Based US Segmentation for Unseen Domain Generalization 摘要 解决医学成像泛化能力提出了一种新的基于互信息(MI)的框架MI- segnet分离解剖结构和领域特征采用两个编码器提取相关特征&#xff1a;两个特征映射中出现的任何MI都将受到惩罚&a…...