[嵌入式系统-24]:RT-Thread -11- 内核组件编程接口 - 网络组件 - TCP/UDP Socket编程

目录

一、RT-Thread网络组件

1.1 概述

1.2 RT-Thread支持的网络协议栈

1.3 RT-Thread如何选择不同的网络协议栈

二、Socket编程

2.1 概述

2.2 UDP socket编程

2.3 TCP socket编程

2.4 TCP socket收发数据


一、RT-Thread网络组件

1.1 概述

RT-Thread 是一个开源的嵌入式实时操作系统(RTOS),它提供了丰富的网络组件用于网络通信。

RT-Thread 的网络组件包括以下几个方面:

  1. TCP/IP 协议栈:RT-Thread 提供了完整的 TCP/IP 协议栈,包括 IP 协议、TCP 协议和 UDP 协议等。它支持 IPV4 和 IPV6,并提供了常用的网络协议(如 DHCP、DNS)的实现。

  2. Socket API:RT-Thread 提供了类似于 POSIX socket API 的接口,使开发者可以使用常见的网络编程模型(如 TCP 或 UDP)在 RT-Thread 上进行网络通信。

  3. LWIP:RT-Thread 基于 LWIP(Lightweight IP)实现了 TCP/IP 协议栈。LWIP 是一个轻量级的 TCP/IP 协议栈,具有较小的内存占用和代码体积,适合嵌入式系统。

  4. PPP:RT-Thread 提供了 PPP(Point-to-Point Protocol)的实现,支持通过串口或以太网设备建立拨号连接,并通过拨号方式实现网络通信。

  5. 协议支持:除了 TCP/IP 协议栈外,RT-Thread 还支持其他网络协议,如 MQTT、CoAP、WebSocket 等,使开发者可以方便地实现各种应用场景的网络通信功能。

总的来说,RT-Thread 的网络组件提供了完整的网络通信功能,并提供了开发者常用的网络编程接口和协议支持,使嵌入式设备可以便捷地实现各种网络应用。

1.2 RT-Thread支持的网络协议栈

RT-Thread 支持多种网络协议栈,常见的有如下几种:

  1. LwIP(Lightweight IP)LwIP 是一个轻量级的网络协议栈,专为嵌入式系统设计,具有小巧、高效的特点。RT-Thread 使用 LwIP 作为默认的网络协议栈,支持 IPv4、IPv6、TCP、UDP、ICMP 等协议。

  2. uIP:uIP 也是一个轻量级的网络协议栈,适用于资源受限的嵌入式系统。RT-Thread 也提供了对 uIP 的支持,使得开发者可以根据实际需求选择合适的网络协议栈。

  3. Salstack:RT-Thread 也提供了 Salstack(Simple Abstract Layer for Stack)协议栈,相对于 LwIP 和 uIP 更轻量级。Salstack 的设计目标是提供简单易用的网络功能,支持 TCP、UDP、ICMP、ARP 等常用协议。

  4. MiCO TCP/IP:MiCO 是一种基于 LwIP 的 TCP/IP 协议栈,适用于连接性和通信性能要求较高的应用场景。RT-Thread 也支持 MiCO TCP/IP 协议栈。

这些网络协议栈在 RT-Thread 中提供了丰富的网络功能,开发者可以根据项目需求选择合适的协议栈。同时,RT-Thread 也支持用户自定义网络协议栈,使得定制化网络功能变得更加灵活。在使用网络功能时,你可以根据具体情况选择合适的网络协议栈,并结合相应的文档和示例进行开发。

1.3 RT-Thread如何选择不同的网络协议栈

