Java 网络编程基础

网络通信三要素

此笔记来之与黑马.B站的视频是真的高

基本的通信架构

  • 基本的通信架构有2种形式:CS架构(Client 客户端/ Server 服务端)、BS架构( Browser 浏览器/ Server 服务端)。

image-20241005174021564

IP 地址

IP(InternetProtocol):全称 “互联网协议地址”,是分配给上网设备的唯一标志。
IP 地址有两种形式:IPv4, IPv6

image-20241005174700193

image-20241005174812691

image-20241005175206940

image-20241005175323233

⚠️ 右上角框框为 运营商 id

公网 IP, 内网 IP
  • **公网 IP:**是可以连接互联网的 IP 地址;内网 IP:也叫局域网 IP,只能组织机构内部使用。
  • 192.168.开头的就是常见的局域网地址,范围即为 192.168.0.0–192.168.255.255,专门为组织机构内部使用。
特殊 IP 地址:
  • 127.0.0.1、localhost:代表本机 IP,只会寻找当前所在的主机。
IP 常用命令:
  • ipconfig:查看本机IP地址。
  • ping IP地址:检查网络是否连通。
InnetAddress (IP 地址)

image-20241005175829937

端口号

标记正在计算机设备上运行的应用程序的,被规定为一个 16位 的二进制,范围是 0 ~ 65535。

分类
  • 周知端口:0 ~ 1023,被预先定义的知名应用占用(如:HTTP占用80,FTP占用21)

  • **注册端口:**1024 ~ 49151,分配给用户进程或某些应用程序。

  • 动态端口:49152 到 65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。

    ⚠️ 注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错。

通信协议

网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。

image-20241005190510717

开放式网络互联标准:OSI 网络参考模型
  • OSI 网络参考模型:全球网络互联标准

image-20241005190553340

传输层的2个通信协议
  • UDP(User Datagram Protocol):用户数据报协议;TCP(Transmission Control Protocol):传输控制协议。
UDP协议

特点:无连接、不可靠通信。诵信效率高!语音诵话视频直播

  • 不事先建立连接,数据按照包发,一包数据包含:自己的 IP、程序端口,目的地 IP、程序端口和数据(限制在 64KB 内)等。
  • 发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的。

image-20241005191313754

TCP 协议
  • 特点:面向连接、可靠通信。
  • TCP 的最终目的:要保证在不可靠的信道上实现可靠的传输。
  • TCP 主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。

image-20241005191628265

四次挥手

image-20241005191731199

ContentsUDP通信-快速入门

Java提供了一个 java.net.DatagramSocket 类来实现 UDP 通信。

image-20241005192053753

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建客户对象(发数据出去的人)
        DatagramSocket socket = new DatagramSocket();
        // 2. 创建数据包对象封装要发出去的数据(创建一个数据包)
        /** public DatagramPacket(byte buf[], int length,
        	InetAddress address, int port)
        	参数一: 封装要发出去的数据
        	参数二:发送出去的数据大小(字节个数)
        	参数三:服务端的 IP 地址(找到服务端主机)
        	参数四:服务端程序的端口
        */
        
        byte[] byres = "我是快乐的客户端,我爱你 abc".getBytes();
        DatagramPacket packet = new DatagramPacket(bytes, bytets.length,
                                                  InetAddress.getLocalHost(), port: 6666);
        
        // 3. 正式发送这个数据包的数据出去了
        socket.send(packet);
        System.out.println("客户端数据发送完毕~~");
        socket.close(); // 释放数据!
    }
}

class Server {
    public static void main(Stirng[] args) throws Exception {
        System.out.println("-----服务器端启动");
        // 1. 创建一个服务端口(创建一个接数据包的人) 注册端口
        DatagramSocker socket = new DatagramSocket(port: 6666);
        
        // 2. 创建一个数据包对象,用于接收数据的(创建一个数据包)
        byte[] buffer = new byte[1024 * 64]; // 64 KB
        DatagramPacket packet = new DatagramPacket(buffer.length);
        
        // 3. 开始正式使用数据包来接收客户端发来的数据
        socket.receive(packet);
        
        // 4.从字节数组中,把接收到的数据直接打印出来
        // 接收多少就倒出多少
        int len = packet.getLength();
        
        String res = new String(buffer, 0, len);
        System.out.println(rs);
        
        System.out.println(packet.getAddress().getHostAddresss());
        System.out.prinlnt(packet.getPort());
        
        socket.close(); //释放资源
    }
}

