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

JavaEE 网络编程

JavaEE 网络编程

文章目录

  • JavaEE 网络编程
    • 引子
    • 1. 网络编程-相关概念
      • 1.1 基本概念
      • 1.2 发送端和接收端
      • 1.3 请求和响应
      • 1.4 客户端和服务端
    • 2. Socket 套接字
      • 2.1 数据包套接字通信模型
      • 2.2 流套接字通信模型
      • 2.3 Socket编程注意事项
    • 3. UDP数据报套接字编程
      • 3.1 DatagramSocket
      • 3.2 DatagramPacket
    • 4. TCP流套接字编程
      • 4.1 ServerSocket
      • 4.2 Socket

引子

如今,我们在任意浏览器打开在线视频网站,如b站去看视频,实质上便是通过网络来获取网络上的视频资源:

在这里插入图片描述

与本地打开视频文件类似,只是当前的视频文件资源的来源是网络,相比于本地资源来说,网络提供了更为丰富的网络资源:

在这里插入图片描述

所谓的网络资源,其实就是在网络中可以获取的各种数据资源。

而所有的网络资源,都是通过网络编程来进行数据传输的。

1. 网络编程-相关概念

1.1 基本概念

网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)

在这里插入图片描述

网络编程的目的便是提供网络上不同的主机基于网络来传输数据资源,如图:

进程A:编程来获取网络资源;进程B:编程来提供网络资源

1.2 发送端和接收端

在一次网络数据传输时:

  • 发送端: 数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机;

  • 接收端: 数据的接受方进程,称为接收端。接收端主机即网络通信中的目的主机;

  • 收发端: 发送端和接收端两端,也简称收发端;

在这里插入图片描述

:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。

1.3 请求和响应

一般来说,获取一个网络资源,涉及到两次网络数据传输:

  • 第一次:请求数据的发送;
  • 第二次:响应数据的发送;

好比在饭店点一份炒饭,先要发起请求:点一份炒饭,再有饭店提供对应的响应:提供一份炒饭

在这里插入图片描述

1.4 客户端和服务端

  • 服务端: 在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外服务;
  • 客户端: 获取服务的一方进程,称为客户端;

一般的客户端服务端模型提供以下操作:

  1. 客户端获取服务资源

    在这里插入图片描述

  2. 客户端保存资源在服务端

    在这里插入图片描述

最常见的模型是,客户端是指给用户使用的程序,服务端是提供用户服务的程序

  1. 客户端先发送请求到服务端;
  2. 服务端根据请求数据,执行相应的业务处理;
  3. 服务端返回响应:发送业务处理结果;
  4. 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存数据资源的处理结果)

在这里插入图片描述

2. Socket 套接字

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程

Socket套接字主要针对传输层协议分为如下三类:

数据报套接字: 使用传输层UDP协议

UDP,即User Datagram Protocol (用户数据报协议),传输层协议。

特点:

  • 无连接;
  • 不可靠传输;
  • 面向数据报;
  • 有接收缓冲区,无发送缓冲区;
  • 大小受限:一次最多传输64K;

对于数据报来说,可以简单理解为,传输数据是一块一块的,发送一块数据假如要100个字节,必须一次发送,接收也必须一次接收100个字节,而不能分100次,每次接收1个字节。

流套接字: 使用传输层TCP协议

TCP,即Transmission Control Protocol (传输控制协议),传输层协议。

特点:

  • 有连接;
  • 可靠传输;
  • 面向字节流;
  • 有接收缓冲区,也有发送缓冲区;
  • 大小不限;

对于字节流来说,可以简单理解为,传输数据是基于IO流的,流式数据的特征就是在IO流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收。

原始套接字: 用于自定义传输层协议,用于读写内核没有处理的IP协议数据(了解)。

2.1 数据包套接字通信模型

对于UDP协议来说,具有无连接,面向数据报的特征,即每次都是没有建立连接,并且一次发送全部数据报,一次接收全部的数据报

Java中使用UDP协议通信,主要基于 DatagramSocket类来创建数据包套接字,并使用 DatagramPacket作为发送或接收的UDP数据报。

一般发送及接收UDP数据报的流程如下:

在这里插入图片描述

2.2 流套接字通信模型

对于TCP协议来说,其具有连接且面向字节流的特征,在进行网络通信前需要通过accept()接收连接请求建立连接后才可进行通信:

