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

网络编程之 Socket 套接字(使用数据报套接字和流套接字分别实现一个小程序(附源码))

文章目录

  • 1. 什么是网络编程
  • 2. 网络编程中的基本概念
    • 1)发送端和接收端
    • 2)请求和响应
    • 3)客户端和服务端
    • 4)常见的客户端服务端模型
  • 3. Socket 套接字
    • 1)Socket 的分类
    • 2)Java 数据报套接字通信模型
    • 3)Java 流套接字通信模型
  • 4. UDP 数据报套接字编程
    • 1)DatagramSocket API
    • 2)DatagramPacket API
    • 3)示例
  • 5. TCP 流套接字编程
    • 1)ServerSocket API
    • 2)Socket API
    • 3)示例
      • a. 短连接版本
      • b. 长连接并发版本

1. 什么是网络编程

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

请添加图片描述

只要满足不同的进程就可以进行通信,所以即便是在同一个主机,只要不同的进程,基于网络传输数据,也属于网络编程

2. 网络编程中的基本概念

1)发送端和接收端

在一次网络传输中:

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

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

收发端: 发送端和接收端两端,简称为收发端

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

请添加图片描述

2)请求和响应

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

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

就好比在饭店里点了一碗面

顾客先发起请求:来一碗面

饭店再做出响应:提供一碗面

请添加图片描述

3)客户端和服务端

服务端: 在常见的网络传输场景下,把 提供服务 的一方进程,称为服务端,可以对外提供服务

客户端: 获取服务 的一方进程,称为客户端

对于服务来说,一般是提供:

  • 客户端获取服务资源

请添加图片描述

  • 客户端保存资源到服务端

请添加图片描述

4)常见的客户端服务端模型

在常见的场景中,客户端是指给用户使用的程序,服务端是指提供用户服务的程序,具体流程如下:

  1. 客户端发送请求到服务端
  2. 服务端根据请求数据,执行相应的业务处理
  3. 服务端返回响应:发送业务处理结果
  4. 客户端根据响应数据,展示处理结果

请添加图片描述

3. Socket 套接字

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

1)Socket 的分类

常用的 Socket 套接字有以下两类:

  • 流套接字: 使用 TCP 协议

    传输数据基于 IO 流,流式数据的特征就是在 IO 流没有关闭的情况下,是无边界的数据,可以多次发送数据,也可以分开多次接收

  • 数据报套接字: 使用 UDP 协议

    传输数据是一块一块的,每一块数据必须一次性发送,接受也必须一次性接受,不能分开发送或接收

2)Java 数据报套接字通信模型

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

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

具体流程如下:

请添加图片描述

3)Java 流套接字通信模型

TCP 协议具有有连接、面向字节流的特征,即传输数据之前要先建立连接,并且数据的传输是基于 IO 流的

具体流程如下:

请添加图片描述

4. UDP 数据报套接字编程

1)DatagramSocket API

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

构造方法:

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

实例方法:

方法签名方法说明
void receive(DatagramPacket p)接收数据报到提前构造的 DatagramPacket 对象中(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)发送提前构造的 DatagramPacket 数据报
void close()关闭套接字

2)DatagramPacket API

DatagramPacket 是 UDP Socket 发送和接收的数据报

构造方法:

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造一个 DatagramPacket 对象用来接收数据报,接收的数据保存到字节数组中
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)构造 DatagramPacket 用来发送数据报,发送的数据为字节数组中的数据。指定目的主机的 IP 和端口号

实例方法:

方法签名方法说明
InetAddress getAddress()从数据报中,获取 IP 地址
int getPort()从数据报中,获取端口号
byte[] getData()获取数据报中的数据

3)示例

使用 UDP Socket 套接字完成一个简单的翻译小程序

客户端向服务端发起翻译请求,服务端接收到请求后,对请求进行处理,再向客户端做出响应

服务端

服务端接收到请求之后,在我们人为规定的 map 中进行查询,再对客户端做出响应