在 RT-Thread 中选择不同的网络协议栈通常需要根据具体的项目需求和硬件平台来进行配置和选择。下面是一般的步骤:

  1. 配置网络协议栈

    • 进入 RT-Thread 的 BSP 配置目录,在 rtconfig.h 或 menuconfig 工具中找到网络协议栈的配置选项。
    • 根据需要选择要使用的网络协议栈,比如 LwIP、uIP、Salstack 或其他协议栈。
    • 根据选择的网络协议栈,进行相应的配置,比如 IP 地址、子网掩码、网关等。
  2. 初始化网络协议栈

    • 在应用程序中调用相应的网络协议栈初始化函数,以初始化选择的协议栈。具体的初始化函数根据选择的协议栈而定,一般在启动代码或应用程序初始化阶段执行。
  3. 编写网络通信代码

    • 根据选择的网络协议栈,编写相应的网络通信代码,比如创建套接字、发送数据、接收数据等操作。
    • 根据选定的协议栈提供的 API,实现对网络功能的调用和控制。
  4. 调试和测试

    • 在选择和配置完成后,进行调试和测试,确保网络协议栈正常工作,网络连接稳定可靠。
    • 可以使用网络调试工具或者监视网络数据流量等方法来验证网络功能是否符合预期。

通过以上步骤,你可以在 RT-Thread 中灵活选择并配置不同的网络协议栈,以满足项目的需求。在选择和配置的过程中,建议参考 RT-Thread 的官方文档和示例代码,以便更好地理解和使用不同的网络协议栈功能。

二、Socket编程

2.1 概述

在 RT-Thread 中进行 socket 编程是一种常见的网络编程方式,可以通过套接字(socket)接口实现网络通信。以下是关于 RT-Thread 中 socket 编程的概述:

  1. 套接字(Socket)

    • 在 RT-Thread 中,套接字是一种抽象的通信端点,通过套接字可以进行网络通信。开发者可以通过套接字接口进行数据的发送和接收,实现网络应用程序的通信功能。
  2. Socket 接口

    • RT-Thread 提供了类似于 POSIX 标准的 socket 接口,开发者可以直接调用这些接口实现网络通信,如创建套接字、绑定地址、监听连接、发送数据、接收数据等操作。
  3. 常用函数

    • 在 RT-Thread 中,常用的 socket 函数包括 socket()bind()listen()accept()connect()send()recv() 等,这些函数可以实现套接字的创建、绑定、监听、连接以及数据的发送和接收。
  4. 网络通信模式

    • RT-Thread 中的 socket 编程支持常见的网络通信模式,包括 TCP 和 UDP。开发者可以根据需要选择合适的协议来实现可靠的数据传输(TCP)或者快速的数据传输(UDP)。
  5. 多线程环境

    • RT-Thread 是一个支持多线程的实时操作系统,因此在进行 socket 编程时,需要考虑多线程环境下的并发和同步。开发者可以使用 RT-Thread 提供的线程同步机制来保护共享资源,确保多线程间的数据安全性。
  6. 错误处理

    • 在 socket 编程中,需要及时处理异常情况和错误,比如网络连接失败、数据传输超时等。通过对错误码进行检查和处理,可以提高程序的健壮性和稳定性。

通过使用 socket 接口,开发者可以在 RT-Thread 中实现各种网络应用程序,如客户端和服务器程序、网络数据采集和处理等。在进行 socket 编程时,建议结合 RT-Thread 提供的文档和示例代码,加深对网络通信的理解,并根据具体需求灵活应用各种 socket 函数。

2.2 UDP socket编程

在 RT-Thread 中进行 UDP(用户数据报协议) socket 编程是一种常见的网络编程方式,可以实现基于 UDP 协议的数据通信。以下是在 RT-Thread 中进行 UDP socket 编程的基本步骤:

  1. 创建 UDP 套接字

    • 使用 socket() 函数创建一个 UDP 套接字。在创建套接字时,需要指定协议族为 AF_INET(IPv4 地址族)或 AF_INET6(IPv6 地址族),类型为 SOCK_DGRAM(数据报套接字),协议为 IPPROTO_UDP(UDP 协议)。
  2. 绑定地址

    • 使用 bind() 函数将 UDP 套接字绑定到本地 IP 地址和端口上。通过绑定地址,UDP 套接字可以监听指定的本地地址和端口,以接收发送到该地址的数据包。
  3. 发送数据

    • 使用 sendto() 函数向目标地址发送 UDP 数据包。需要指定目标 IP 地址(目标主机地址)和端口号,以及待发送的数据内容和长度。
  4. 接收数据

    • 使用 recvfrom() 函数从 UDP 套接字接收数据包。可以指定一个缓冲区来存储接收到的数据,同时获取发送方的 IP 地址和端口号。
  5. 关闭套接字

    • 使用 closesocket() 函数关闭 UDP 套接字,释放资源并停止网络通信。