UDP 通信-多发多收

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建客户对象(发数据出去的人)
        DatagramSocket socket = new DatagramSocket();
        // 2. 创建数据包对象封装要发出去的数据(创建一个数据包)
        /** public DatagramPacket(byte buf[], int length,
        	InetAddress address, int port)
        	参数一: 封装要发出去的数据
        	参数二:发送出去的数据大小(字节个数)
        	参数三:服务端的 IP 地址(找到服务端主机)
        	参数四:服务端程序的端口
        */
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("请说: ");
            String msg = scanner.nextLine();
            
            if ("exit".equals(msg)) {
                break;
            }
            
             byte[] byres = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(bytes, bytets.length,
                                                      InetAddress.getLocalHost(), port: 6666);

            // 3. 正式发送这个数据包的数据出去了
            socket.send(packet);
            System.out.println("客户端数据发送完毕~~");
        }
        
         socket.close(); // 释放数据!
    }
}

class Server {
    public static void main(Stirng[] args) throws Exception {
        System.out.println("-----服务器端启动");
        // 1. 创建一个服务端口(创建一个接数据包的人) 注册端口
        DatagramSocker socket = new DatagramSocket(port: 6666);
        
        // 2. 创建一个数据包对象,用于接收数据的(创建一个数据包)
        byte[] buffer = new byte[1024 * 64]; // 64 KB
        DatagramPacket packet = new DatagramPacket(buffer.length);
        
        while (true) {
            System.out.println("服务端启动");
            // 3. 开始正式使用数据包来接收客户端发来的数据
            socket.receive(packet);

            // 4.从字节数组中,把接收到的数据直接打印出来
            // 接收多少就倒出多少
            int len = packet.getLength();

            String res = new String(buffer, 0, len);
            System.out.println(rs);

            System.out.println(packet.getAddress().getHostAddresss());
            System.out.printtln(packet.getPort());   
            System.out.println("--------------分割线---------------");
        }
        socket.close(); //释放资源
    }
}

TCP 通信-快速入门

Java 提供了一个 java.net.Socket 类来实现 TCP 通信。

image-20241005200654684

image-20241005200740292

public class Client {
	public static void main(String[] args) throws Exception {
        // 1. 创建 Socket 对象,并同时请求与服务端程序的连接
		Socket socket = new Socket("127.0.0.1", 8888);
        
        // 2.从 socket 通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();
        
        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        
        // 4.开始写数据出去了
        dos.writeUTF("在一起, 好吗?");
        dos.close();
        
        socket.close(); // 释放连接资源
    }
}

public class Server {
    public static void main(String[] args) {
        
    }
}

服务端是通过 java.net包 下的 ServerSocket 类来实现的。

image-20241005201852781

public class Server {
    public static void (String[] args) throws Exception {
        // 1. 创建 ServerSocket的对象, 同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(port: 8888);
        
        // 2.使用 serverSocket 对象,调用一个 accept 方法,等待客户端的连接请求
        Socket socket = serverSocket.accept();
        
        // 3. 从socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();
        
        // 5.使用数据输入流读取客户端发送过来的消息
        String rs = dis.readUTF();
        System.out.println(rs);
        
        System.out.println(socket.getRemoteSocketAddress())
            
        dis.close();
        socket.close();
    }
}

TCP 通信-多发多收

public class Client {
	public static void main(String[] args) throws Exception {
        // 1. 创建 Socket 对象,并同时请求与服务端程序的连接
		Socket socket = new Socket("127.0.0.1", 8888);
        
        // 2.从 socket 通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();
        
        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        
        Scanner sc = new Scanner(System.in);
        while (true) {
            
            System.out.println("请说: ");
            String msg = sc.nextLine();
            
            // 一旦用户输入了 exit, 就退出了客户端程序
            if ("exit".equals(msg)) {
                System.out.println("欢迎您下次光临!! 退出成功!");
                break;
            }
            
            // 4.开始写数据输出了
            dos.writeUTF(msg);
            dos.flush();
        }
		
        dos.close();
        socket.close(); // 释放连接资源
    }
}
public class Server {
    public static void (String[] args) throws Exception {
        // 1. 创建 ServerSocket的对象, 同时为服务器注册端口
        ServerSocket serverSocket = new ServerSocket(port: 8888);
        
        // 2.使用 serverSocket 对象,调用一个 accept 方法,等待客户端的连接请求
        Socket socket = serverSocket.accept();
        
        // 3. 从socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();
        
        // 4.把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);
        
        while (true) {
            // 5.使用数据输入流读取客户端发送过来的消息
            try {
                String rs = dis.readUTF();
            	System.out.println(rs);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(socket.getRemoteSocketAddress() + "离线了");
                break;
            }
        	
        }
            
        dis.close();
        socket.close();
    }
}

