【网络编程通关之路】 Tcp 基础回显服务器(Java实现)及保姆式知识原理详解 ! ! !

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在这里插入图片描述

引言

在这个数字化时代,信息的快速流通已成为我们日常生活的一部分。想象一下,当你发送一封电子邮件或浏览网页时,背后是一系列复杂的网络协议在默默工作,确保数据的准确传输。

今天,我们将聚焦于这些协议中的一个核心成员——传输控制协议(TCP)。TCP协议是互联网通信的基石,它通过确保数据的可靠传输,支撑着我们每天使用的无数网络服务。

目录

  1. Tcp回显服务器的普通实现

  2. Tcp 回显服务器的多线程实现

  3. Tcp 回显服务器的线程池实现

一. Tcp 回显服务器的普通实现

1. Tcp 的特点

在上一篇 实现Udp 的回显服务器的文章中 , 我们提及Tcp 和 Udp 分别有4个主要的特点

  • Tcp 是 可靠 传输, Udp是 不可靠 传输。
  • Tcp是面向 字节流, Udp是面向 数据报
  • Tcp 是 有连接 , Udp是 无连接
  • Tcp 是 全双工 , Udp也是 全双工

关于以上这些 特点 还有 回显服务器 的详解全部都收录到了 【网络编程通关之路】 Udp 基础回响服务器(Java实现)及你不知道知识原理详解 ! ! ! 这篇文章中 。

Tcp网络编程文章详解

还没学习过或者忘记的小伙伴记得去看看哦。

2. Tcp使用的相关类

TcpUdp一样, 在进行网络通信的过程中,需要调用系统 Socket api , 但在 Java标准库 中已经封装好了相关的类, 通过这几个类, 在 JVM 中来调用系统原生的 Socket api操作网卡 , 进行网络通信。

关于Tcp 来实现回显

ServerSocket 类 :

在这里插入图片描述

  • 实例化ServerSocket 对象时, 只用于服务器一端 , 并且进行 端口号 连接 进程 的过程。

  • 用于建立 服务器客户端 连接,并且返回 Socket 对象。

    accept() 方法

鱼式疯言

从上面可以确定 Tcp的 有连接 的特点之一。

ServerSocket的构造方法 的连接是 端口号与进程的连接 , 相当于 “接好了电话线”

accept() 的连接是 服务器与客户端的连接 , 相当于 客户端那边给服务器 “打电话”, 而服务器这边就用 accept() 来接电话。完成连接。


Socket 类

在这里插入图片描述

  • 用于客户端与服务器连接:

    Socket 的构造方法, 在 实例化Socket 对象 时, 添加 IP地址端口号, 就意味着 建立了连接

  • 操作 Socket对象 来获取各种 IP地址 和 输入和输出流对象

    获取IP地址

    getInetAddress()

    获取输入字节流方法
    getInputStream()

    获取输出字节流方法

    getOutputStream()

鱼式疯言

  1. 由于我们 Tcp 特点 之一就是 面向字节流 , 并且是 全双工

所以我们既可以获取到 输入字节流对象 ,也可以获取到 输出字节流对象

  1. ServerSocket 类一般只适用于 服务器一端的端口号和进程的连接 , 而 Socket 一般只适用于 客户端一端服务器 的连接, 但是都适用于 服务器和客户端获取输入流与输出流 的操作。
  1. 同一台主机 上,同一个协议 , 一个 端口号 直接连接 一个进程

    但是在不同协议中, 一个端口号 可以连接 不同协议 下的进程。

  1. 无论是 ServerSocket 类 还是 Socket 类 , 都是属于 java.net 下的包的类。

回显服务器的普通实现代码展示

<1>. 服务器实现