下面是一个简单的示例代码,演示了如何在 RT-Thread 中使用 UDP 套接字发送和接收数据:

#include <rtthread.h>
#include <sys/socket.h>void udp_socket_demo(void)
{int sockfd;struct sockaddr_in addr;char buffer[128];// 创建 UDP 套接字sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);// 绑定本地地址和端口addr.sin_family = AF_INET;addr.sin_port = htons(12345);addr.sin_addr.s_addr = inet_addr("192.168.1.100");bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));// 发送数据sendto(sockfd, "Hello UDP", 9, 0, (struct sockaddr *)&addr, sizeof(addr));// 接收数据recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, 0);// 关闭套接字closesocket(sockfd);
}

在实际应用中,开发者可以根据具体需求和场景,进行更加复杂和完善的 UDP socket 编程,实现各种基于 UDP 协议的网络通信功能。同时,建议结合 RT-Thread 的网络编程文档和示例,加深对 UDP socket 编程的理解,并进行必要的调试和测试工作。

2.3 TCP socket编程

在 RT-Thread 中进行 TCP socket 编程时,可以同时实现客户端和服务器端的功能。

首先,我们先介绍服务器端的示例代码:

#include <rtthread.h>
#include <netdb.h>
#include <sys/socket.h>#define PORT 8080int main(void)
{int sockfd, newsockfd;struct sockaddr_in server_addr, client_addr;socklen_t client_len;// 创建 TCP socketsockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){rt_kprintf("Failed to create TCP socket\n");return -1;}// 设置服务器地址server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);// 绑定服务器地址if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){rt_kprintf("Failed to bind address\n");return -1;}// 开始监听if (listen(sockfd, 5) < 0){rt_kprintf("Failed to listen on socket\n");return -1;}rt_kprintf("Server listening on port %d\n", PORT);while (1){// 接受客户端连接client_len = sizeof(client_addr);newsockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);if (newsockfd < 0){rt_kprintf("Failed to accept client connection\n");return -1;}rt_kprintf("Accepted new client connection\n");// 在这里可以进行与客户端通信的处理// 处理完client的通信,关闭连接close(newsockfd);}return 0;
}

上述代码中,服务器端首先创建一个 TCP socket,并绑定到指定的 IP 地址和端口号。然后通过 listen 函数开始监听客户端的连接请求。在接收到客户端的连接请求后,使用 accept 函数接受连接,创建一个新的 socket 来与客户端进行通信。在这个循环中,服务器端可以与多个客户端进行通信。

接下来是客户端的示例代码:

#include <rtthread.h>
#include <netdb.h>
#include <sys/socket.h>#define SERVER_IP "192.168.0.100"
#define SERVER_PORT 8080int main(void)
{int sockfd;struct sockaddr_in server_addr;// 创建 TCP socketsockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){rt_kprintf("Failed to create TCP socket\n");return -1;}// 设置服务器地址server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);// 连接服务器if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){rt_kprintf("Failed to connect to server\n");return -1;}// 在这里可以进行与服务器通信的处理// 关闭连接close(sockfd);return 0;
}

上述代码中,客户端创建一个 TCP socket,并使用 connect 函数连接到指定的服务器地址和端口号。在连接建立后,客户端可以进行与服务器通信的处理。

请注意,上述示例代码中的 IP 地址和端口号需要根据实际情况进行修改。在实际开发中,你可能需要处理更多的错误和异常情况,并且在通信过程中进行数据的发送和接收操作。