public class Server {private final static HashMap<String, String> map = new HashMap<>();static {map.put("苹果", "apple");map.put("香蕉", "banana");map.put("梨", "pear");map.put("电脑", "computer");map.put("手机", "phone");}public static void main(String[] args) throws IOException {// 得到 socket 对象,并对其绑定端口号Log.println("服务器开启并且绑定了 8080 端口");DatagramSocket socket = new DatagramSocket(8080);// 循环接受和处理请求while (true) {// 准备接收数据的容器byte[] buf = new byte[1024];// 包装数据包DatagramPacket received = new DatagramPacket(buf, 0, 1024);// 接收请求Log.println("服务器准备接受请求");socket.receive(received);Log.println("服务器接受到了请求");// 处理请求InetAddress address = received.getAddress();    // 得到发起请求方的 IPLog.println("对方的地址:" + address);int port = received.getPort();      // 得到发起请求方的端口号Log.println("对方的端口:" + port);int length = received.getLength();      // 得到请求中真实有效的数据长度Log.println("真实的数据长度:" + length);byte[] realData = Arrays.copyOf(buf, length);   // 得到请求中真实有效的数据// 将请求数据转换成 StringString request = new String(realData, 0, length, StandardCharsets.UTF_8);Log.println("请求中的数据:\r\n" + request);// 人为规定请求和相应的格式// 请求格式必须以 “我是请求:\r\n” 开始,以 “\r\n” 结束if (!request.startsWith("我是请求:\r\n")) {Log.println("请求格式出错");// 请求出错continue;}if (!request.endsWith("\r\n")) {Log.println("请求格式出错");// 请求出错continue;}// 得到请求中的英文单词String EnglishWord = request.substring("我是请求:\r\n".length(), request.length() - 2);Log.println("请求中的英文单词:" + EnglishWord);// 进行翻译String ChineseWord = map.getOrDefault(EnglishWord, "我不知道");Log.println("翻译后的中文:" + ChineseWord);// 将翻译后的结果进行包装String response = String.format(ChineseWord, "%s\r\n");byte[] bytes = response.getBytes(StandardCharsets.UTF_8);// 包装数据包DatagramPacket send = new DatagramPacket(bytes, 0, bytes.length, address, port);// 发起响应Log.println("准备发送响应");socket.send(send);Log.println("相应发送成功");}}
}

客户端

public class Client {public static void main(String[] args) throws IOException {Scanner sc = new Scanner(System.in);DatagramSocket socket = new DatagramSocket(9999);while (sc.hasNextLine()) {String str = sc.nextLine();String send = "我是请求:\r\n" + str + "\r\n";byte[] bytes = send.getBytes();DatagramPacket request = new DatagramPacket(bytes, 0, bytes.length, InetAddress.getLoopbackAddress(), 8080);socket.send(request);// 接收响应byte[] buf = new byte[1024];DatagramPacket datagramPacket = new DatagramPacket(buf, 0, 1024);socket.receive(datagramPacket);int n = datagramPacket.getLength();String response = new String(buf, 0, n, StandardCharsets.UTF_8);Log.println(response);}}
}

请添加图片描述

5. TCP 流套接字编程

1)ServerSocket API

用于创建 TCP 服务端 Socket 的 API

构造方法:

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

实例方法:

方法签名方法说明
Socket accept()等待客户端发起连接,连接成功后返回一个 Socket 对象
void close()关闭 Socket

2)Socket API

这里的 Socket 是客户端 Socket,或服务端中接收到客户端连接请求后,accept 方法返回的服务端 Socket

不管是客户端还是服务端 Socket,都是双方建立连接后,保存对端信息,以及用来与对方收发数据的

构造方法:

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

实例方法:

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

3)示例

使用 TCP Socket 套接字完成一个简单的翻译小程序

完成的效果和上文 UDP 的小程序效果一样

不过在 TCP 这里有长短连接的区分,所以有两个版本的代码,在长连接版本中加入了并发编程,使得同一个服务端可以被多个客户端所连接

a. 短连接版本

客户端:

public class 短连接版本Client {public static void main(String[] args) throws IOException {for (int i = 0; i < 3; i++) {Socket socket = new Socket("127.0.0.1", 8080);      // 拨号OutputStream os = socket.getOutputStream();OutputStreamWriter writer = new OutputStreamWriter(os, "UTF-8");PrintWriter printWriter = new PrintWriter(writer);printWriter.printf("我是请求\r\n%s\r\n", "苹果");printWriter.flush();InputStream is = socket.getInputStream();Scanner scanner = new Scanner(is, "UTF-8");String header = scanner.nextLine();String word = scanner.nextLine();System.out.println(word);socket.close();     // 挂电话}}
}

服务端:

public class 短连接版本Server {private final static HashMap<String, String> map = new HashMap<>();static {map.put("苹果", "apple");map.put("香蕉", "banana");map.put("梨", "pear");map.put("电脑", "computer");map.put("手机", "phone");}public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);while(true) {Log.println("等待客户端建立连接");Socket socket = serverSocket.accept();Log.println("客户端连接成功");InetAddress address = socket.getInetAddress();Log.println("客户端 IP 地址:" + address);int port = socket.getPort();Log.println("客户端端口号:" + port);InputStream is = socket.getInputStream();Scanner sc = new Scanner(is, "UTF-8");String header = sc.nextLine();String EnglishWord = sc.nextLine();Log.println("请求中的英文单词为:" + EnglishWord);String ChineseWord = map.getOrDefault(EnglishWord, "我不知道");Log.println("翻译后的中文为:" + ChineseWord);Log.println("准备响应");OutputStream os = socket.getOutputStream();OutputStreamWriter writer = new OutputStreamWriter(os);PrintWriter printWriter = new PrintWriter(writer);printWriter.printf("OK!\r\n%s\t\n", ChineseWord);printWriter.flush();Log.println("响应成功");socket.close();Log.println("断开连接");}}
}

请添加图片描述

b. 长连接并发版本

在长连接版本中,必须服务端和客户端同时支持长连接才可以进行通信

如果不清楚长连接和短连接,可以去看看我上篇文章,里面有介绍长连接和短连接,HTTP 和 HTTPS,有介绍 HTTP 的长短连接,实质上就是 TCP 长短连接

客户端:

public class Client {public static void main(String[] args) throws IOException {Scanner sc = new Scanner(System.in);Socket socket = new Socket("127.0.0.1", 8080);OutputStream os = socket.getOutputStream();OutputStreamWriter writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);PrintWriter printWriter = new PrintWriter(writer);InputStream is = socket.getInputStream();Scanner scanner = new Scanner(is, "UTF-8");while (sc.hasNextLine()) {String str = sc.nextLine();printWriter.printf("我是请求:\r\n%s\r\n", str);printWriter.flush();// 接收响应String header = scanner.nextLine();String response = scanner.nextLine();Log.println(header + "\r\n" + response);}socket.close();}
}

服务端:

public class Server {private final static HashMap<String, String> map = new HashMap<>();static {map.put("苹果", "apple");map.put("香蕉", "banana");map.put("梨", "pear");map.put("电脑", "computer");map.put("手机", "phone");}private final static class ServerTask implements Runnable {private final Socket socket;private ServerTask(Socket socket) {this.socket = socket;}@Overridepublic void run() {InetAddress address = socket.getInetAddress();Log.println("客户端 IP 地址为:" + address);int port = socket.getPort();Log.println("客户端端口号为:" + port);try {InputStream is = socket.getInputStream();// 请求格式必须以 “我是请求:\r\n” 开始,以 “\r\n” 结束Scanner sc = new Scanner(is, "UTF-8");// 进行响应OutputStream os = socket.getOutputStream();OutputStreamWriter writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);PrintWriter printWriter = new PrintWriter(writer);while (sc.hasNextLine()) {String header = sc.nextLine();String EnglishWord = sc.nextLine();Log.println("请求中的词为:" + EnglishWord);// 对请求进行处理String ChineseWord = map.getOrDefault(EnglishWord, "我不知道");Log.println("翻译后的词:" + ChineseWord);Log.println("准备发起响应");printWriter.printf("OK!\r\n%s\r\n", ChineseWord);printWriter.flush();Log.println("响应成功");}socket.close();Log.println("连接已关闭");} catch (IOException e) {e.printStackTrace();}}}public static void main(String[] args) throws IOException {// 使用多线程完成多用户同时在线的功能ExecutorService threadPool = Executors.newFixedThreadPool(3);ServerSocket serverSocket = new ServerSocket(8080);Log.println("绑定端口到 8080");while (true) {Log.println("等待客户端连接");Socket socket = serverSocket.accept();Log.println("客户端连接成功");ServerTask serverTask = new ServerTask(socket);threadPool.execute(serverTask);}}
}

请添加图片描述

相关文章:

网络编程之 Socket 套接字(使用数据报套接字和流套接字分别实现一个小程序(附源码))

文章目录 1. 什么是网络编程2. 网络编程中的基本概念1&#xff09;发送端和接收端2&#xff09;请求和响应3&#xff09;客户端和服务端4&#xff09;常见的客户端服务端模型 3. Socket 套接字1&#xff09;Socket 的分类2&#xff09;Java 数据报套接字通信模型3&#xff09;J…...

What Are Docker Image Layers?

Docker images consist of multiple layers that collectively provide the content you see in your containers. But what actually is a layer, and how does it differ from a complete image? In this article you’ll learn how to distinguish these two concepts and…...

范数详解-torch.linalg.norm计算实例

文章目录 二范数F范数核范数无穷范数L1范数L2范数 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 范数是一种数学概念&#xff0c;可以将向量或矩阵映射到非负实数上&#xff0c;通常被…...

postgresdb备份脚本

以下是一个简单的postgresdb备份脚本示例&#xff1a; 复制 #!/bin/bash # 设置备份目录和文件名 BACKUP_DIR/path/to/backup BACKUP_FILEdb_backup_$(date %F_%H-%M-%S).sql # 设置数据库连接参数 DB_HOSTlocalhost DB_PORT5432 DB_NAMEmydatabase DB_USERmyusername DB_PA…...

MATLAB程序员投简历的技巧解析,如何写出有亮点的简历

如果你想在简历中展示你的项目经验&#xff0c;一定要有亮点。一个导出的 Excel 文件过大导致浏览器卡顿的例子就是一个很好的亮点。你可以在简历中写明这个例子。如果面试官问起&#xff0c;可以用浏览器的原理来解释。浏览器内核可以简单地分为以下 5 个线程&#xff1a;GUI …...

颜色空间转换RGB-YCbCr

颜色空间 颜色空间&#xff08;Color Space&#xff09;是描述颜色的一种方式&#xff0c;它是一个由数学模型表示的三维空间&#xff0c;通常用于将数字表示的颜色转换成可见的颜色。颜色空间的不同取决于所选的坐标轴和原点&#xff0c;以及用于表示颜色的色彩模型。在计算机…...

年薪40万程序员辞职炒股,把一年工资亏光了,得了抑郁症,太惨了

年薪40万的程序员辞职全职炒股 把一年的工资亏光了 得了抑郁症 刚才在网上看了一篇文章 是一位北京的一位在互联网 大厂上班的程序员 在去年就是股市行情比较好的时候 他买了30多万股票 结果连续三个月都赚钱 然后呢 他是就把每天就996这种工作就辞掉了 然后在家全是炒股 感觉炒…...

10分钟如何轻松掌握JMeter使用方法?

目录 引言 安装jmeter HTTP信息头管理器 JMeter断言 HTTP请求默认值来代替所有的域名与端口 JSON提取器来替换变量 结语 引言 想要了解网站或应用程序的性能极限&#xff0c;JMeter是一个不可或缺的工具。但是&#xff0c;对于初学者来说&#xff0c;该如何上手使用JMe…...

[NLP]如何训练自己的大型语言模型

简介 大型语言模型&#xff0c;如OpenAI的GPT-4或Google的PaLM&#xff0c;已经席卷了人工智能领域。然而&#xff0c;大多数公司目前没有能力训练这些模型&#xff0c;并且完全依赖于只有少数几家大型科技公司提供技术支持。 在Replit&#xff0c;我们投入了大量资源来建立从…...

LeetCode1047. 删除字符串中的所有相邻重复项

1047. 删除字符串中的所有相邻重复项 给出由小写字母组成的字符串 S&#xff0c;重复项删除操作会选择两个相邻且相同的字母&#xff0c;并删除它们。 在 S 上反复执行重复项删除操作&#xff0c;直到无法继续删除。 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一…...

3。数据结构(3)

嵌入式软件开发第三部分&#xff0c;各类常用的数据结构及扩展&#xff0c;良好的数据结构选择是保证程序稳定运行的关键&#xff0c;&#xff08;1&#xff09;部分包括数组&#xff0c;链表&#xff0c;栈&#xff0c;队列。&#xff08;2&#xff09;部分包括树&#xff0c;…...

QT停靠窗口QDockWidget类

QT停靠窗口QDockWidget类 QDockWidget类简介函数和方法讲解 QDockWidget类简介 QDockWidget 类提供了一个部件&#xff0c;它可以停靠在 QMainWindow 内或作为桌面上的顶级窗口浮动。 QDockWidget 提供了停靠窗口部件的概念&#xff0c;也称为工具面板或实用程序窗口。 停靠窗…...

【LeetCode】139. 单词拆分

139. 单词拆分&#xff08;中等&#xff09; 思路 首先将大问题分解成小问题&#xff1a; 前 i 个字符的子串&#xff0c;能否分解成单词&#xff1b;剩余子串&#xff0c;是否为单个单词&#xff1b; 动态规划的四个步骤&#xff1a; 确定 dp 数组以及下标的含义 dp[i] 表示 s…...

【三维重建】NeRF原理+代码讲解

文章目录 一、技术原理1.概览2.基于神经辐射场&#xff08;Neural Radiance Field&#xff09;的体素渲染算法3.体素渲染算法4.位置信息编码&#xff08;Positional encoding&#xff09;5.多层级体素采样 二、代码讲解1.数据读入2.创建nerf1.计算焦距focal与其他设置2.get_emb…...

IntelliJ IDEA 社区版2021.3配置SpringBoot项目详细教程及错误解决方法

目录 一、SpringBoot的定义 二、Spring Boot 优点 三、创建一个springboot的项目 四、使用IDEA创建SpringBoot失败案例 一、SpringBoot的定义 Spring 的诞⽣是为了简化 Java 程序的开发的&#xff0c;⽽ Spring Boot 的诞⽣是为了简化 Spring 程序开发的。 Spring Boot 翻…...

Qt中QDebug的使用

QDebug类为调试信息(debugging information)提供输出流。它的声明在<QDebug>中&#xff0c;实现在Core模块中。将调试或跟踪信息(debugging or tracing information)写出到device, file, string or console时都会使用QDebug。 此类的成员函数参考&#xff1a;https://doc…...

vue使用路由的query配置项时如何清除地址栏的参数

写vue项目时&#xff0c;如果想通过路由的query配置项把参数从一个组件传到另一个组件&#xff0c;但是又不希望?idxxx显示在地址栏&#xff08;如&#xff1a;http://localhost:8080/test?idxxx的?idxxx&#xff09;&#xff0c;该怎么做&#xff1a; 举一个案例&#xff1…...

Redis-列表(List)

Redis列表(List) 介绍 单键多值Redis 列表是简单的字符串列表&#xff0c;按照插入顺序排序。你可以添加一个元素到列表的头部&#xff08;左边&#xff09;或者尾部&#xff08;右边&#xff09;它的底层实际是个双向链表&#xff0c;对两端的操作性能很高&#xff0c;通过索…...

ripro主题修改教程-首页搜索框美化教程

先看效果图: 我们来看怎么实现: 1、找到wp-content/themes/ripro/assets/css/diy.css并将下面的内容整体复制进去并保存 /*首页搜索框*/ .bgcolor-fff {background-color: #fff; } .row,.navbar .menu-item-mega>.sub-menu{margin-left:-10px;margin-right:-10px;} .home…...

写作业用白光还是暖光?盘点色温4000K的护眼台灯

台灯的白光或者暖光指的是台灯的色温&#xff0c;低色温的光线看起来发黄发红&#xff0c;高色温的光线发白发蓝。 如果灯光的光源是高品质光源&#xff0c;本身没有蓝光问题&#xff0c;那么色温的选择对护眼的影响是比较少的&#xff0c;更多的是对人学习工作状态&#xff0c…...

Flowable 6.3.0 从安装到实战:手把手教你搭建第一个BPMN流程(附MySQL 8.0避坑指南)

Flowable 6.3.0实战指南&#xff1a;从零构建企业级流程引擎 当企业业务流程复杂度超过CRUD范畴时&#xff0c;一套可靠的流程引擎就成为技术架构中的关键基础设施。作为Activiti原班团队打造的新一代开源BPM引擎&#xff0c;Flowable 6.3.0在保持轻量级特性的同时&#xff0c;…...

FireRedASR Pro Java集成开发指南:SpringBoot微服务语音处理实战

FireRedASR Pro Java集成开发指南&#xff1a;SpringBoot微服务语音处理实战 如果你是一个Java后端开发者&#xff0c;最近接到了要给系统加上语音识别功能的需求&#xff0c;比如处理用户上传的客服录音&#xff0c;或者分析会议纪要&#xff0c;那你可能正在寻找一个既稳定又…...

OpenClaw配置文件详解:Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF性能调优全参数解析

OpenClaw配置文件详解&#xff1a;Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF性能调优全参数解析 1. 为什么需要手动调优OpenClaw配置 第一次看到OpenClaw的配置文件时&#xff0c;我和大多数开发者一样&#xff0c;直接选择了默认的QuickStart模式。直到某个深夜…...

pnpm 使用教程

现代 JavaScript 项目的首选包管理器 pnpm&#xff08;performant npm&#xff09;是一个快速、节省磁盘空间的包管理器&#xff0c;它通过全局存储和硬链接机制&#xff0c;解决了 npm 传统的依赖重复和“幽灵依赖”问题。本教程将带你从零开始掌握 pnpm 的核心用法&#xff0…...

基于模型的增程式混合动力汽车整车策略开发与建模

基于模型的整车策略开发思路、整车模型搭建流程&#xff0c;增程式混合动力汽车建模仿真模型&#xff0c;增程纯电&#xff0c;类似Nisson的e-power整车配置策略 具体内容包括&#xff1a;增程器模型、电机模型、电池模型&#xff0c;驾驶员模型&#xff0c;整车VCU控制模型等 …...

智能车竞赛调参避坑指南:从舵机中值校准到PD参数整定,新手也能快速上手的实战经验

智能车竞赛调参实战手册&#xff1a;从机械校准到控制算法优化的全流程解析 引言&#xff1a;为什么调参是智能车竞赛的核心竞争力&#xff1f; 全国大学生智能汽车竞赛中&#xff0c;硬件组装和基础代码编写只是起点&#xff0c;真正的挑战在于如何让车辆在赛道上稳定高速行驶…...

实战:在无商店的Win10企业版ThinkPad上,通过PowerShell手动部署Lenovo Vantage

1. 为什么需要手动部署Lenovo Vantage 很多ThinkPad用户可能都遇到过这样的困扰&#xff1a;新装的Windows 10企业版系统找不到微软应用商店&#xff0c;而Lenovo Vantage这个必备的管理工具又只能通过商店安装。作为一个长期使用ThinkPad的技术博主&#xff0c;我完全理解这种…...

Java OOM 异常:从原理、场景、排查到解决方案全攻略

原理 → 场景 → 排查 → 解决方案&#xff08;面试 线上实战必备&#xff09;这是后端开发、测试、运维必须烂熟于心的终极 OOM 指南&#xff0c;结构清晰、可直接用于复习、面试、故障处理。一、OOM 基础&#xff1a;到底什么是 OOM&#xff1f;1. 定义OOM OutOfMemoryErro…...

Vivado GUI隐藏技巧:如何手动修改OOC模式IP的时钟频率(附200MHz实战案例)

Vivado GUI隐藏技巧&#xff1a;如何手动修改OOC模式IP的时钟频率&#xff08;附200MHz实战案例&#xff09; 在FPGA开发中&#xff0c;Vivado的IP核(IP Catalog)功能极大提升了设计效率&#xff0c;但OOC(Out-of-Context)模式下IP核的时钟频率设置却常常让初学者困惑。当你在G…...

1746-NR4电阻模拟输入

1746-NR4 模拟输入模块&#xff08;电阻输入&#xff09;特点由 Allen-Bradley 生产&#xff0c;属于 SLC 500 系列类型为 模拟输入模块&#xff0c;专门用于电阻信号采集提供 4 路独立输入通道支持热电偶、RTD&#xff08;热电阻&#xff09;及其他电阻传感器输入精度高&#…...