package echoTCP;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.Executor;
import java.util.concurrent.Executors;public class MyTcpEchoServer {ServerSocket serverSocket = null;// 进行连接public MyTcpEchoServer(int port) {try {// 进行连接serverSocket = new ServerSocket(port);} catch (IOException e) {throw new RuntimeException(e);}}public  void start() {// 开始交互System.out.println("服务器开始运行...");while(true) {// 使用线程池Socket socket = null;try {socket = serverSocket.accept();} catch (IOException e) {throw new RuntimeException(e);}// 进行接收请求并响应ProcessServerConnect(socket);}}private void ProcessServerConnect(Socket socket) {try(InputStream inputSTream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {System.out.printf("客户端上线 : [客户端ip = %s,客户端端口号 = %d]\n",socket.getInetAddress(),socket.getPort());// 得到请求Scanner scanner = new Scanner(inputSTream);if(!scanner.hasNext()) {break;}// 得到请求String request = scanner.nextLine();// 计算响应// 执行业务String response =  process(request);// 返回响应// 让客户端得到业务的执行结果PrintWriter printWriter = new PrintWriter(outputStream);// 开始返回printWriter.println(response);// 进行刷新printWriter.flush();//                    打印日志System.out.printf("客户端下线 :  [ip = %s , port = %d], 请求 = %s , 响应 = %s\n",socket.getInetAddress(),socket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}private String process(String request) {return  request;}public static void main(String[] args) {MyTcpEchoServer myTcpEchoServer = new MyTcpEchoServer(9090);myTcpEchoServer.start();}
}

在这里插入图片描述

服务器一端的实现的整体流程可分为以下几步:

  1. 创建 ServerSocket 对象 , 在构造方法中参数列表添加 端口号 , 建立端口号与进程的 连接
   // 进行连接serverSocket = new ServerSocket(port);
  1. 调用 accept 方法让服务器与客户端进行,并返回一个 Socket 对象。
   Socket socket = null;try {socket = serverSocket.accept();} catch (IOException e) {throw new RuntimeException(e);}
  1. 获取到输入流,利用 Scanner 包装输入流 得到请求
// 得到请求
Scanner scanner = new Scanner(inputSTream);
if(!scanner.hasNext()) {break;
}// 得到请求
String request = scanner.nextLine();
  1. 计算响应 并把 输出流对象 包装到 printWriter 输出到客户端
// 计算响应// 执行业务String response =  process(request);// 返回响应// 让客户端得到业务的执行结果PrintWriter printWriter = new PrintWriter(outputStream);// 开始返回printWriter.println(response);
// 进行刷新printWriter.flush();
  1. 打印日志,并关闭 Socket 对象
//                    打印日志System.out.printf("客户端下线 :  [ip = %s , port = %d], 请求 = %s , 响应 = %s\n",socket.getInetAddress(),socket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}

鱼式疯言

补充细节

  1. 对于大部分 IO流 来说, 并不是 输入或输出一个/ 一段 就会加载到 硬盘 , 而是会存放到一个叫 缓冲区的地方, 当数据积攒到 一定的量 , 才会 加载过去

    所以我们为了每次只加载 一个 / 一段数据 , 可以调用 flush 这个方法 来将 缓冲区 的数据全部
    刷新出去

 // 进行刷新printWriter.flush();

  1. 小编在这里利用了 ScannerprintWriter 来包装输入和输出流。 但是小伙伴们也可以利用小编之前提及过的 IO流的操作方式 来进行哦, 效果是一样的 。

关于IO的流的操作文章, 可以多学习学习并且回去哦 💖 💖 💖 💖

IO流理论篇文章详解

IO流Java实践篇文章详解

  1. 对于上述 回显服务器 来说, 服务端一端 accept() 只有当服务器每次发来请求时,才会进行 连接, 否则进行 阻塞等待

<2>. 客户端实现

package echoTCP;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;public class MyTcpEchoClient {Socket clientSocket = null;// 进行连接public MyTcpEchoClient(String ip , int port) {try {// 进行连接clientSocket = new Socket(ip, port);} catch (IOException e) {throw new RuntimeException(e);}}public  void start() {// 开始交互System.out.println("客户端开始运行...");// 发送请求并接受响应ProcessServerConnect(clientSocket);}private void ProcessServerConnect(Socket socket) {try(InputStream inputSTream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {Scanner in = new Scanner(System.in);System.out.print("请输入你的需求-> ");//                输入请求并发送String request = in.nextLine();PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);// 进行刷新printWriter.flush();// 接收响应并输出Scanner scanner = new Scanner(inputSTream);if(!scanner.hasNext()) {break;}String response = scanner.nextLine();System.out.println("response = "+ response);}} catch (IOException e) {throw new RuntimeException(e);} finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}public static void main(String[] args) {MyTcpEchoClient myTcpEchoClient = new MyTcpEchoClient("127.0.0.1",9090);myTcpEchoClient.start();}
}

在这里插入图片描述