另外,还可以通过 RT-Thread 提供的套接字封装库 lwip_socket.h 来简化 TCP socket 编程。可以参考 RT-Thread 官方文档和示例代码获取更详细的信息和使用方法。

2.4 TCP socket收发数据

在 RT-Thread 上进行 TCP socket 编程,你可以使用 RT-Thread 提供的 Socket API 来创建和管理 TCP socket。

对于客户端,你可以按照以下步骤进行编程:

  1. 使用 socket 函数创建一个套接字,指定协议族为 AF_INET,类型为 SOCK_STREAM,以及协议为 IPPROTO_TCP。
  2. 使用 connect 函数将套接字连接到服务器的 IP 地址和端口号。
  3. 使用 send 函数来发送数据到服务器。
  4. 使用 recv 函数来接收服务器发送的数据。
  5. 使用 close 函数关闭套接字。

下面是一个简单的客户端代码示例:

#include <rtthread.h>
#include <netdb.h>
#include <sys/socket.h>#define SERVER_IP       "192.168.1.100"   // 服务器 IP 地址
#define SERVER_PORT     5000              // 服务器端口号void client_thread_entry(void* parameter)
{int sockfd;struct sockaddr_in server_addr;char buffer[1024];// 创建套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){rt_kprintf("Socket creation failed\n");return;}// 设置服务器地址信息rt_memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);// 连接到服务器if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){rt_kprintf("Connection failed\n");close(sockfd);return;}// 发送数据到服务器const char* data = "Hello, server!";if (send(sockfd, data, strlen(data), 0) < 0){rt_kprintf("Sending data failed\n");close(sockfd);return;}// 接收服务器发送的数据int recv_len;if ((recv_len = recv(sockfd, buffer, sizeof(buffer), 0)) > 0){buffer[recv_len] = '\0';rt_kprintf("Received data from server: %s\n", buffer);}else{rt_kprintf("Receiving data failed\n");}// 关闭套接字close(sockfd);
}// 启动客户端线程
int start_client(void)
{rt_thread_t thread;thread = rt_thread_create("client", client_thread_entry, RT_NULL, 2048, 25, 10);if (thread != RT_NULL){rt_thread_startup(thread);return 0;}return -1;
}

对于服务器端,你可以按照以下步骤进行编程:

  1. 使用 socket 函数创建一个套接字,指定协议族为 AF_INET,类型为 SOCK_STREAM,以及协议为 IPPROTO_TCP。
  2. 使用 bind 函数将套接字绑定到服务器的 IP 地址和端口号。
  3. 使用 listen 函数开始监听客户端连接请求。
  4. 使用 accept 函数接受客户端的连接请求,并返回一个新的套接字,通过这个套接字与客户端进行通信。
  5. 使用 send 函数发送数据给客户端。
  6. 使用 recv 函数接收客户端发送的数据。
  7. 使用 close 函数关闭套接字。

下面是一个简单的服务器端代码示例:

#include <rtthread.h>
#include <netdb.h>
#include <sys/socket.h>#define SERVER_PORT     5000              // 服务器端口号// 服务器线程的主函数
void server_thread_entry(void* parameter)
{int sockfd, new_sockfd;struct sockaddr_in server_addr, client_addr;socklen_t addr_len = sizeof(client_addr);char buffer[1024];// 创建套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){rt_kprintf("Socket creation failed\n");return;}// 设置服务器地址信息rt_memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);server_addr.sin_addr.s_addr = htonl(INADDR_ANY);// 绑定套接字到服务器地址if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){rt_kprintf("Binding failed\n");close(sockfd);return;}// 开始监听连接请求if (listen(sockfd, 5) < 0){rt_kprintf("Listening failed\n");close(sockfd);return;}rt_kprintf("Waiting for client connection...\n");// 接受客户端的连接请求if ((new_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &addr_len)) < 0){rt_kprintf("Accepting failed\n");close(sockfd);return;}rt_kprintf("Client connected\n");// 接收客户端发送的数据int recv_len;if ((recv_len = recv(new_sockfd, buffer, sizeof(buffer), 0)) > 0){buffer[recv_len] = '\0';rt_kprintf("Received data from client: %s\n", buffer);// 发送数据给客户端const char* data = "Hello, client!";if (send(new_sockfd, data, strlen(data), 0) < 0){rt_kprintf("Sending data failed\n");}}else{rt_kprintf("Receiving data failed\n");}// 关闭套接字close(new_sockfd);close(sockfd);
}// 创建并且启动服务器线程
int start_server(void)
{rt_thread_t thread;thread = rt_thread_create("server", server_thread_entry, RT_NULL, 2048, 25, 10);if (thread != RT_NULL){rt_thread_startup(thread);return 0;}return -1;
}