在这里插入图片描述

2.3 Socket编程注意事项

在这里插入图片描述

  1. 客户端和服务端:开发时,经常是基于一个主机开启两个进程作为客户端和服务端,但真实的场景一般是不同主机;

  2. 需要注意目的IP和目的端口号,标识了一次数据传输时要发送数据的终点主机和进程

  3. 如果一个进程A已经绑定了一个端口,再启动一个进程B绑定该端口,就会报错,这种情况也叫端口被占用。对于Java进程来说,端口被占用常见报错信息如下:

    在这里插入图片描述

    对此,如果占用端口的进程A不需要运行,可以关闭A后再启动需要绑定该端口的进程B;如果需要运行A进程,则可以修改进程B的绑定端口,换为其它没有使用的端口。

3. UDP数据报套接字编程

以下是UDP数据报编程相关的API:

3.1 DatagramSocket

DatagramSocket是UDP Socket 用于发送和接收UDP的数据报。

DatagramSocket构造方法

方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端

DatagramSocket方法

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

3.2 DatagramPacket

DatagramPacket是UDP Socket发送和接收的数据报,传递的数据内容参数都存储在由它构建的对象中。

DatagramPacket构造方法

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造一个DatagramPacket用来接收数据报,接收的数据报保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[] offset, int length, SocketAddress address)构造一个DatagramPacker用来发送数据报,发送的数据为字节数组(第一个参数buff)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

DatagramPacket方法

方法签名方法说明
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,和获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据

在UDP客户端发送数据报时,需要传入SocketAddress,该对象可以使用InetSocketAddress来创建

方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

代码示例

UDP Echo Server(服务器)

package netWork;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 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();}
}

在这里插入图片描述

UDP Echo Client(客户端)

package netWork;import java.io.IOException;
import java.net.*;
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 {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("->"); // 提示用户接下来要输入内容// 1. 从控制台读取要发送的请求数据if (!scanner.hasNext()) {break;}String request = scanner.next();// 2. 构造请求并发送DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length, InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 3. 读取服务器的响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 4. 把响应显示到控制台上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();}
}

在这里插入图片描述

UDP Dict Server(字典服务器)

编写一个英译汉的服务器,只需要重写process

package netWork;import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;public class UdpDictServer extends UdpEchoServer{HashMap<String, String> map = new HashMap<>();public UdpDictServer(int port) throws SocketException {super(port);map.put("cat", "猫");map.put("dog", "狗");map.put("apple", "苹果");}@Overridepublic String process(String request) {return map.getOrDefault(request, "所查单词不存在!");}public static void main(String[] args) throws IOException {UdpDictServer server = new UdpDictServer(9090);server.start();}
}

在这里插入图片描述

:因为此处使用的字典服务器与上述回显服务器端口号相同,如果同时启动会报错,因此需要关闭其中一个服务器才能使用!

4. TCP流套接字编程

以下是TCP流编程相关的API:

4.1 ServerSocket

ServerSocket是创建TCP服务端Socket的API

ServerSocket构造方法

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket方法

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

4.2 Socket

Socket有两种存在形式:

  • 一种是客户端Socket
  • 另一种是服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。

Socket构造方法

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并于对应IP的主机上,对应端口的进程建立连接

Socket方法

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

代码示例

TCP Echo Server(服务器)

package netWork;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*TCP 回显服务器*/
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("服务器启动!");while(true) {// 通过 accept 方法来“接听电话”,然后才能进行通信Socket clientSocket = serverSocket.accept(); // 在未接收到客户端连接请求前到此处将处于阻塞状态processConnection(clientSocket);}}// 通过这个方法来处理一次连接,连接建立的过程中就会涉及到多次的请求响应交互public 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();}
}

在这里插入图片描述

TCP Echo Client(客户端)