TCP 通信-同时接收多个客户端

image-20241005205708921

public class Client {
	public static void main(String[] args) throws Exception {
        // 1. 创建 Socket 对象,并同时请求与服务端程序的连接
		Socket socket = new Socket("127.0.0.1", 8888);
        
        // 2.从 socket 通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();
        
        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        
        Scanner sc = new Scanner(System.in);
        while (true) {
            
            System.out.println("请说: ");
            String msg = sc.nextLine();
            
            // 一旦用户输入了 exit, 就退出了客户端程序
            if ("exit".equals(msg)) {
                System.out.println("欢迎您下次光临!! 退出成功!");
                break;
            }
            
            // 4.开始写数据输出了
            dos.writeUTF(msg);
            dos.flush();
        }
		
        dos.close();
        socket.close(); // 释放连接资源
    }
}

public class Server {
    public static void main(String[] args) {
        System.out.println("--------服务器启动成功--------------");
        // 1. 创建ServerSocket的对象,同时为服务端注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        
        while (true) {
            
            // 2. 使用serverSocket对象,调用一个 accept 方法,等待客户端连接请求
            Socket socket = serverSocket.accept();
            
            // 3. 把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            new ServerReaderThread(socket).start();
        }
    }
}
public class ServerReaderThread extends Thread {
	private Socket socket;
    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }
    
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            
            while (true) {
            	String msg = dis.readUTF();
                System.out.println(msg);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

TCP通信-综合案例

即时通信-群聊

image-20241005211636643

public class Client {
	public static void main(String[] args) throws Exception {
        // 1. 创建 Socket 对象,并同时请求与服务端程序的连接
		Socket socket = new Socket("127.0.0.1", 8888);
        
        // 创建一个独立的线程 负责随机从socket中接收服务端发送过来的消息
        new ClentReaderThread(socket).start();
        // 2.从 socket 通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();
        
        // 3.把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        
        Scanner sc = new Scanner(System.in);
        while (true) {
            
            System.out.println("请说: ");
            String msg = sc.nextLine();
            
            // 一旦用户输入了 exit, 就退出了客户端程序
            if ("exit".equals(msg)) {
                System.out.println("欢迎您下次光临!! 退出成功!");
                break;
            }
            
            // 4.开始写数据输出了
            dos.writeUTF(msg);
            dos.flush();
        }
		
        dos.close();
        socket.close(); // 释放连接资源
    }
    
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                } catch (Exception e) {
                    System.out.println("自己下线了: " + socket.getRemoteSock());
                }
            }
        }
    }
}
public class ClentReaderThread extends Thread {
    private Socket socket;
    public ClentReaderThread(Socket socket) {
        this.socket = socket;
    }
}

public class Server {
    public static List<Socket> onLineSockets = new ArrayList<>();
    public static void main(String[] args) {
        
        System.out.println("--------服务器启动成功--------------");
        // 1. 创建ServerSocket的对象,同时为服务端注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        
        while (true) {
            
            // 2. 使用serverSocket对象,调用一个 accept 方法,等待客户端连接请求
            Socket socket = serverSocket.accept();
            onLineSockets.add(socket); 
            System.out.println("有人上线了: " + socket.getRemoteSocketAddress());
            // 3. 把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            new ServerReaderThread(socket).start();
        }
    }
}
public class ServerReaderThread extends Thread {
	private Socket socket;
    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }
    
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            
            while (true) {
            	String msg = dis.readUTF();
                System.out.println(msg);
                
                sendMsgToAll(msg); // 发送给所有的客户端
            }
            
        } catch (IOException e) {
            System.out.println("有人下线了: " + socket.getRemoteSocketAddress());
            Server.onLineSockets.remove(socket);
            e.printStackTrace();
        }
    }
    
    private void sendMsgToAll(String msg) throws IOExecption {
		// 发送给所有在线的 socket 管道接收
        for (Socket onLineSocket : Server.onLineSockets) {
            OUtputStream os = onLineSocket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            dos.write(msg);
            dos.flush();
        }
    }
}

实现一个 BS 架构(浏览器+程序)

要求从浏览器中访问服务器, 并立即让服务器响应一个很简单的网页给浏览器展示, 网页内容就是“黑马程序员666”

image-20241005213841638

image-20241005213929070

public class ServerReaderThread extends Thread {
    private Socket socket;
    public SeverReaderThread(Socket socket) {
        this.socket = socket;
    }
    