你可以根据需要将这两段代码添加到你的 RT-Thread 项目中,并根据实际情况修改服务器的 IP 地址和端口号。代码中的注释可以帮助你理解每个步骤的功能。

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

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

相关文章

SpringCloud(15)之SpringCloud Gateway

一、Spring Cloud Gateway介绍 Spring Cloud Gateway 是Spring Cloud团队的一个全新项目&#xff0c;基于Spring 5.0、SpringBoot2.0、 Project Reactor 等技术开发的网关。旨在为微服务架构提供一种简单有效统一的API路由管理方式。 Spring Cloud Gateway 作为SpringCloud生态…

ThreadLocal的一些理解

阅读本篇博客您将了解如下内容&#xff1a; TreadLocal的作用。ThreadLocal的实现原理。ThreadLocal是否会引起内存泄漏&#xff0c;在什么样的条件下引发&#xff0c;如何避免。 1、ThreadLocal的作用 使用线程封闭的指导思想来解决变量共享的并发安全问题&#xff0c;–可以…

【数据库】达梦数据库DM8开发版安装

目录 一、达梦数据库概述 1.1 达梦数据库简介 1.2 产品特性 1.3 产品架构 二、安装前准备 2.1 新建 dmdba 用户 2.2 修改文件打开最大数 2.3 挂载镜像 2.4 新建安装目录 2.5 修改安装目录权限 三、数据库安装 3.1 命令行安装 3.2 配置环境变量 四、配置实例 4.1…

十六、多边形填充和绘制

项目功能实现&#xff1a;对多边形进行轮廓绘制和填充 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 mult-drawing.h #pragma once#include<opencv2/opencv.hpp>using namespace cv;class Mult_Drawing { public:void mult_drawing(); };#pragma onc…

Rman全备和增量备份说明

RMAN备份分为全备和增量备份&#xff0c;全备不能成为增量备份策略的一部分&#xff0c;它也不能作为后续增量备份的基础。 RMAN增量备份分为0、1、2三级&#xff0c;其中0级备份是增量备份的基础&#xff0c;备份内容也跟全备份一样&#xff0c;要使用增量备份&#xff0c;必…

Android 面试问题 2024 版(其二)

Android 面试问题 2024 版&#xff08;其二&#xff09; 六、多线程和并发七、性能优化八、测试九、安全十、Material设计和 **UX/UI** 六、多线程和并发 Android 中的进程和线程有什么区别&#xff1f; 答&#xff1a;进程是在自己的内存空间中运行的应用程序的单独实例&…

[计算机网络]---TCP协议

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一 、TCP协…

基于SpringBoot + Layui的社区物业管理系统

项目介绍 社区物业管理系统是基于java编程语言&#xff0c;springboot框架&#xff0c;idea工具&#xff0c;mysql数据库进行开发&#xff0c;本系统分为业主和管理员两个角色&#xff0c;业主可以登陆系统&#xff0c;查看车位费用信息&#xff0c;查看物业费用信息&#xff0…

代码随想录算法训练营第58天 | 392.判断子序列 115.不同的子序列

判断子序列 这道题可以双指针方法解决。 class Solution { public:bool isSubsequence(string s, string t) {int s_index 0;for(int t_index 0; t_index < t.size(); t_index) {if(s[s_index] t[t_index]) {s_index;}}return s_index s.size();} };用动态规划也是可解…