具体客户端一端的整体实现流程梳理

  1. 实例化Socket 对象, 并把 IP地址端口号 作为 Socket 构造方法的参数进行 客户端与服务端 的连接。
Socket clientSocket = null;// 进行连接
public MyTcpEchoClient(String ip , int port) {try {// 进行连接clientSocket = new Socket(ip, port);} catch (IOException e) {throw new RuntimeException(e);}
}
  1. 输入请求 并发送给 客户端
                Scanner in = new Scanner(System.in);System.out.print("请输入你的需求-> ");//                输入请求并发送String request = in.nextLine();PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);// 进行刷新printWriter.flush();
  1. 接收服务器返回的 响应并输出
 // 接收响应并输出Scanner scanner = new Scanner(inputSTream);if(!scanner.hasNext()) {break;}String response = scanner.nextLine();System.out.println("response = "+ response);
  1. 宣布服务器执行结束, 并 关闭Socket对象
 finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}

鱼式疯言

补充细节

  1. 对应上述代码中的 hasNext() 方法来说, 出现了 换行 才会 break 结束 出去, 而当 服务器/ 客户端 没有 发来数据时, 是会进入 阻塞等待 的, 不会break 直接跳出。
   if(!scanner.hasNext()) {break;}

二. Tcp 回显服务器的多线程实现

1. 代码展示

服务器源码

package echoTCP;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.Executor;
import java.util.concurrent.Executors;public class MyTcpEchoServer {ServerSocket serverSocket = null;// 进行连接public MyTcpEchoServer(int port) {try {// 进行连接serverSocket = new ServerSocket(port);} catch (IOException e) {throw new RuntimeException(e);}}public  void start() {// 开始交互System.out.println("服务器开始运行...");//        使用多线程while(true) {Thread t = new Thread(()->{Socket socket = null;try {socket = serverSocket.accept();} catch (IOException e) {throw new RuntimeException(e);}// 进行接收请求并响应ProcessServerConnect(socket);});t.start();}}private void ProcessServerConnect(Socket socket) {try(InputStream inputSTream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {System.out.printf("客户端上线 : [客户端ip = %s,客户端端口号 = %d]\n",socket.getInetAddress(),socket.getPort());// 得到请求Scanner scanner = new Scanner(inputSTream);if(!scanner.hasNext()) {break;}// 得到请求String request = scanner.nextLine();// 计算响应// 执行业务String response =  process(request);// 返回响应// 让客户端得到业务的执行结果PrintWriter printWriter = new PrintWriter(outputStream);// 开始返回printWriter.println(response);// 进行刷新printWriter.flush();//                    打印日志System.out.printf("客户端下线 :  [ip = %s , port = %d], 请求 = %s , 响应 = %s\n",socket.getInetAddress(),socket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}private String process(String request) {return  request;}public static void main(String[] args) {MyTcpEchoServer myTcpEchoServer = new MyTcpEchoServer(9090);myTcpEchoServer.start();}
}

客户端源码

