网络编程套接字TCP

前集回顾

上一篇博客中我们写了一个UDP的echo server,是一个回显服务器:请求是啥,响应就是啥

一个正常的服务器,要做三个事情:

  1. 读取请求并解析
  2. 根据请求,计算响应
  3. 把响应写回到客户端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length,requestPacket.getSocketAddress());
//先得到字节数组,然后取字节,然后取数组的长度,这里的长度单位是“字节数”
String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
//这里的长度单位是“字符数”

客户端的整体流程:

  1. 从控制台读取字符串
  2. 把字符串发送给服务器
  3. 从服务器读取到响应
  4. 把响应打印到控制台上

同时后面的serverIp为127.0.0.1,需要把字符串格式的ip地址转成Java能识别的对象,InetAddress对象,提供了getByName工厂方法,把上述字符串格式的ip地址,转成Java能识别的InetAddress对象了

这个对象里有的就是IP地址,会按照32位整数的形式来保存,计算机认识的是32位整数形式的ip,点分十进制是给人看的

DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,InetAddress.getByName(serverIp), serverPort);
socket.send(requestPacket);
//读取响应数据
DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
socket.receive(responsePacket);

这个代码在写的时候,上面的send完成之后,就立即执行到下面的receive了,但是实际上,数据在网络传输过程中,也是需要时间的,此处的receive也会阻塞,阻塞到真正到达为止

上述阻塞行为,不需要咱们代码进行任何干预,都是人家的api内部已经实现好了(系统内核完成好了的功能)

在系统内核中,让某个线程阻塞是很容易的事情,通过链表方式来组织PCB,链表不只是一个,而是有多个,有的链表,称为“就绪队列”,这里的PCB就要参与cpu调度,有的链表,称为“阻塞队列”(这里的PCB不参与PCB调度),调用receive的时候,系统会看网卡上是否有数据来了(通过网卡驱动很容易能够感知到),然后如果没来,就把当前线程PCB放到阻塞的队列中即可(链表节点的删除/插入)

服务器代码

客户端代码

运行

先运行服务器,后运行客户端

服务器是被动方,要先准备好,得餐馆先开门,然后才能去吃饭

有个客户端,发来一个请求,请求内容是hello,响应内容也是hello,客户端ip是127.0.0.1,客户端的port是49874(系统自动分配的结果)

如何启动多个客户端

默认情况下,idea里面只能启动一个客户端,要想启动多个,需要如下操作:

在service中可以看到

刚才是客户端和服务器,都在同一个电脑上,如果是不同电脑呢?

Question:如果我把客户端发给你,你在客户端中填写这个ip,能否访问我的这个服务器程序呢?


Answer:不能,要想能访问,有一个前提,需要在同一个局域网下,如何能够让世界上任何一个能上网的人脸上咱们的服务器呢?不是咱们的程序代码不行(代码已经就绪),当前这个电脑的IP只是一个局域网内部使用的私有IP,而不是能够在广域网上直接使用的“公网IP”,需要一个云服务器来提供公网IP

通过XShell可以远程控制云服务器

上述一串数字就是云服务器IP,也就是公网IP,另外,在所有IP地址中,以下三种情况是私网IP,剩下的都是公网IP

私网IP常用格式

  • 10.*
  • 172.16-172.31.*
  • 192.168.*

  1. 把写好的udpechoserver放到云服务器上,需要把服务器程序打一个jar包出来
  2. 把这个jar包传到云服务器上
  3. 运行这个程序

通过命令来运行程序

通过这串代码可以理解两方面:

总结

  1. socket api(UDP)
  2. 服务器程序的典型工作流程
  •  读取请求并解析
  •  根据请求计算响应
  •  把响应写回到客户端
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);// 为了方便在 java 代码中处理 (尤其是后面进行打印) 可以把上述数据报中的二进制数据, 拿出来, 构造成 StringString request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2) 根据请求计算响应String response = this.process(request);// 3) 把响应写回到客户端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);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();}
}