力扣OJ题——随机链表的复制

题目&#xff1a; 138. 随机链表的复制 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 要求&#xff1a;构造这个链表的 深拷贝 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中…

Vue状态管理库-Pinia

一、Pinia是什么&#xff1f; Pinia 是 Vue 的专属状态管理库&#xff0c;它允许支持跨组件或页面共享状态&#xff0c;即共享数据&#xff0c;他的初始设计目的是设计一个支持组合式API的 Vue 状态管理库&#xff08;因为vue3一个很大的改变就是组合式API&#xff09;,当然这…

简介高效的 CV 入门指南: 100 行实现 InceptionResNet 图像分类

简介高效的 CV 入门指南: 100 行实现 InceptionResNet 图像分类 概述InceptionResNetInception 网络基本原理关键特征 ResNet 网络深度学习早期问题残差学习 InceptionResNet 网络InceptionResNet v1InceptionResNet v2改进的 Inception 模块更有效的残差连接设计 100 行实现 I…

Docker本地部署Rss订阅工具并实现公网远程访问

文章目录 1. Docker 安装2. Docker 部署Rsshub3. 本地访问Rsshub4. Linux安装Cpolar5. 配置公网地址6. 远程访问Rsshub7. 固定Cpolar公网地址8. 固定地址访问 Rsshub是一个开源、简单易用、易于扩展的RSS生成器&#xff0c;它可以为各种内容生成RSS订阅源。 Rsshub借助于开源社…

JDBC简介

JDBC体系结构 Java Data Base Connectivity&#xff08;JDBC&#xff09;&#xff0c;Java数据库连接。 JDBC重要的类和接口 JDBC API 定义了一组用于与数据库进行通信的接口和类&#xff0c;这些接口和类都定义在Java.sql包中。 类或接口作用DriverManager处理驱动程序的加…

校园兼职|大学生校园兼职小程序|基于微信小程序的大学生校园兼职系统设计与实现(源码+数据库+文档)

大学生校园兼职小程序目录 目录 基于微信小程序的大学生校园兼职系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户​微信端功能模块​ 2、管理员服务端功能模块 &#xff08;1&#xff09; 兼职管理 &#xff08;2&#xff09;论坛管理 &#xff08;3&…

Leetcode 102.二叉树的层序遍历

目录 题目 思路 题目 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]]示例…

leetcode hot100组合综合四

本题中&#xff0c;是要求nums中求的总和为target的排列数&#xff0c;因为题中说了&#xff0c;元素顺序不同&#xff0c;则可以视为不同的结果之一。 所以&#xff0c;根据对背包问题的总结&#xff0c;本题中元素可以重复使用&#xff0c;是完全背包并且需要求排列数&#…

Redis之缓存穿透问题解决方案实践SpringBoot3+Docker

文章目录 一、介绍二、方案介绍三、Redis Docker部署四、SpringBoot3 Base代码1. 依赖配置2. 基本代码 五、缓存优化代码1. 校验机制2. 布隆过滤器3. 逻辑优化 一、介绍 当一种请求&#xff0c;总是能越过缓存&#xff0c;调用数据库&#xff0c;就是缓存穿透。 比如当请求一…

数字之美:探索人工智能绘画的奇妙世界

目录 引言AI绘画的定义与发展历程定义与发展历程AI绘画产品有哪些? AI绘画的应用领域设计与创意产业影视与游戏制作数字艺术与展览 AI绘画的基本原理与技术深度学习与神经网络生成对抗网络&#xff08;GAN&#xff09;风格迁移算法 AI绘画效果展示一只带着墨镜的小猫在高楼林立…

05.STLvector、list、stack、queue

STL标准模板库 standard template library STL将原来常用的容器和操作进行封装&#xff0c;增加了C的编码效率 容器 string #include vector #include list #include stack #include queue #include set #include map #include 迭代器 容器和算法之间的粘合剂&#xff0…