    @Override
    public void run() {
		// 立即响应一个网页内容:"黑马程序员"给浏览器展示
        try {
            OutputStream os = socket.getOutputStream();
            PrintStream ps = new PrintStream(os);
            ps.println("HTTP/1.1 200 OK");
            ps.println("Content-Type:text/html;charset=UTF-8");
            ps.println(); // 必须换行
            ps.println("<div style="color:red;font-size:120px;text-align:center" 黑马程序员磊哥</div>);
        } cathch (Exception e) {
            e.printStackTrace();
        }
    }
}

线程池优化 BS 架构

可以参考博主这篇JUC笔记
image-20241005214829542


public class Server {
    public static List<Socket> onLineSockets = new ArrayList<>();
    public static void main(String[] args) {
        
        System.out.println("--------服务器启动成功--------------");
        // 1. 创建ServerSocket的对象,同时为服务端注册端口
        ServerSocket serverSocket = new ServerSocket(8888);
        
        // 创建出一个线程池,负责处理通信管道的任务
        ThreadPoolExecutor pool = new ThreadPoolExecutor(16*2, 16*2, new ArrayBlockingQueue<>(8), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        
        while (true) {
            
            // 2. 使用serverSocket对象,调用一个 accept 方法,等待客户端连接请求
            Socket socket = serverSocket.accept();
            pool.execute(new ServerReaderRunnable(socket))
        }
    }
}
public class ServerReaderThread extends Runnable {
    private Socket socket;
    public SeverReaderThread(Socket socket) {
        this.socket = socket;
    }
    
