JAVA网络编程——socket套接字的介绍下(详细)
目录
前言
1.TCP 套接字编程 与 UDP 数据报套接字的区别
2.TCP流套接字编程
API 介绍
TCP回显式服务器
Scanner 的多种使用方式
PrintWriter 的多种使用方式
TCP客户端
3. TCP 服务器中引入多线程
结尾
前言
各位读者大家好,今天笔者继续更新socket套接字的下半部分,这部分承接上半篇的内容接着往下写
JAVA网络编程——socket套接字的介绍上(详细)-CSDN博客
上半篇博客笔者主要汇总了一些网络编程的基础知识,并介绍了UDP数据报套接字编程和代码案例
实现了一个简单的回显服务器和客户端
博客的主要内容如下:
1.TCP流套接字编程 与 UDP 数据报套接字的区别,并结合具体代码,说明两者在实现方式上的差异。
2.TCP流套接字 编程常用 API 和代码示例,并尝试引入多线程思路对服务端代码进行优化。
3.最后,笔者还将分享一些学习过程中遇到的问题和经验,希望能对读者有所启发。
本篇博客的内容会和上半篇博客有联系,但您依旧可以把他看作是独立的知识博客,无需太多阅读门槛,言尽于此,就让我们开始吧!
1.TCP 套接字编程 与 UDP 数据报套接字的区别
在实际编程之前,我们首先要了解:为什么 TCP 和 UDP 的套接字写法会有所不同?
从传输层协议的角度来看, TCP和UDP是不同的协议
TCP 是一种面向连接的传输层协议,在通信前需要通过“三次握手”建立连接,通信过程中也会通过校验、序号、确认应答等机制保证数据的可靠传输。可以理解为,TCP 的通信就像是打电话,必须先拨号接通,双方确认后才能说话。
而 UDP 是一种无连接的协议,发送数据前并不建立连接,也不会确认数据是否成功送达。UDP 更像是发快递,你把包裹投递出去就完事了,送达与否不做额外处理。这种机制导致 UDP 的通信过程更加简单高效,但也更容易出现数据丢失、乱序的问题。
也正因为如此,在编程中,两者的使用方式也大相径庭。
对于UDP套接字编程,正如前文提到的服务端通过 DatagramSocket
创建一个端口并监听,客户端发送数据时需要用 DatagramPacket
显式地指定目标 IP 和端口号。
通俗来说 UDP就像发短信
- 直接发送,不管对方是否收到
- 发完就完了,不知道对方看没看到
- 快速简单,但不保证送达
相比之下,TCP 流套接字编程更加结构化。服务端使用 ServerSocket
来监听端口,当有客户端发起连接时,会通过 accept()
方法返回一个与客户端进行一对一通信的 Socket
对象。在这之后,服务端和客户端之间就建立起了一个稳定的通信通道,后续的通信就像操作输入输出流一样,不需要再关注 IP 和端口这些底层细节。
换句话说:TCP读取数据的基本单位是字节,TCP 协议本身是面向字节流(byte stream)的协议
同样通俗的说 , TCP就像打电话
- 拨号建立连接,确认对方接听后才开始说话
- 说话过程中可以确认对方是否听到
- 如果线路有问题会重新说一遍
- 说完话要挂断电话结束通话
也就是说,UDP 更加“灵活”和“轻便”,每次通信都要说明来龙去脉(目标地址);而 TCP 则是“关系型”的,一旦连接建立,双方就可以安心地进行数据交换,程序的逻辑也更加清晰。
接下来笔者开始介绍API和代码示例,并介绍TCP套接字的代码是如何体现它和UDP的区别的.
2.TCP流套接字编程
和UDP数据报套接字编程类似,TCP流套接字编程 同样有两个重要的API
API 介绍
ServerSocket 构造方法
ServerSocket serverSocket = new ServerSocket(int port);
其中 int port 表示 监听的端口号 ,一旦绑定成功,port端口就会被占用,等待客户端连接
常用方法:
1.Socket accept()
开始监听指定端⼝(创建时绑定的端⼝),有客⼾端连接后,返回⼀个服务端Socket对象,并基于该Socket建⽴与客⼾端的连接,否则阻塞等待具体一点说:
accept()
方法执行以后:服务器端和客户端之间就建立起了一条可靠的 TCP 连接,双方都会在系统内核中保存关于对方的关键信息,如:
客户端的 IP 地址
客户端的端口号
服务器的 IP 地址
服务器的端口号
这 4 个信息,加上传输协议(TCP),就构成了所谓的 “五元组”,唯一标识一条 TCP 连接。这也体现了 TCP协议和UDP协议之间的区别
2.Socket close()
关闭此套接字
2. Socket
Socket 是客户端/服务端之间的通信通道
客户端和服务端之间每一次连接,都会被封装成一个 Socket
对象,负责双方的输入输出数据流。
Socket 构造方法
构造方法(客户端使用):
Socket socket = new Socket(String host, int port);
其中 host 表示 IP 地址,port表示端口
常用方法:
1.InputStream getInputStream()
获取输入流,用于读取从对端发送过来的字节数据。
2.OutputStream getOutputStream()
获取输出流,用于向对端发送字节数据。
3.close()
关闭当前连接。
TCP回显式服务器
根据上面对 ServerSocket
的介绍,我们可以知道:
在编写一个 TCP 回显式服务器时,首先需要创建一个 ServerSocket
实例并指定监听的端口号。这个操作会在当前机器上开启一个服务器进程,等待客户端的连接请求。
一旦有客户端连接到这个端口,服务器就会通过 accept()
方法接收这个连接请求,并返回一个新的 Socket
对象。这个 Socket
对象就代表了服务器与某个客户端之间的一条通信通道。
public class TcpEchoServer {ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);// 绑定端口号
// 和 UDP 不同,TCP 在通信前必须先建立连接(就是三次握手)。
// 所以服务器要做的第一件事:不是接收数据,而是 等待客户端来连我。}
}
然后我们启动服务器:
public void start() throws IOException {System.out.println("服务器启动了");Socket socket = serverSocket.accept(); // 建立连接processwork(socket);}
其中 processwork () 方法内来实现服务器的功能
而我们的服务器主要实现的功能为:
1.读取请求
2.响应
3.返回请求
请看代码:
private void processwork(Socket socket) throws IOException {// 1.读取请求// 2.响应// 3.返回响应try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){// 包装一下Scanner scanner = new Scanner(inputStream);//填入什么参数,就代表了什么输入方式PrintWriter printWriter = new PrintWriter(outputStream);while(true) {String request = scanner.nextLine();// 读取请求String response = process(request); // 回显printWriter.println(response); // 返回响应printWriter.flush(); // 刷新缓冲区,确保已经返回// 4.打印日志System.out.printf("[%s:%d] request: %s, response: %s\n",socket.getInetAddress().toString(),socket.getPort(),request,response);}}finally {socket.close();}}
InputStream 表示从客户端读入数据的字节流,OutputStream 表示写数据给客户端的字节流
使用了 try-with-resources 语法,能确保在代码执行完毕后,自动关闭资源(这里是输入输出流)。这种写法简洁、安全,避免了流忘记关闭导致的资源泄露问题。
使用 Scanner
包装输入流,能够将字节数据按照「行文本」的形式解析,方便我们通过 scanner.nextLine()
读取一整行字符串。相比直接用 inputStream.read()
读取字节数组,这种方式更直观、适合处理文本请求。
我们都知道,我们常用 Scanner scanner = new Scanner(System.in); 这代表控制台输入,这是我们初学时学会的,但实际上 Scanner 会根据你传入参数的不同表示不同的输入方法
Scanner 的多种使用方式
1. 控制台输入:
Scanner scanner = new Scanner(System.in);
从键盘读取用户输入,适合交互式程序。
2. 从文件中读取:
Scanner scanner = new Scanner(new File("input.txt"));
读取文件内容,适用于处理数据文件或配置文件等场景。
3. 从字符串中读取:
Scanner scanner = new Scanner("Hello World\n123");
可以将字符串当作输入源,非常适合字符串解析。
4. 从网络输入流中读取(Socket 网络通信中):
InputStream inputStream = socket.getInputStream();Scanner scanner = new Scanner(inputStream);
这是网络编程中常见的用法,此时
Scanner
会从网络连接中读取对方(比如客户端)发送来的数据。比如 TCP 编程中,服务器端使用socket.getInputStream()
获取输入流,从客户端接收数据。
同理
PrintWriter
是对输出流的包装,能够方便地以「文本行」的形式输出数据,比如我们可以用 printWriter.println(response)
将一行响应发出去。注意它默认有缓冲机制,发送数据前必须手动调用 flush()
刷新缓冲区,确保数据立即写出。
同理,我在这里汇总一下
PrintWriter 的多种使用方式
1. 输出到控制台
PrintWriter writer = new PrintWriter(System.out); writer.println("Hello, Console!"); writer.flush();
2. 输出到文件
PrintWriter writer = new PrintWriter(new File("output.txt")); writer.println("Write this to file."); writer.flush(); writer.close();
输出目标:磁盘文件
适用场景:日志记录、写入结果、持久化数据
3. 输出到网络(如 TCP 编程)
OutputStream outputStream = socket.getOutputStream(); PrintWriter writer = new PrintWriter(outputStream); writer.println("Hello, client!"); writer.flush();
输出目标:通过 TCP 连接的对方客户端(或服务器)
适用场景:TCP 套接字通信中,服务器/客户端发送响应或数据
4. 输出到内存字符串缓冲区
StringWriter stringWriter = new StringWriter();PrintWriter writer = new PrintWriter(stringWriter);writer.println("Write to memory."); writer.flush(); String result = stringWriter.toString(); // 获取最终字符串
输出目标:内存中的字符串
适用场景:构建复杂字符串、模板处理、动态拼接内容
最后,无论通信过程中是否抛出异常,最终都要关闭 socket
。这是网络编程中很重要的一步,必须手动释放网络资源,避免连接堆积导致服务器崩溃。
那么为什么之前的UDP不用?
本质原因:UDP 是无连接的
TCP 是一种面向连接的协议,通信前需要建立连接,通信后要关闭连接,连接的生命周期是明确的,因此必须显式关闭以释放资源。
而 UDP 是无连接的协议,DatagramSocket
并不会维持一个长时间的连接状态。它只是一个发送/接收数据报的工具,就像一个“邮筒”或“信箱”,你发完信或者收完信就可以不管它了,系统会随着进程结束自动回收资源。
因此完整的服务器代码如下:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TcpEchoServer {ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);// 绑定端口号
// 和 UDP 不同,TCP 在通信前必须先建立连接(就是三次握手)。
// 所以服务器要做的第一件事:不是接收数据,而是 等待客户端来连我。}public void start() throws IOException {System.out.println("服务器启动了");Socket socket = serverSocket.accept(); // 建立连接processwork(socket);}private void processwork(Socket socket) throws IOException {// 1.读取请求// 2.响应// 3.返回响应try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){// 包装一下Scanner scanner = new Scanner(inputStream);//填入什么参数,就代表了什么输入方式PrintWriter printWriter = new PrintWriter(outputStream);while(true) {String request = scanner.nextLine();// 读取请求String response = process(request); // 回显printWriter.println(response); // 返回响应printWriter.flush(); // 刷新缓冲区,确保已经返回// 4.打印日志System.out.printf("[%s:%d] request: %s, response: %s\n",socket.getInetAddress().toString(),socket.getPort(),request,response);}}finally {socket.close();}}private String process(String request){return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}
TCP客户端
接下来是客户端,他大概有两个功能
1.构造请求,并发送给服务器
2.读取服务器发送回来的请求
我们首先创建一个 Socket 对象,并且绑定好IP地址和端口号
public class TcpEchoClient{private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {// 连接服务器socket = new Socket(serverIp, serverPort);}
}
然后实现功能:
代码和服务器原理一致,笔者就不过多细说了
public void start() throws IOException{System.out.println("客户端启动,已连接服务器");Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){Scanner scannerNet = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);while(true){// 1.读取内容System.out.println("输入内容");String request = scanner.nextLine();// 2.发送给服务器printWriter.println(request);// 加上ln, 暗中约定一个请求以\n作为结尾// 刷新缓冲区,保证数据能正确发出去printWriter.flush();// 3.读取服务器返回的响应String response = scannerNet.nextLine();//4.打印返回的数据System.out.println(response);}}catch (IOException e){throw new RuntimeException(e);}}
最后效果如下:
3. TCP 服务器中引入多线程
接下来我们谈一下 多线程的问题
在最初的 TCP 服务器代码中,我们使用如下方式来接收客户端连接:
Socket socket = serverSocket.accept();
processwork(socket);
这种写法是单线程、串行处理,意味着服务器一次只能处理一个客户端的请求。当一个客户端连接上来,服务器就会一直处理这个客户端的请求,直到处理完毕后,才能继续 accept()
等待下一个客户端。这带来两个致命问题:
-
其他客户端无法同时连接
如果第一个客户端一直占用服务器,那么第二个客户端连接时,服务器就无法accept()
,连接会阻塞甚至超时。 -
服务器响应效率极低
在网络通信中,尤其是长连接的场景下,一个客户端可能长时间保持连接,服务器如果不使用并发机制,就会严重浪费资源和降低效率。
TCP 的连接机制导致必须并发处理
TCP 是面向连接的协议,通信前需要完成三次握手,通信过程中保持连接状态。每个 Socket
实例都代表一次独立的连接。一旦 accept()
接收了连接,这个 Socket
的处理过程就独占了当前线程。如果不多线程处理,服务器根本无法同时应对多个 Socket 连接。
因此我们可以引入多线程的写法, 那么,我们怎么引入呢?
笔者选的的是线程池,这样方便管理
来看具体代码:
ExecutorService executorService = Executors.newCachedThreadPool(); // 创建线程池while (true) {Socket socket = serverSocket.accept(); // 接受连接executorService.submit(() -> { // 把任务提交给线程池try {processwork(socket); // 多线程处理该连接} catch (IOException e) {throw new RuntimeException(e);}});
}
newCachedThreadPool()
:这是一个可自动扩容的线程池,适合连接数不固定、通信时长不一致的场景;
submit(() -> {...})
:使用 Lambda 表达式将每个客户端的任务包装成线程任务提交;每个客户端的
Socket
都被交给线程池中的一个线程独立处理,互不干扰。
完整代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TcpEchoServer {ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);// 绑定端口号
// 和 UDP 不同,TCP 在通信前必须先建立连接(就是三次握手)。
// 所以服务器要做的第一件事:不是接收数据,而是 等待客户端来连我。}public void start() throws IOException {System.out.println("服务器启动了");ExecutorService executorService = Executors.newCachedThreadPool();//动态增长的线程池while (true) {Socket socket = serverSocket.accept(); // 建立连接executorService.submit(() ->{try {processwork(socket);} catch (IOException e) {throw new RuntimeException(e);}});}
// Socket socket = serverSocket.accept(); // 建立连接
// processwork(socket);}private void processwork(Socket socket) throws IOException {// 1.读取请求// 2.响应// 3.返回响应try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){// 包装一下Scanner scanner = new Scanner(inputStream);//填入什么参数,就代表了什么输入方式PrintWriter printWriter = new PrintWriter(outputStream);while(true) {String request = scanner.nextLine();// 读取请求String response = process(request); // 回显printWriter.println(response); // 返回响应printWriter.flush(); // 刷新缓冲区,确保已经返回// 4.打印日志System.out.printf("[%s:%d] request: %s, response: %s\n",socket.getInetAddress().toString(),socket.getPort(),request,response);}}finally {socket.close();}}private String process(String request){return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}
效果如下:
由此可见,可以同步的和服务器进行网络通信
如果多线程依旧无法满足要求,那么还可以考虑多路复用,这个的话以后有时间笔者完全理解了,就写博客分享一下
结尾
这一篇的文本量也达到了1w字往上,希望对于读者们有帮助
后面笔者还想开博客介绍一下 IO操作,HTTPS和HTTP协议,希望能多多支持
相关文章:

JAVA网络编程——socket套接字的介绍下(详细)
目录 前言 1.TCP 套接字编程 与 UDP 数据报套接字的区别 2.TCP流套接字编程 API 介绍 TCP回显式服务器 Scanner 的多种使用方式 PrintWriter 的多种使用方式 TCP客户端 3. TCP 服务器中引入多线程 结尾 前言 各位读者大家好,今天笔者继续更新socket套接字的下半部分…...
Apache SeaTunnel 引擎深度解析:原理、技术与高效实践
Apache SeaTunnel 作为新一代高性能分布式数据集成平台,其核心引擎设计融合了现代大数据处理架构的精髓。 Apache SeaTunnel引擎通过分布式架构革新、精细化资源控制及企业级可靠性设计,显著提升了数据集成管道的执行效率与运维体验。其模块化设计允许用…...
深入理解 Maven 循环依赖问题及其解决方案
在 Java 开发领域,Maven 作为主流构建工具极大简化了依赖管理和项目构建。然而**循环依赖(circular dependency)**问题仍是常见挑战,轻则导致构建失败,重则引发类加载异常和系统架构混乱。 本文将从根源分析循环依赖的…...
pytest中的元类思想与实战应用
在Python编程世界里,元类是一种强大而高级的特性,它能在类定义阶段深度定制类的创建与行为。而pytest作为热门的测试框架,虽然没有直接使用元类,但在设计机制上,却暗含了许多与元类思想相通的地方。接下来,…...
前端生成UUID
UUID(Universally Unique Identifier)是一种在分布式系统中广泛使用的标识符,具有全球唯一性。在前端开发中,生成可靠的UUID对于数据追踪、会话管理、缓存键生成等场景至关重要。接下来将深入探讨UUID的实现原理、前端生成方案及最佳实践。 一、UUID标准与版本 1. UUID结构…...
玩客云WS1608控制LED灯的颜色
玩客云WS1608控制LED灯的颜色 玩客云设备有个红、绿、蓝三色led灯,在刷入armbian系统以后,这个灯的颜色就会显示异常,往往是一直显示红色。 如果要自动动手调整led灯的颜色,控制命令如下(需要root用户执行࿰…...

实验三 企业网络搭建及应用
实验三 企业网络搭建及应用 一、实验目的 1.掌握企业网络组建方法。 2.掌握企业网中常用网络技术配置方法。 二、实验描述 某企业设有销售部、市场部、技术部和财务部四个部门。公司内部网络使用二层交换机作为用户的接入设备。为了使网络更加稳定可靠,公司决定…...

顶会新热门:机器学习可解释性
🧀机器学习模型的可解释性一直是研究的热点和挑战之一,同样也是近两年各大顶会的投稿热门。 🧀这是因为模型的决策过程不仅需要高准确性,还需要能被我们理解,不然我们很难将它迁移到其它的问题中,也很难进…...
ReactJS 中的 JSX工作原理
文章目录 前言✅ 1. JSX 是什么?🔧 2. 编译后的样子(核心机制)🧱 3. React.createElement 做了什么?🧠 4. JSX 与组件的关系🔄 5. JSX 到真实 DOM 的过程📘 6. JSX 与 Fr…...

《STL--stack 和 queue 的使用及其底层实现》
引言: 上次我们学习了容器list的使用及其底层实现,相对来说是比较复杂的,今天我们要学习的适配器stack和queue与list相比就简单很多了,下面我们就开始今天的学习: 一:stack(后进先出ÿ…...
ArcGIS Pro 3.4 二次开发 - 地理处理
环境:ArcGIS Pro SDK 3.4 + .NET 8 文章目录 地理处理1 通用1.1 如何执行模型工具1.2 设置地理处理范围环境1.3 在 Geoprocessing 窗格中打开脚本工具对话框1.4 打开特定工具的地理处理工具窗格1.5 获取地理处理项目项1.6 阻止通过GP创建的特征类自动添加到地图中1.7 GPExecut…...

基于springboot的医护人员排班系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...
Asp.Net Core FluentValidation校验框架
文章目录 前言一、使用步骤1.安装 NuGet 包2.创建模型3.创建验证器4.配置 Program.cs5.创建控制器6.测试结果 二、常见问题及注意事项三、性能优化建议总结 前言 FluentValidation 是一个流行的 .NET 库,用于构建强类型的验证规则。它通常用于验证领域模型、DTO等对…...

CRISPR-Cas系统的小型化研究进展-文献精读137
Progress in the miniaturization of CRISPR-Cas systems CRISPR-Cas系统的小型化研究进展 摘要 CRISPR-Cas基因编辑技术由于其简便性和高效性,已被广泛应用于生物学、医学、农学等领域的基础与应用研究。目前广泛使用的Cas核酸酶均具有较大的分子量(通…...

利用python工具you-get下载网页的视频文件
有时候我们可能在一个网站看到一个视频(比如B站),想下载,但是页面没有下载视频的按钮。这时候,我们可以借助python工具you-get来实现下载功能。下面简要说下步骤 (一)因为使用的是python工具&a…...
Wi-Fi 切换 5G 的时机
每天都希望 Wi-Fi 在我离开信号覆盖范围时能尽快切到 5G,但每次它都能坚挺到最后半格信号,我却连看个天气预报都看不了…我不得不手工关闭 Wi-Fi,然后等走远了之后再打开,如此反复,不厌其烦。 早上出门上班,…...
【请关注】各类数据库优化,抓大重点整改,快速优化空间mysql,Oracle,Neo4j等
各类数据库优化,抓大重点整改,快速优化,首先分析各数据库查询全部表的空间大小及记录条数的语句: MySQL -- 查看所有表的空间大小 SELECT TABLE_SCHEMA AS 数据库名, TABLE_NAME AS 表名, ENGINE AS 存储引擎, CONCAT(ROUND(DAT…...
Mybatis Plus JSqlParser解析sql语句及JSqlParser安装步骤
MyBatis Plus 整合 JSqlParser 进行 SQL 解析的实现方案,主要包括环境配置和具体应用。通过 Maven 添加mybatis-plus-core 和 jsqlparser 依赖后,可用 CCJSqlParserUtil 解析 SQL 语句,支持对 SELECT、UPDATE 等语句的语法树分析和重构。技术…...
React从基础入门到高级实战:React 高级主题 - 性能优化:深入探索与实践指南
React 性能优化:深入探索与实践指南 引言 在现代Web开发中,尤其是2025年的技术环境下,React应用的性能优化已成为开发者不可忽视的核心课题。随着用户对应用速度和体验的要求日益提高,React应用的规模和复杂性不断增加ÿ…...
负载均衡群集---Haproxy
目录 一、HAproxy 一、概念 二、核心作用 三、主要功能特性 四、应用场景 五、优势与特点 二、 案例分析 1. 案例概述 2. 案例前置知识点 (1)HTTP 请求 (2)负载均衡常用调度算法 (3)常见的 web …...
2025年5月个人工作生活总结
本文为 2025年5月工作生活总结。 研发编码 一个项目的临时记录 月初和另一项目同事向业主汇报方案,两个项目都不满意,后来领导做了调整,将项目合并,拆分了好几大块。原来我做的一些工作,如数据库、中间件等ÿ…...

【stm32开发板】单片机最小系统原理图设计
一、批量添加网络标签 可以选择浮动工具中的N,单独为引脚添加网络标签。 当芯片引脚非常多的时候,选中芯片,右键选择扇出网络标签/非连接标识 按住ctrl键即可选中多个引脚 点击将引脚名称填入网络名 就完成了引脚标签的批量添加 二、电源引…...

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.2 R语言解题
本文是实验设计与分析(第6版,Montgomery著,傅珏生译) 第5章析因设计引导5.7节思考题5.2 R语言解题。主要涉及方差分析,正态假设检验,残差分析,交互作用。 dataframe<-data.frame( Surfacec(74,64,60,92…...

2025山东CCPC题解
文章目录 L - StellaD - Distributed SystemI - Square PuzzleE - Greatest Common DivisorG - Assembly Line L - Stella 题目来源:L - Stella 解题思路 签到题,因为给出的字母不是按顺序,可以存起来赋其值,然后在比较。 代码…...
【解决办法】ubuntu重启不起来,输入用户名和密码进不去,又重新返回登录页。
项目场景: ubuntu重启不起来,输入用户名和密码进不去,又重新返回登录页。 问题描述 在华硕天选一代笔记本上面安装了ubuntu22.04.5桌面版,但是重启以后出现,输入了用户名和密码,等待一会还让输入用户名和…...

CentOS Stream 9 中部署 MySQL 8.0 MGR(MySQL Group Replication)一主两从高可用集群
🐇明明跟你说过:个人主页 🏅个人专栏:《MySQL技术精粹》🏅 🔖行路有良友,便是天堂🔖 目录 一、前言 1、MySQL 8.0 中的高可用方案 2、适用场景 二、环境准备 1、系统环境说明…...

pycharm 新UI 固定菜单栏 pycharm2025 中文版
pycharm 新UI 文件 -> 设置 -> 外观与行为 -> 外观 -> UI选项 -> 主菜单:显示在主工具栏上方. 即可固定...
跟单业务和量化交易业务所涉及到的设计模式
🔁 跟单业务中常用的设计模式: 1. 观察者模式(Observer) 场景:一个大V下单,系统需要自动通知所有跟随者进行同步下单。好处:解耦下单者与跟随者,支持灵活扩展、异步通知。面试亮点…...

我的世界Java版1.21.4的Fabric模组开发教程(十一)创建方块
这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第十一章——创建方块。想要阅读其他内容,请查看或订阅上面的专栏。 方块(Block) 是构成Minecraft世界的主要组成部分,是组成游戏地图的最基本单元,也是模组开发的核心元素之一…...

VR/AR 视网膜级显示破局:10000PPI 如何终结颗粒感时代?
一、传统液晶 “纱窗效应”:VR 沉浸体验的最大绊脚石 当用户首次戴上 VR 头显时,眼前密密麻麻的像素网格往往打破沉浸感 —— 这正是传统液晶显示在近眼场景下的致命缺陷。受限于 500-600PPI 的像素密度,即使达到 4K 分辨率,等效到…...