如果要写别的服务器(例如翻译网站),可以继承该服务器,然后重写process方法,在响应方面重新重写,使用Map来记录key-value之间的关系

TCP

TCP的socket api也有两个关键的类

ServerSocket

其中也有三个重要的方法:

接听操作方法

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

构造方法

public ServerSocket(int port) throws IOException {this(port, 50, null);
}

关闭资源的方法

public void close() throws IOException {synchronized(closeLock) {if (isClosed())return;if (created)impl.close();closed = true;}
}

Socket客户端和服务器都要用(两边都要用,不能叫做ClientSocket),TCP传输的是字节流,就是传输字节,传输的基本单位就是byte

Socket

其中重要的方法

构造方法

public Socket(String host, int port) throws UnknownHostException, IOException {this(host != null ? new InetSocketAddress(host, port) :new InetSocketAddress(InetAddress.getByName(null), port),(SocketAddress) null, true);
}

获取socket内部持有的对象

public InputStream getInputStream() throws IOException {if (isClosed())throw new SocketException("Socket is closed");if (!isConnected())throw new SocketException("Socket is not connected");if (isInputShutdown())throw new SocketException("Socket input is shutdown");InputStream in = this.in;if (in == null) {// wrap the input stream so that the close method closes this socketin = new SocketInputStream(this, impl.getInputStream());if (!IN.compareAndSet(this, null, in)) {in = this.in;}}return in;
}

获取socket内部持有的流对象

public OutputStream getOutputStream() throws IOException {if (isClosed())throw new SocketException("Socket is closed");if (!isConnected())throw new SocketException("Socket is not connected");if (isOutputShutdown())throw new SocketException("Socket output is shutdown");OutputStream out = this.out;if (out == null) {// wrap the output stream so that the close method closes this socketout = new SocketOutputStream(this, impl.getOutputStream());if (!OUT.compareAndSet(this, null, out)) {out = this.out;}}return out;
}

同时还可以获得源和目的主机的信息

public InetAddress getInetAddress() {if (!isConnected())return null;try {return getImpl().getInetAddress();} catch (SocketException e) {}return null;
}

ServerSocket和Socket这俩起到的作用,截然不同的,服务器一上来要先处理客户端来的连接

Socket clientSocket = serverSocket.accept();
//服务器一启动,就会立即执行到这里,如果客户端没有连接过来,accept也会产生阻塞,直到说有客户端真的连接上来了

举一个比较形象的栗子:有一个西装革履的小哥来到我面前,这个人不是大老板就是销售,他把我领到一个地方,这个地方都是西装革履的人,给我介绍房子,然后小哥就消失了,然后由别的人带我介绍,此时小哥就可以理解为ServerSocket,其他带我介绍的人可以理解为clientSocket

  • ServerScoket用于在服务器端使用的(揽客) - accept
  • Socket用于服务器和客户端来进行通信 - getInputStream,getOutStream

相当于打电话的时候,接通电话后,会说很多话,不是说一句就挂了

Scanner scanner = new Scanner(inputStream);
String request = scanner.next();
//这个读取方式,就是会读到“空白符”才会读取完毕,如果直接按照read方式来读,读出来的就是byte[]还需要转成Srting
//如果直接使用Scanner的话,直接读出来的就是String,Scanner已经帮我们做好上述的转换操作了
//客户端在发送数据的时候,无比要在每个请求的结尾,填上空白符(\n, \t, 回车, 换行)
//上述要求属于咱们对于通信细节的约定

由于TCP上面是按照字节来传输的,而是实际上,我们是希望,若干个字节能够构成一个“应用层数据报”,如何区分从哪到哪是一个应用层数据报?就可以通过“分隔符”的方式来约定,上述代码就是在约定说,使用空白符,来作为一个请求的结束标记


从TCP socket中读出一大串字节,可能会包含多个应用层的请求数据,就需要作出区分


不论是发请求,还是返回响应,也要使用Scanner的方式来next,因此就要求服务器返回的响应也要带有\n,使用next读取数据,如果数据中不带有\n等分隔符的话,此时next就会一直阻塞,Scanner是会带有阻塞功能的,

if (!scanner.hasNext()) {// 如果发现后续没有数据了, 此时说明 TCP 的连接是已经断开了的.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;
}
String request = scanner.next();

这里的scanner.hasNext就会阻塞等待请求的到达

  1. 请求到了,有明确的分隔符,返回true
  2. tcp连接断开了,返回false

scanner,可以认为是关联到了服务器这边的socket文件,socket是能感知到tcp断开连接的(本身是系统内核里面会有一系列的流程,四次挥手)

操作系统知道这个事情之后,就会告知socket,对应的scanner读取的文件,就相当于是“无效文件”,类似于读取到EOF这样的效果,使用scanner读文件的时候,就是读到文件末尾,hasNext也是会返回false,一旦tcp连接断开,scanner就相当于读到文件末尾的效果,都是读到EOF,反映到scanner上面就是hasNext为false

Question:

  1. hasNext方法阻塞时间长了就表名TCP连接断开了吗?
  2. 客户端自行断开会影响服务端吗?

Answer:

  1. 不是的,TCP连接断开,hasNext解除阻塞,并返回false,TCP连接仍然存在,但是对方没有发数据过来,hashNext是阻塞的,对方发数据过来了,hasNext解除阻塞,返回true
  2. 在TCP中是这样的,客户端断开连接,服务器是能感知到的
while (true) {// 3.1 读取请求并解析if (!scanner.hasNext()) {// 如果发现后续没有数据了, 此时说明 TCP 的连接是已经断开了的.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}String request = scanner.next();// 3.2 根据请求计算响应String response = process(request);// 3.3 把响应写回给客户端.outputStream.write(response.getBytes(), 0, response.getBytes().length);// 3.4 服务器打印日志System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(), request, response);
}
public void start() {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {Scanner scannerNetwork = new Scanner(inputStream);while (true) {// 1. 从控制台读取数据System.out.print("请输入要发送的数据: ");String request = scanner.next();// 2. 把请求发送给服务器, 发送的请求要带有 \n, 和服务器的 scanner.next 是对应的.//    由于上述通过 next 读到的 request 本身已经没有 \n 结尾了. 需要手动添加上换行request += "\n";outputStream.write(request.getBytes());// 3. 从服务器读取到响应if (!scannerNetwork.hasNext()) {break;}String response = scannerNetwork.next();// 4. 把响应显示到控制台上System.out.println(response);}} catch (Exception e) {e.printStackTrace();}
}

重点理解“客户端下线”操作,当强制终止客户端进程,或者通过代码调用客户端socket,close(),就会使客户端所在的主机的操作系统内核,触发TCP断开连接流程(四次挥手),服务器就能感知到,于是就会在hasNext解除阻塞,并返回false(if这里逻辑取反,于是就进入if语句内部,执行打印 下线 的操作,并break了)

上述代码,还存在一些问题

  • 服务器代码这边,对于accept创建的socket对象,是没有进行关闭操作的

 Socket clientSocket = serverSocket.accept();
//这个东西在processConnection中使用之后没有进行close,这个是不科学的
  1. serverSocket是可以不必特别关闭的,因为生命周期是跟随整个服务器进程的
  2. 客户端的socket也是可以不必特别关闭的

但是服务器的clientSocket就不行了,服务器会对应多个客户端,每个客户端都有一个对应的clientSocket,如果用完了不关闭,就会使当前clientSocket对应的文件描述符得不到释放,引起文件资源泄露

try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {...} catch (IOException e) {e.printStackTrace();
} finally {// 在这里关闭是比较靠谱的做法.// 即使当前 processConnection 在不同的线程中被调用, 也可以正确关闭.clientSocket.close();
}

有的时候,close操作的异常也需要单独处理,没啥太好的方法

  • 当前这个代码,服务器是无法同时给多个客户端提供服务端

使用service操作,虽然有两个客户端了,但是服务器只感知到一个客户端上线,第一个客户端,发来的请求能够顺利处理,第二个客户端的请求就处理不了了,一旦第一个客户端结束,服务器就能立即感知到第二个客户端上线,以及感知到客户端之前的请求,并且立即返回响应

while (true) {// 3.1 读取请求并解析if (!scanner.hasNext()) {// 如果发现后续没有数据了, 此时说明 TCP 的连接是已经断开了的.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}String request = scanner.next();// 3.2 根据请求计算响应String response = process(request);// 3.3 把响应写回给客户端.outputStream.write(response.getBytes(), 0, response.getBytes().length);// 3.4 服务器打印日志System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(), request, response);
}

解决方案:多线程

第一个客户端连接之后,此时accept就返回了,进入到processConnection方法,就在方法内部的while循环,开始循环起来了,第二个客户端来了之后,此时,没有办法执行到第二次accept的(第二个客户端,给服务器打电话,服务器一直没接听!)一方面希望给第一个客户端提供服务,另一方面,还能希望快速第二次调用到accept,我们可以使用多线程

主线程,专门负责循环的处理accept,每次accept获取到一个客户端连接之后,都创建一个新的线程,用新的线程来给客户端循环的提供服务

public void start() throws IOException {System.out.println("服务器启动!");// 能一直扩容// 如果用固定线程个数的线程池, 不太合适, 就限制了最多有多少个客户端同时连接.ExecutorService pool = Executors.newCachedThreadPool();while (true) {Socket clientSocket = serverSocket.accept();// 代码改成多线程的形式, 就不能通过 try ( ) 的方式来关闭 clientSocket 了.// 否则就会使 clientSocket 被立即关闭, 此时 processConnection 还没来得及使用的.
//            Thread t = new Thread(() -> {
//                try {
//                    processConnection(clientSocket);
//                    // clientSocket.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            });
//            t.start();// 把任务添加到线程池中pool.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}}});}
}

如果线程太多,电脑会撑不住,所以这里核心解决方案:IO多路复用 + 多个服务器(分布式系统)

IO多路复用

通过AI可以知道IO多路复用是什么机制!


IO多路复用是一种同步非阻塞的IO模型,它允许单个线程处理多个文件描述符(FD),从而管理多个网络连接或IO流。这种机制使得服务器能够高效地处理大量的并发连接而不需要为每个连接创建一个独立的线程或进程。

IO多路复用主要通过三种机制实现:select、poll和epoll。

  • select:这是最早的IO多路复用机制,它使用一个文件描述符集合来进行监控,并通过内核检查每个FD来确定是否有事件发生。select的缺点包括对文件描述符数量有限制(通常是1024),以及需要在用户态和内核态之间复制文件描述符集合,这会导致额外的性能开销。
  • poll:poll是select的改进版,它没有最大文件描述符数量的限制,并且使用动态数组来存储FD。尽管如此,poll仍然需要遍历整个FD集合来查找哪些FD已经就绪,这在大量FD的情况下效率不高。
  • epoll:这是Linux特有的IO多路复用机制,它比select和poll更高效。epoll使用内核事件表来管理FD,并且不需要复制文件描述符集合,从而减少了数据复制的开销。epoll还支持水平触发(LT)和边缘触发(ET)两种模式,其中边缘触发模式可以避免大量不必要的事件通知。

IO多路复用的优势在于它能够提高单个线程处理多个IO请求的能力,减少了线程创建和上下文切换的开销,提高了系统的并发性能。它在网络编程中特别有用,可以用于实现高性能的服务器和客户端应用程序。

在实际应用中,IO多路复用可以用于网络编程、高性能服务器、文件操作和定时器事件调度等场景。例如,Web服务器可以使用IO多路复用来同时处理大量并发请求,而不会因为某个请求的IO操作而阻塞其他请求的执行。

总结来说,IO多路复用是一种强大的技术,可以在单个线程中处理多个I/O操作,提高程序的实时性能,特别是在处理大量数据、提高实时性能和提高系统性能方面具有非常重要的作用。

当前写的tcp server和client这里,就涉及到三种socket

  • 服务器ServerSocket
  • 服务器Socket(通过这个Socket和客户端提供交互能力)
  • 客户端Socket(通过这个Socket和服务器进行交互)

第二个socket,服务器这边会有多个这样的socket,每个客户端都有一个对应的socket,这个socket在客户端断开连接之后,就不再使用了,就需要关闭掉

第一个和第三个都是生命周期跟随整个进程,程序只要在运行,就需要这个socket,不能提前close的,随着进程结束,这些socket自然释放

何时关闭第二个socket?这个连接用完了之后

private void processConnection(Socket clientSocket) throws IOException;

此处的processConnection这个方法就表示一个客户端连接的,整个处理过程,这个方法执行完毕,就是用完了(这个方法里也是感知到客户端关闭(断开连接)才返回的),此时就可以在这个方法的末尾,进行close了

自定义应用层协议

  • 信息
  • 确定数据的格式
  1. 基于行文本的方式来传输
  2. 基于xml的方式
  3. 基于json
  4. yml
  5. protobuffer:针对要传输的数据进行压缩,虽然可读性不好,但是能够把空间最充分的利用,最节省网络带宽,效率也最高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1552827.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

基于大数据的大屏高速公路收费系统的开发设计与实现SpringBoot+vue

目录 1. 需求分析 2. 技术选型 3. 系统架构设计 4. 开发实现 5. 代码示例和效果演示 6. 持续优化 由于我国高速公路的建设和发展与国外先进国家有很大差距。在高速公路建成后,收费系统往往选用国外的成熟产品。虽然这些产品在功能上基本满足了高速公路收费的要…

【AI大模型】深入Transformer架构:编码器部分的实现与解析(上)

目录 🍔 编码器介绍 🍔 掩码张量 2.1 掩码张量介绍 2.2 掩码张量的作用 2.3 生成掩码张量的代码分析 2.4 掩码张量的可视化 2.5 掩码张量总结 🍔 注意力机制 3.1 注意力计算规则的代码分析 3.2 带有mask的输入参数: 3.…

电子竞技信息交流平台+ssm论文源码调试讲解

2系统关键技术 2.1 微信小程序 微信小程序,简称小程序,英文名Mini Program,是一种全新的连接用户与服务的方式,可以快速访问、快速传播,并具有良好的使用体验[1]。 小程序的主要开发语言是JavaScript,它与…

利用PDLP扩展线性规划求解能力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

【Maven】依赖管理,Maven仓库,Maven核心功能

Maven 是一个项目管理工具,基于 POM(Project Object Model,项目对象模型)的概念,Maven 可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件 大白话:Maven 是一个项目管理工…

IDEA 2024将Java项目(module)打成JAR包

说明:标题中所说的项目在IDEA中被称为Module(模块),这里实际上是要将IDEA中的建立的Module打成JAR包。 目标:将module打包为JAR文件,随后在另一Module中导入并使用该JAR包。流程:新建chpt03与test两个Module&#xff0…

解决银河麒麟操作系统V10软件包架构不符问题

TOC 💖The Begin💖点点关注,收藏不迷路💖 在银河麒麟桌面操作系统V10中安装软件包时,如果遇到“软件架构与本机架构不符”的提示,可以尝试以下步骤来解决问题: 1. 确认架构一致性 查看本机架构…

小学一年级教材识字表,写字表,笔画名称表,偏旁名称表大全,方便大家学习打印!

前言 本次巧手打字通(一起来打字)小课堂文章主要为大家带来小学一年级语文识字表、写字表、笔画名称表以及偏旁名称表。这份资料不仅涵盖了一年级语文课程中必须掌握的核心字词,还列出教程里的笔画名称表,旨在帮助孩子们在识字的…

开源模型应用落地-模型微调-语料采集-数据核验(三)

一、前言 在自然语言处理(NLP)的快速发展中,语料采集作为基础性的步骤显得尤为重要。它不仅为机器学习模型提供了所需的训练数据,还直接影响模型的性能和泛化能力。随着数据驱动技术的不断进步,如何有效并高效地收集、清洗和整理丰富多样的语料,已成为研究者和工程师们亟…

使用OneAPI+Ollama+Dify搭建一个兼容OpenAI的API发布及AI应用开发系统(二)客户端设置

这一编我们介绍Ollama客户端的设置,那么客户端在这里指的就是你放在家里的Ollama服务器,通过与VPS里安装的OneAPI配合,从而实现了为Ollama生成API访问的服务,并为后端服务器提供安全保障。 一:安装客户端软件 客户端…

【Linux】进程优先级、调度、命令行参数:从理论到实践(二)

🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 🚀 前言一: 🔥 进程优先级 🍵 基本概念🍵 查看系统进程🍵 PRI and NI🍵 PRI vs NI🍵 用to…

【数据管理】数据脱敏解决方案(word原件)

1 概述 1.1 数据脱敏定义 1.2 数据脱敏原则 1.2.1基本原则 1.2.2技术原则 1.2.3管理原则 1.3 数据脱敏常用方法 3.1.1泛化技术 3.1.2抑制技术 3.1.3扰乱技术 3.1.4有损技术 1.4 数据脱敏全生命周期 2 制定数据脱敏规程 3 发现敏感数据 4 定义脱敏规则 5 执…

本科生已不够 AI公司雇佣各领域专家训练大模型

9月29日消息,人工智能模型的性能在很大程度上依赖于其训练数据的质量。传统方法通常是雇用大量低成本劳动力对图像、文本等数据进行标注,以满足模型训练的基本需求。然而,这种方式容易导致模型在理解和生成信息时出现“幻觉”现象&#xff0c…

<<迷雾>> 第5章 从逻辑学到逻辑电路(5)--异或门 示例电路

!ABA!B 的逻辑电路组成 info::操作说明 鼠标单击开关切换开合状态 注: 这个实际就是 异或门, 当两个输入相异时输出高电平, 否则输出低电平 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/cyjsjdmw-examples/assets/circuit/cyj…

读数据湖仓04数据架构与数据工程

1. 大容量存储器 1.1. 几乎是到最后时刻,大容量存储器才被引入基础数据的基础设施中 1.1.1. 分析人员通常不会直接在大容量存储器中进行数据分析 1.1.2. 大容量存储器在基础数据中扮演的角色也特别重要,它能够在许多方面支持数据分析人员自由灵活地完成…

从零开始搭建UVM平台(七)-加入monitor

书接上回: 从零开始搭建UVM平台(一)-只有uvm_driver的验证平台 从零开始搭建UVM平台(二)-加入factory机制 从零开始搭建UVM平台(三)-加入objection机制 从零开始搭建UVM平台(四&…

Github 2024-10-02C开源项目日报 Top9

根据Github Trendings的统计,今日(2024-10-02统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目9BitBake项目1Netdata: 开源实时监控平台 创建周期:4020 天开发语言:C协议类型:GNU General Public License v3.0Star数量:68982 个For…

JAVA开源项目 周边产品销售网站 计算机毕业设计

本文项目编号 T 061 ,文末自助获取源码 \color{red}{T061,文末自助获取源码} T061,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

【算法】0/1背包问题

背包中有一些物品,每件物品有它的价值与重量,给定一个重量,在该重量范围内取物品(每件物品不可重复取),求最大价值。 将需求转化为表格,每一行中的每个格子代表可选哪些下标的物品在总重量限额内…

VMware Aria Operations 8.18 发布,新增功能概览

VMware Aria Operations 8.18 - 多云 IT 运维管理 通过统一的高性能平台,实现跨私有云、混合云和多云环境的 IT 运维管理。 请访问原文链接:https://sysin.org/blog/vmware-aria-operations/,查看最新版。原创作品,转载请保留出…