package netWork;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() throws IOException {System.out.println("客户端启动!");try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {Scanner scannerConsole = new Scanner(System.in);Scanner scannerNetWork = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);while (true) {System.out.print("->");// 1. 从控制台读取输入的字符串if (!scannerConsole.hasNext()) {break;}String request = scannerConsole.next();// 2. 将请求发送给服务器// 这里需要使用 println 来发送,为了让发送的请求末尾带有 \n , 这里与服务器的 scanner.next 相呼应printWriter.println(request);// 通过这个 flush 主动刷新缓冲区,确保数据真的发出去了printWriter.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.7", 9090);client.start();}
}

在这里插入图片描述

为了能够响应多个客户端请求,可以进行以下修改:

注:如果想在IDEA中同时打开多个相同的客户端,可以按一下步骤修改设置:

在这里插入图片描述

  • 给每个客户端都分配一个线程

    public void start() throws IOException {System.out.println("服务器启动!");while(true) {// 通过 accept 方法来“接听电话”,然后才能进行通信Socket clientSocket = serverSocket.accept();// processConnection(clientSocket);Thread t = new Thread(() -> {processConnection(clientSocket);});t.start();}}
    

    在这里插入图片描述

  • 为了避免频繁创建销毁线程,可以引入线程池

     public void start() throws IOException {System.out.println("服务器启动!");// 可通过调用线程池的方式完成多个客户端的同时连接ExecutorService pool = Executors.newCachedThreadPool();while(true) {// 通过 accept 方法来“接听电话”,然后才能进行通信Socket clientSocket = serverSocket.accept();pool.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}
    

    在这里插入图片描述

相关文章:

JavaEE 网络编程

JavaEE 网络编程 文章目录 JavaEE 网络编程引子1. 网络编程-相关概念1.1 基本概念1.2 发送端和接收端1.3 请求和响应1.4 客户端和服务端 2. Socket 套接字2.1 数据包套接字通信模型2.2 流套接字通信模型2.3 Socket编程注意事项 3. UDP数据报套接字编程3.1 DatagramSocket3.2 Da…...

5.rk3588用cv读取图片(C++)

rk3588自带了cv&#xff0c;不需要重新安装&#xff0c;执行以下操作即可&#xff1a; 一、读取图片 1.读取某张图片 #define HAVE_OPENCV_VIDEO #define HAVE_OPENCV_VIDEOIO#include <opencv2/opencv.hpp> #include <iostream> #include <opencv2/opencv.h…...

Github 无法正常访问?一招解决

查询IP网址: https://ip.chinaz.com/ 主页如下&#xff1a; 分别查询以下三个网址的IP&#xff1a; github.com github.global.ssl.fastly.net assets-cdn.github.com 修改 hosts 文件&#xff1a; 将 /etc/hosts 复制到 home 下 sudo cp /etc/hosts ./ gedit hosts 在底下…...

架构师的36项修炼-08系统的安全架构设计

本课时讲解系统的安全架构。 本节课主要讲 Web 的攻击与防护、信息的加解密与反垃圾。其中 Web 攻击方式包括 XSS 跨站点脚本攻击、SQL 注入攻击和 CSRF 跨站点请求伪造攻击&#xff1b;防护手段主要有消毒过滤、SQL 参数绑定、验证码和防火墙&#xff1b;加密手段&#xff0c…...

docker 构建应用

docker 应用程序开发手册 开发 docker 镜像 Dockerfile 非常容易定义镜像内容由一系列指令和参数构成的脚本文件每一条指令构建一层一个 Dockerfile 文件包含了构建镜像的一套完整指令指令不区分大小写&#xff0c;但是一般建议都是大写从头到尾按顺序执行指令必须以 FROM 指…...

Go语言grpc服务开发——Protocol Buffer

文章目录 一、Protocol Buffer简介二、Protocol Buffer编译器安装三、proto3语言指南四、序列化与反序列化五、引入grpc-gateway1、插件安装2、定义proto文件3、生成go文件4、实现Service服务5、gRPC服务启动方法6、gateway服务启动方法7、main函数启动8、验证 相关参考链接&am…...

【开源】基于JAVA语言的实验室耗材管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 耗材档案模块2.2 耗材入库模块2.3 耗材出库模块2.4 耗材申请模块2.5 耗材审核模块 三、系统展示四、核心代码4.1 查询耗材品类4.2 查询资产出库清单4.3 资产出库4.4 查询入库单4.5 资产入库 五、免责说明 一、摘要 1.1…...

金智易表通构建学生缴费数据查询+帆软构建缴费大数据报表并整合到微服务

使用金智易表通挂接外部数据,快速建设查询类服务,本次构建学生欠费数据查询,共有3块设计,规划如下: 1、欠费明细查询:学校领导和财务处等部门可查询全校欠费学生明细数据;各二级学院教职工可查询本二级学院欠费学生明细数据。 2、大数据统计报表:从应收总额、欠费总额…...

MySQL复合索引

复合索引是指在数据库表上同时包含两个或更多列的索引。它们对于优化涉及这些列的查询非常有效&#xff0c;特别是当这些列常常在查询条件&#xff08;如WHERE子句&#xff09;、排序&#xff08;ORDER BY子句&#xff09;和连接&#xff08;JOIN条件&#xff09;中使用时。 复…...

Web3 游戏开发者的数据分析指南

作者&#xff1a;lesleyfootprint.network 在竞争激烈的 Web3 游戏行业中&#xff0c;成功不仅仅取决于游戏的发布&#xff0c;还需要在游戏运营过程中有高度的敏锐性&#xff0c;以应对下一次牛市的来临。 人们对 2024 年的游戏行业充满信心。A16Z GAMES 和 GAMES FUND ONE …...

temu跨境电商怎么样?做temu蓝海项目有哪些优势?

在全球电商市场激烈的竞争中&#xff0c;Temu跨境电商平台以其独特的优势和策略&#xff0c;逐渐崭露头角。对于许多想要拓展海外市场的商家来说&#xff0c;Temu的蓝海项目提供了一个充满机遇的新平台。本文将深入探讨Temu跨境电商的优势以及在蓝海市场中的发展前景。 全球化市…...

C#使用RabbitMQ-1_Docker部署并在c#中实现简单模式消息代理

介绍 RabbitMQ是一个开源的消息队列系统&#xff0c;实现了高级消息队列协议&#xff08;AMQP&#xff09;。 &#x1f340;RabbitMQ起源于金融系统&#xff0c;现在广泛应用于各种分布式系统中。它的主要功能是在应用程序之间提供异步消息传递&#xff0c;实现系统间的解耦和…...

EasyExcel中自定义拦截器的运用

在EasyExcel中自定义拦截器不仅可以帮助我们不止步于数据的填充&#xff0c;而且可以对样式、单元格合并等带来便捷的功能。下面直接开始 我们定义一个MergeWriteHandler的类继承AbstractMergeStrategy实现CellWriteHandler public class MergeLastWriteHandler extends Abst…...

shell编程-7

shell学习第7天 sed的学习1.sed是什么2.sed有两个空间pattern hold3.sed的语法4. sed里单引号和双引号的区别:5.sed的查找方式6.sed的命令sed的标签用法sed的a命令:追加sed的i命令:根据行号插入sed的c命令:整行替换sed的r命令sed的s命令:替换sed的d命令:删除sed中的&符号 7…...

工业智能网关储能物联网应用实现能源的高效利用及远程管理

储能电力物联网是指利用物联网技术和储能技术相结合&#xff0c;实现对电力系统中各种储能设备的智能管理和优化控制。随着可再生能源的不断发展和应用&#xff0c;电力系统面临着越来越大的电力调度和储能需求而储能电力物联网的出现可以有效解决这一问题&#xff0c;提高电力…...

虹科数字化与AR部门升级为安宝特AR子公司

致关心虹科AR的朋友们&#xff1a; 感谢您一直以来对虹科数字化与AR的支持和信任&#xff0c;为了更好地满足市场需求和公司发展的需要&#xff0c;虹科数字化与AR部门现已升级为虹科旗下独立子公司&#xff0c;并正式更名为“安宝特AR”。 ”虹科数字化与AR“自成立以来&…...

服务器是什么?(四种服务器类型)

服务器 服务器定义广义: 专门给其他机器提供服务的计算机。狭义:一台高性能的计算机&#xff0c;通过网络提供外部计算机一些业务服务 个人PC内存大概8G&#xff0c;服务器内存128G起步 服务器是什么 服务器指的是 网络中能对其他机器提供某些服务的计算机系统 &#xff0c;相对…...

09-微服务Sentinel整合GateWay

一、概述 在微服务系统中&#xff0c;网关提供了微服务系统的统一入口&#xff0c;所以我们在做限流的时候&#xff0c;肯定是要在网关层面做一个流量的控制&#xff0c;Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。 1.1 总览 Sentinel 1.6.…...

python基础学习-03 安装

python3 可应用于多平台包括 Windows、Linux 和 Mac OS X。 Unix (Solaris, Linux, FreeBSD, AIX, HP/UX, SunOS, IRIX, 等等。)Win 9x/NT/2000Macintosh (Intel, PPC, 68K)OS/2DOS (多个DOS版本)PalmOSNokia 移动手机Windows CEAcorn/RISC OSBeOSAmigaVMS/OpenVMSQNXVxWorksP…...

HTML — 区块元素

HTML 通过各种标签将元素组合起来。 一. 区块元素 大多数 HTML 元素被定义为块级元素或内联元素。块级元素在浏览器显示时&#xff0c;通常会以新的行开始。例如&#xff1a;<div>、<h1>、<p>、<ul>等。 它们在使用时会独自占据一行&#xff0c;称为块…...

《PCI Express体系结构导读》随记 —— 第I篇 第3章 PCI总线的数据交换(4)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第I篇 第3章 PCI总线的数据交换&#xff08;3&#xff09; 3.2 PCI设备的数据传递 PCI设备的数据传递使用地址译码方式&#xff0c;当一个存储器读写总线事务到达PCI总线时&#xff0c;在这条总线上的所有PCI设…...

力扣0083——删除排序链表中的重复元素

删除排序链表中的重复元素 难度&#xff1a;简单 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例1 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例2 输入&#xff1a…...

MySQL数据库的一些缩写含义

DDL Data Definition Language&#xff0c;数据定义语言&#xff0c;用来定义数据库对象(数据库&#xff0c;表&#xff0c;字段) DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进 行增、删、改操作。 添加数据&#x…...

解决 ssh: connect to host github.com port 22: Connection timed out

问题 今天使用git克隆github上的代码时&#xff0c;一直报错 原以为是公钥过期了&#xff0c;就尝试修改配置公钥&#xff0c;但是尝试了几次都不行&#xff0c;最终在博客上找到了解决方案&#xff0c;在次记录一下&#xff0c;以备不时之需 解决ssh-connect-to-host-github…...

【iOS ARKit】同时开启前后摄像头BlendShapes

在上一节中已经了解了 iOS ARkit 进行BlendShapes的基本操作&#xff0c;这一小节继续实践同时开启前后摄像头进行人脸捕捉和世界追踪。 iOS设备配备了前后两个摄像头&#xff0c;在运行AR 应用时&#xff0c;需要选择使用哪个摄像头作为图像输人。最常见的AR 体验使用设备后置…...

Vue3动态插入组件

一、使用<component>is实现动态组件插入 <component>&#xff1a;一个用于渲染动态组件或元素的“元组件”。 :is : 要渲染的实际组件&#xff0c;当 is 是字符串&#xff0c;它既可以是 HTML 标签名也可以是组件的注册名。 <script> import Foo from ./F…...

介绍一下OpenCV中常用的图像处理函数

OpenCV中常用的图像处理函数有很多&#xff0c;以下是其中一些函数的介绍&#xff1a; - cvLoadImage()&#xff1a;读入图像函数。 - imshow()&#xff1a;显示图像函数。 - imwrite()&#xff1a;保存图像函数。 - Mat srcImage imread()&#xff1a;读入图像函数。 - …...

vscode vim 快捷键汇总

需满足操作&#xff1a; 上下移动按照 word 移动选中增删改查找字符/变量移动、增加、复制、删除 行选中多个相同的变量/字符屏幕移动增加多个光标快速注释 上下左右移动 CommandDescription&#x1f522; hleft (also: CTRL-H, BS, or Left key)&#x1f522; lright (also…...

npm官方注册表和淘宝镜像切换

1.切换到淘宝镜像 加快npm包的下载速度&#xff0c; //已失效 //npm config set registry https://registry.npm.taobao.org/ npm config set registry https://registry.npmmirror.com这会将npm的注册表设置为淘宝镜像 查看&#xff1a; npm config get registry如果返回的…...

LFU算法

LFU算法 Least Frequently Used&#xff08;最不频繁使用&#xff09; Leetcode有原题&#xff0c;之前手写过LRU&#xff0c;数据结构还是习惯于用java实现&#xff0c;实现是copy的评论题解。 题解注释写的很清楚 大致就是说LFUCache类维护一个存放node的map&#xff0c;同…...