package echoTCP;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;public class MyTcpEchoClient {Socket clientSocket = null;// 进行连接public MyTcpEchoClient(String ip , int port) {try {// 进行连接clientSocket = new Socket(ip, port);} catch (IOException e) {throw new RuntimeException(e);}}public  void start() {// 开始交互System.out.println("客户端开始运行...");// 发送请求并接受响应ProcessServerConnect(clientSocket);}private void ProcessServerConnect(Socket socket) {try(InputStream inputSTream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {Scanner in = new Scanner(System.in);System.out.print("请输入你的需求-> ");//                输入请求并发送String request = in.nextLine();PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);// 进行刷新printWriter.flush();// 接收响应并输出Scanner scanner = new Scanner(inputSTream);if(!scanner.hasNext()) {break;}String response = scanner.nextLine();System.out.println("response = "+ response);}} catch (IOException e) {throw new RuntimeException(e);} finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}public static void main(String[] args) {MyTcpEchoClient myTcpEchoClient = new MyTcpEchoClient("127.0.0.1",9090);myTcpEchoClient.start();}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 原理剖析

对于多线程的回显服务器的实现, 最主要是解决 多个 客户端同时给 一个 服务器 发送请求 的问题。

对于服务器来说 外边套着一个循环 , 里面又加了 一层循环 , 这样的话就会导致 两层循环 的加入

第一个客户端进入内循环 时, 它的任务还 没结束, 第二个客户端就向服务器 发送请求 , 这时由于内部的还 一直循环, 服务器就无法进入内循环 , 只能让第二个客户端一直停留在 缓冲区

这时我们就引入 多线程 的方式, 将每一个服务器都 分布同时 执行循环, 这样就能保证不会让 多个 服务器一直阻塞到 缓冲区

关于代码的实现实现流程, 只是在普通回显服务器的基础上加了 一行多线程 的代码。 其他都是一样的, 小编在这里就 不赘述了

三. Tcp 回显服务器的线程池实现

1. 代码展示

服务器一端

package echoTCP;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.Executor;
import java.util.concurrent.Executors;public class MyTcpEchoServer {ServerSocket serverSocket = null;// 进行连接public MyTcpEchoServer(int port) {try {// 进行连接serverSocket = new ServerSocket(port);} catch (IOException e) {throw new RuntimeException(e);}}public  void start() {// 开始交互System.out.println("服务器开始运行...");while(true) {// 使用线程池Executor executor = Executors.newCachedThreadPool();executor.execute(() -> {Socket socket = null;try {socket = serverSocket.accept();} catch (IOException e) {throw new RuntimeException(e);}// 进行接收请求并响应ProcessServerConnect(socket);});}}private void ProcessServerConnect(Socket socket) {try(InputStream inputSTream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {System.out.printf("客户端上线 : [客户端ip = %s,客户端端口号 = %d]\n",socket.getInetAddress(),socket.getPort());// 得到请求Scanner scanner = new Scanner(inputSTream);if(!scanner.hasNext()) {break;}// 得到请求String request = scanner.nextLine();// 计算响应// 执行业务String response =  process(request);// 返回响应// 让客户端得到业务的执行结果PrintWriter printWriter = new PrintWriter(outputStream);// 开始返回printWriter.println(response);// 进行刷新printWriter.flush();//                    打印日志System.out.printf("客户端下线 :  [ip = %s , port = %d], 请求 = %s , 响应 = %s\n",socket.getInetAddress(),socket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}private String process(String request) {return  request;}public static void main(String[] args) {MyTcpEchoServer myTcpEchoServer = new MyTcpEchoServer(9090);myTcpEchoServer.start();}
}

在这里插入图片描述
客户端一端

package echoTCP;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;public class MyTcpEchoClient {Socket clientSocket = null;// 进行连接public MyTcpEchoClient(String ip , int port) {try {// 进行连接clientSocket = new Socket(ip, port);} catch (IOException e) {throw new RuntimeException(e);}}public  void start() {// 开始交互System.out.println("客户端开始运行...");// 发送请求并接受响应ProcessServerConnect(clientSocket);}private void ProcessServerConnect(Socket socket) {try(InputStream inputSTream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {Scanner in = new Scanner(System.in);System.out.print("请输入你的需求-> ");//                输入请求并发送String request = in.nextLine();PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);// 进行刷新printWriter.flush();// 接收响应并输出Scanner scanner = new Scanner(inputSTream);if(!scanner.hasNext()) {break;}String response = scanner.nextLine();System.out.println("response = "+ response);}} catch (IOException e) {throw new RuntimeException(e);} finally {System.out.printf("任务执行结束: [%s,%d]\n",socket.getInetAddress(),socket.getPort());try {
//                    关闭 socket 流socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}public static void main(String[] args) {MyTcpEchoClient myTcpEchoClient = new MyTcpEchoClient("127.0.0.1",9090);myTcpEchoClient.start();}
}

在这里插入图片描述

在这里插入图片描述

代码说明

关于线程池的代码实现: 主要还是在原来 普通 回显服务器的基础上, 加上了线程池的 newCachedThreadPool 对象 。

这个线程池对象在 任务繁忙 时, 最多可以创建出 Integer.MAX_VALUES非核心线程

具体详情小伙伴们可以参考多线程的文章, 有重点讲解哦

多线程实践篇详解

非常适合 服务器开发使用

  // 使用线程池Executor executor = Executors.newCachedThreadPool();executor.execute(() -> {Socket socket = null;try {socket = serverSocket.accept();} catch (IOException e) {throw new RuntimeException(e);}// 进行接收请求并响应ProcessServerConnect(socket);});

鱼式疯言

如果是大量的客户端, 我们可能会用到上面的 线程池 来使用。

如果是海量的客户端使用, 就会使用 IO多路复用 (了解即可)。

总结

  1. Tcp回显服务器的普通实现: 从Tcp 的四大特点: 有连接, 面向字节流, 可靠传输, 全双工 的四个特点展开介绍 Tcp 的两个主要网络通信的类: ServerSocketSocket 两个类 ,并在代码中充分的使用并结合理解流程。

  2. Tcp 回显服务器的 多线程实现 : 利用多线程解决了一个服务器只能解决一个客户端的问题。

  3. Tcp 回显服务器的线程池实现: 从另外一个线程池的角度更解决大量客户端的问题。

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux下IO多路复用—select,poll,epoll

一.概述 1.IO多路复用介绍 IO多路复用是一种操作系统的技术&#xff0c;用于在单个线程或进程中管理多个输入输出操作。它的主要目的是通过将多个IO操作合并到一个系统调用中来提高系统的性能和资源利用率&#xff0c;避免了传统的多线程或多进程模型中因为阻塞IO而导致的资源…

在Linux下搭建go环境

下载go go官网&#xff1a;All releases - The Go Programming Language 我们可以吧压缩包下载到Windows上再传到Linux上&#xff0c;也可以直接web下载&#xff1a; wget https://golang.google.cn/dl/go1.23.0.linux-amd64.tar.gz 解压 使用命令解压&#xff1a; tar -x…

解决有向图中节点出度和入度计算问题

解决有向图中节点出度和入度计算问题 引言邻接链表表示法邻接链表的数据结构创建图添加边计算节点的出度伪代码C代码计算节点的入度伪代码C代码时间复杂度示例结论引言 在图论中,有向图是一种重要的数据结构,用于表示元素之间的方向性关系。有向图中的节点(顶点)通过边连接…

VBA之正则表达式(47)-- 快速将公式转换为静态值计算

实例需求&#xff1a;工作表I列包含多种计算公式&#xff0c;为了便于演示&#xff0c;将I列公式显示在J列单元格中&#xff0c;现在需要将公式的单元格引用转换为静态值&#xff0c;如K列所示。 示例代码如下。 Sub RegExpDemoReplace()Dim Res()Dim objRegEx As ObjectDim o…

[解决]Invalid configuration `aarch64-openwrt-linux‘: machine `aarch64-openwrt

背景 交叉编译libev-4.19 问题 checking host system type… Invalid configuration aarch64-openwrt-linux: machine aarch64-openwrt’ not recognized 解决 打开config.sub&#xff0c;在244行后添加"| aarch64-openwrt \ "

Git学习(001 git介绍以及安装)

尚硅谷2024最新Git企业实战教程&#xff0c;全方位学习git与gitlab 总时长 5:42:00 共40P 此文章包含第1p-第p4的内容 文章目录 介绍Git介绍GitLab介绍 概述Git安装版本控制工具介绍 介绍 Git介绍 GitLab介绍 相当于中央仓库 概述 Git安装 进入官网(下载当前版本 2.43.0) …

解决 RT-Thread bsp stm32l476-st-nucleo STM32L4 HAL库缺失问题

问题描述 当前最新的 RT-Thread 版本&#xff1a;5.2.0&#xff0c;发现在 编译 BSP stm32l476-st-nucleo&#xff0c;缺少了 STM32L4xx_HAL 驱动库&#xff0c;造成生成的 工程&#xff0c;如 Keil MDK5 工程无法编译通过 初步的【临时】解决方法是 回退 RT-Thread 的版本&am…

rabbitmq发送的消息接收不到

1.消息被其他消费者消费 2.主要说的2这种情况&#xff0c;就是在延迟队列中&#xff0c;忘记给一个bean加注解导致日志报exchange not found. 这个报错&#xff0c;进而引发了bindings没有绑定。没有绑定的话&#xff0c;发送消息就会接收不到。

心脑血管科曹启富医生谈:引起高血压的原因

曹医生指出&#xff0c;高血压这一日益普遍的健康问题&#xff0c;其根源深藏于多重复杂因素之中。首要提及的便是年龄因素&#xff0c;它如同时间的刻度&#xff0c;悄然影响着我们的血管健康。随着年龄的增长&#xff0c;血管逐渐失去往昔的弹性与活力&#xff0c;变得僵硬而…

HTMl标签;知识回忆;笔记分享;

HTML标签是用于定义和组织网页内容的基础构建块。每个标签都有特定的作用。 一&#xff0c;标准结构标签&#xff1a; HTML文档标准结构&#xff1a; <html><head></head><body>this is my second html... </body> </html> 【1】htm…

python-FastApi框架

文章目录 FastApi一. 简介二. 特性三. 安装1. 安装fastapi模块2. 安装ASGI服务器( Uvicorn 或者 Hypercorn) 四. 实例1. 创建**main.py**文件(GET请求)2. 运行3. 测试4. 更新main_py(加入PUT请求) 五. 自动化API文档1. Swagger UI(交互式文档)2. ReDoc(可选式文档) FastApi 一…

企微获客链接 中文乱码问题处理

企微获客链接 中文乱码问题处理 问题背景问题处理补充内容 问题背景 为了推广产品&#xff0c;同时更好的服务客户&#xff0c;公司在接入企业微信后&#xff0c;需要用到企微获客链接相关推广操作&#xff0c;那么通过API 接口创建企微获客链接时&#xff0c;出现了中文乱码问…

OpenCV 图像处理基础算法介绍c++

VS2022配置OpenCV环境 关于OpenCV在VS2022上配置的教程可以参考&#xff1a;VS2022 配置OpenCV开发环境详细教程 图像处理 图像处理是一个广泛的领域&#xff0c;它涉及到对图像数据进行分析、修改和改进的各种技术。以下是一些基本的图像处理操作&#xff0c;这些操作通常可…

AntV G6 的坑之——渲染残留/残影

G6 4.x 依赖的渲染引擎 antv/g4.x 版本支持了局部渲染&#xff0c;带了性能提升的同时&#xff0c;也带来了图形更新时可能存在渲染残影的问题。比如拖拽节点时&#xff0c;节点的文本会留下轨迹。 解决办法&#xff1a; 关闭局部渲染&#xff0c;graph.get("canvas"…

uni-app组件

一. 什么是组件,有什么好处? 在uni-app中&#xff0c;组件是构成应用的基本单位&#xff0c;它们是用来定义用户界面的一部分&#xff0c;并且通常包含了视图和逻辑。组件的设计使得开发者能够以声明式的方式构建应用界面&#xff0c;并且通过组件化的开发方式来提高代码的复…

Centos7 java安装

卸载自带 jdk 查询所有的 java( 使用最小配置命令行则查询不出 java 直接进行安装即可 ) 卸载以下4个java软件 删除之后在使用命令进行查询 rpm -qa | grep java 解压jdk&#xff1a; 找到下载位置 使用Ctrlf搜索 配置环境变量&#xff1a; 打开/ etc/profile 在末尾添加以下…

旅游行业怎么利用C#接口发送短信

旅游企业一般拥有众多的分支机构&#xff0c;同时各地分支机构又有众多下属分散在当地各区的旅游营业报名点&#xff0c;以前传统的解决方案是采用专线、MODEM拔号等方式&#xff0c;专线的成本很高&#xff0c;MODEM拔号更费时&#xff0c;且长途拔号互联成本在多点情况下费用…

【一起学Rust | 框架篇 | Tauri2.0框架】rust和前端的相互调用(前端调用rust)

文章目录 前言1. 前端调用rust&#xff08;command&#xff09;1. 在后端定义一个command2. 注册command3. 前端调用command 2. 前端调用rust&#xff08;event&#xff09;4. command完整实例 前言 本期将继续接着上一期&#xff0c;继续探索tauri中rust和前端的相互调用&…

【ceph学习】ceph如何进行数据的读写(1)

版本 ceph版本为17. ceph如何进行读写接口的实现 Ceph的客户端通过librados的接口进行集群的访问&#xff0c;这里的访问包括&#xff1a; 1&#xff09;对集群的整体访问 2&#xff09;对象的访问 两类接口&#xff0c;这套接口&#xff08;API&#xff09;包括C、C和Pytho…

XXE-labs靶场通关攻略

环境地址自行查找 1.寻找靶机地址 使用工具goby进行扫描 因为我的靶场是搭在ubuntu上 直接查找系统是Ubuntu的就可以找到 靶机IP 172.16.1.183 2.访问靶场 3.使用目录扫描工具进行扫描 使用kali自带的dirsearch进行扫描 可以看到一个robots.txt文件 4.访问robots.txt文件 …