    @Override
    public void run() {
		// 立即响应一个网页内容:"黑马程序员"给浏览器展示
        try {
            OutputStream os = socket.getOutputStream();
            PrintStream ps = new PrintStream(os);
            ps.println("HTTP/1.1 200 OK");
            ps.println("Content-Type:text/html;charset=UTF-8");
            ps.println(); // 必须换行
            ps.println("<div style="color:red;font-size:120px;text-align:center" 黑马程序员磊哥</div>);
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java中的break、continue和return语句

break、continue和return break语句引入基本介绍基本语法示意图注意事项练习String字符串的比较 continue跳转控制语句基本介绍基本语法示意图 return跳转控制语句 break语句 引入 随机生成1-100的一个数&#xff0c;直到生成了97这个数&#xff0c;看看你一共用了几次&#…

Electron 使⽤ electron-builder 打包应用

electron有几种打包方式&#xff0c;我使用的是electron-builder。虽然下载依赖的时候让我暴躁&#xff0c;使用起来也很繁琐&#xff0c;但是它能进行很多自定义&#xff0c;打包完成后的体积也要小一些。 安装electron-builder&#xff1a; npm install electron-builder -…

教育领域的技术突破:SpringBoot系统实现

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

传感器模块编程实践(二)W5500 SPI转以太网模块简介及驱动源码

文章目录 一.概要二.W5500芯片介绍W5500通讯协议介绍 三.W5500模块介绍四.W5500模块原理图五.W5500以太网模通讯实验六.CubeMX工程源代码下载七.小结 一.概要 我们介绍过单片机的以太网系统一般是由&#xff1a;单片机MACPHYRJ45。有些单片机比如STM32F407VET6芯片内部自带MAC…

Vue基础(2)检测数据原理~生命周期

文章目录 检测数据原理1.更新时遇到的问题2.检测数据的原理-对象3. vue.set()的使用 收集表单数据过滤器内置指令1.v-text2.v-html3.v-cloak4.v-once5.v-pre 自定义指令生命周期1.挂载流程2.更新流程3.销毁流程 检测数据原理 1.Vue会监视data中的所有层次的数据 2.如何监测对象…

学习资料库系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;观看记录管理&#xff0c;基础数据管理&#xff0c;论坛信息管理&#xff0c;公告信息管理&#xff0c;轮播图信息 微信端账号功能包括&#xff1a;系统首页&#xff0c;阅读资…

OpenAI在周四推出了一种与ChatGPT互动的新方式——一种名为“Canvas”的界面

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

界星空科技漆包线行业称重系统

万界星空科技为漆包线行业提供的称重系统是其MES制造执行系统解决方案中的一个重要组成部分。以下是对该系统的详细介绍&#xff1a; 一、系统概述 万界星空科技漆包线行业称重系统&#xff0c;是集成在MES系统中的一个功能模块&#xff0c;专门用于漆包线生产过程中的重量检…

Pikachu-unsafe upfileupload-getimagesize

什么是getimagesize()&#xff1f; getimagesize()是PHP中用于获取图像的大小和格式的函数。它可以返回一个包含图像的宽度、高度、类型和MIME类型的数组。 由于返回的这个类型可以被伪造&#xff0c;如果用这个函数来获取图片类型&#xff0c;从而判断是否时图片的话&#xff…

懒洋洋浅谈--机器学习框架

机器学习&#xff0c;这个词汇听起来就像是科幻小说里那些能够自我进化的机器人一样神秘而强大。但别担心&#xff0c;让我用一种更接地气的方式来揭开它的神秘面纱。 关于机器学习&#xff0c;有一个非常有意思的介绍误闯机器学习&#xff08;第一关-概念和流程&#xff09;-C…

【FPGA开发】Modelsim如何给信号分组

前面已经发布过了一篇关于 Modelsim 的入门使用教程&#xff0c;针对的基本是只有一个源文件加一个仿真tb文件的情况&#xff0c;而实际的工程应用中&#xff0c;往往是顶层加多个底层的源文件结构&#xff0c;如果不对信号进行一定的分组&#xff0c;就会显得杂乱不堪&#xf…

GAMES101(19节,相机)

相机 synthesis合成成像&#xff1a;比如光栅化&#xff0c;光线追踪&#xff0c;相机是capture捕捉成像&#xff0c; 但是在合成渲染时&#xff0c;有时也会模拟捕捉成像方式&#xff08;包括一些技术 动态模糊 / 景深等&#xff09;&#xff0c;这时会有涉及很多专有名词&a…

阿里云ACP认证考试题库

最近有好些同学&#xff0c;考完阿里云ACP了&#xff0c;再来跟我反馈&#xff1a;自己花700买的阿里云ACP题库&#xff0c;结果答案是错的&#xff01; 或者考完后发现&#xff0c;买的阿里云ACP题库覆盖率只有50%&#xff01; 为避免大家继续踩坑&#xff0c;给大家分享一个阿…

洗车行软件系统有哪些 佳易王洗车店会员管理系统操作教程#洗车店会员软件试用版下载

一、前言 【试用版软件下载可点击本文章最下方官网卡片】 洗车行软件系统有哪些 佳易王洗车店会员管理系统操作教程#洗车店会员软件试用版下载 洗车管理软件应用是洗车业务的得力助手&#xff0c;实现会员管理及数据统计一体化&#xff0c;助力店铺高效、有序运营。 洗车项…

CSS | 响应式布局之媒体查询(media-query)详解

media type(媒体类型)是CSS 2中的一个非常有用的属性&#xff0c;通过media type我们可以对不同的设备指定特定的样式&#xff0c;从而实现更丰富的界面。media query(媒体查询)是对media type的一种增强&#xff0c;是CSS 3的重要内容之一。随着移动互联网的发展&#xff0c;m…

【CSS Tricks】css动画详解

目录 引言一、动画关键帧序列二、动画各属性拆解1. animation-name2. animation-duration3. animation-delay3.1 设置delay为正值3.2 设置delay为负值 4. animation-direction5. animation-iteration-count6. animation-fill-mode7. animation-play-state8. animation-timing-f…

读数据湖仓08数据架构的演化

1. 数据目录 1.1. 需要将分析基础设施放置在数据目录(Data Catalogue)的结构中 1.1.1. 元数据 1.1.2. 数据模型 1.1.3. 本体 1.1.4. 分类标准 1.2. 数据目录类似于图书馆的图书检索目录 1.2.1. 先通过图书馆的图书检索目录进行查找&#xff0c;以便快速找到所需的图书 1…

【AGC005D】~K Perm Counting(计数抽象成图)

容斥原理。 求出f(m) &#xff0c;f(m)指代至少有m个位置不合法的方案数。 怎么求&#xff1f; 注意到位置为id&#xff0c;权值为v ,不合法的情况&#xff0c;当且仅当 v idk或 v id-k 因此&#xff0c;我们把每一个位置和权值抽象成点 &#xff0c;不合法的情况之间连一…

NASA:北极植被地块 ATLAS 项目 北坡和苏厄德半岛,明尼苏达州,1998-2000 年

目录 简介 摘要 代码 引用 网址推荐 0代码在线构建地图应用 机器学习 Arctic Vegetation Plots ATLAS Project North Slope and Seward Peninsula, AK, 1998-2000 简介 文档修订日期&#xff1a;2018-12-31 数据集版本&#xff1a;1 本数据集提供了在北极陆地-大气系统…

基于auth2的单点登录原理理解

创作背景&#xff1a;基于auth2实现企业门户与业务系统的单点登录跳转。 架构组成&#xff1a;4A统一认证中心&#xff0c;门户系统&#xff0c;业务系统&#xff0c;用户&#xff1b; 实现目标&#xff1a;用户登录门户系统后&#xff0c;可通过点击业务系统菜单&#xff0c…