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

【ESP32】ESP-IDF开发 | WiFi开发 | UDP用户数据报协议 + UDP客户端和服务器例程

1. 简介

        UDP协议(User Datagram Protocol),全称用户数据报协议,它是一种面向非连接的协议,面向非连接指的是在正式通信前不必与对方先建立连接, 不管对方状态就直接发送。至于对方是否可以接收到这些数据内容,UDP协议无法控制,因此说UDP协议是一种不可靠的协议。UDP协议适用于一次只传送少量数据、对可靠性要求不高的应用环境。

        因为UDP的数据传输不一定是一对一的,所以也衍生出单播、组播和广播的概念。

1. 单播

        单播(unicast),是指封包在计算机网络的传输中,目的地址为单一目标的一种传输方式。它是现今网络应用最为广泛,通常所使用的网络协议或服务大多采用单播传输,例如TCP协议。

2. 多播

        组播(multicast),也叫多播或群播。 指把信息同时传递给一组目的地址。它使用策略是最高效的,因为消息在每条网络链路上只需传递一次,而且只有在链路分叉的时候,消息才会被复制。

3. 广播

        广播(broadcast),是指封包在计算机网络中传输时,目的地址为网络中所有设备的一种传输方式。

2. lwIP

         ESP-IDF使用lwIP库实现TCP/IP协议栈,这个库在大多数嵌入式系统中都有用到,它是一个轻量的TCP/IP协议层套件。

        支持以下特性:

  • IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over multiple network interfaces
  • ICMP (Internet Control Message Protocol) for network maintenance and debugging
  • IGMP (Internet Group Management Protocol) for multicast traffic management
  • MLD (Multicast listener discovery for IPv6). Aims to be compliant with RFC 2710. No support for MLDv2
  • ND (Neighbor discovery and stateless address autoconfiguration for IPv6). Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 (Address autoconfiguration)
  • DHCP, AutoIP/APIPA (Zeroconf) and (stateless) DHCPv6
  • UDP (User Datagram Protocol) including experimental UDP-lite extensions
  • TCP (Transmission Control Protocol) with congestion control, RTT estimation fast recovery/fast retransmit and sending SACKs
  • raw/native API for enhanced performance
  • Optional Berkeley-like socket API
  • TLS: optional layered TCP ("altcp") for nearly transparent TLS for any
  • TCP-based protocol (ported to mbedTLS) (see changelog for more info)
  • PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet)
  • DNS (Domain name resolver incl. mDNS)
  • 6LoWPAN (via IEEE 802.15.4, BLE or ZEP)

        支持以下应用层协议:

  • HTTP server with SSI and CGI (HTTPS via altcp)
  • SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp
  • SNTP (Simple network time protocol)
  • NetBIOS name service responder
  • MDNS (Multicast DNS) responder
  • iPerf server implementation
  • MQTT client (TLS support via altcp)

3. 例程

         例程分别在ESP32上实现TCP客户端和服务端,使用电脑作为另一方进行简单通信测试。需要注意的是,测试时,ESP32和电脑必须处于同一局域网。 

        电脑端测试使用的上位机为VOFA+,下载地址:VOFA+

3.1 发送端

        这个例程配置ESP32为发送端,当连接WiFi热点成功后会向目标IP每隔1秒发送一段数据。

#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "nvs_flash.h"
#include "sys/socket.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "netdb.h"
#include "arpa/inet.h"#include <string.h>#define TAG "app"
#define HOST_IP_ADDR "172.16.10.26"
#define HOST_PORT 20001static const char *payload = "Hello from ESP32\r\n";
static TaskHandle_t client_task_handle;static void udp_client_task(void *args)
{struct sockaddr_in dest_addr;dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);dest_addr.sin_family = AF_INET;dest_addr.sin_port = htons(HOST_PORT);int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);if (sock < 0) {ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);}ESP_LOGI(TAG, "Socket created, sending to %s:%d", HOST_IP_ADDR, HOST_PORT);while (1) {int err = sendto(sock, payload, strlen(payload), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (err < 0) {ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);break;}ESP_LOGI(TAG, "Message sent");vTaskDelay(1000 / portTICK_PERIOD_MS);}close(sock);vTaskDelete(NULL);
}static void wifi_event_handler(void* arg,esp_event_base_t event_base,int32_t event_id,void* event_data)
{if (event_base == IP_EVENT) {if (event_id == IP_EVENT_STA_GOT_IP) {xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, &client_task_handle);}} else if (event_base == WIFI_EVENT) {if (event_id == WIFI_EVENT_STA_DISCONNECTED) {vTaskDelete(client_task_handle);} else if (event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();}}
}int app_main()
{/* 初始化NVS */esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ESP_ERROR_CHECK(nvs_flash_init());}/* 初始化WiFi协议栈 */ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_create_default_wifi_sta();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL));ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL));wifi_config_t wifi_config = {.sta = {.ssid = "QXL",.password = "88888888",.threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK,},};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));ESP_ERROR_CHECK(esp_wifi_start());return 0;
}

        ESP32的WiFi驱动初始化在前面的文章已经有详细的介绍了,这里不再赘述。

        因为UDP是面向无连接的,所以编程会相对简单,流程如下:

1. 创建套接字

        调用socket函数。第一个参数表示IP协议,这里使用IPv4,对应IP_INET;第二个参数表示socket类型,UDP协议只能填SOCK_DGRAM;第三个参数表示协议栈类型,这里填IPPROTO_IP。函数会返回套接字描述符。

2. 套接字配置(可选)

        socket的接收和发送默认是阻塞的,即如果数据不到达就一直等待,所以根据应用的需要设置接收的超时时间。

        调用setsockopt函数。第一个参数为套接字描述符;第二个参数为协议层,必须填SOL_SOCKET;第三个参数为设置项,填SO_RCVTIMEO,设置超时时间,当然函数还支持以下配置项:

#define SO_DEBUG        0x0001 /* Unimplemented: turn on debugging info recording */
#define SO_ACCEPTCONN   0x0002 /* socket has had listen() */
#define SO_DONTROUTE    0x0010 /* Unimplemented: just use interface addresses */
#define SO_USELOOPBACK  0x0040 /* Unimplemented: bypass hardware when possible */
#define SO_LINGER       0x0080 /* linger on close if data present */
#define SO_DONTLINGER   ((int)(~SO_LINGER))
#define SO_OOBINLINE    0x0100 /* Unimplemented: leave received OOB data in line */
#define SO_REUSEPORT    0x0200 /* Unimplemented: allow local address & port reuse */
#define SO_SNDBUF       0x1001 /* Unimplemented: send buffer size */
#define SO_RCVBUF       0x1002 /* receive buffer size */
#define SO_SNDLOWAT     0x1003 /* Unimplemented: send low-water mark */
#define SO_RCVLOWAT     0x1004 /* Unimplemented: receive low-water mark */
#define SO_SNDTIMEO     0x1005 /* send timeout */
#define SO_RCVTIMEO     0x1006 /* receive timeout */
#define SO_ERROR        0x1007 /* get error status and clear */
#define SO_TYPE         0x1008 /* get socket type */
#define SO_CONTIMEO     0x1009 /* Unimplemented: connect timeout */
#define SO_NO_CHECK     0x100a /* don't create UDP checksum */
#define SO_BINDTODEVICE 0x100b /* bind to device */

        比较常用的就是SO_RCVTIMEO,设置接收超时;SO_SNDTIMEO,设置发送超时。上面带Unimlemented注释的是ESP-IDF不支持的配置

        每种配置项需要传入的数据是不一样的,用之前建议参考官方的说明文档。设置超时传入的是struct timeval这个结构体。

struct timeval {time_t		tv_sec;suseconds_t	tv_usec;
};

        tv_sec设置秒数,tv_usec设置微秒数。

3. 发送数据

        调用sendto函数。参数1为套接字描述符;参数2为数据指针;参数3为数据长度;参数4为标志位,有以下选项:

#define MSG_PEEK       0x01
#define MSG_WAITALL    0x02
#define MSG_OOB        0x04
#define MSG_DONTWAIT   0x08
#define MSG_MORE       0x10
#define MSG_NOSIGNAL   0x20

        这些标志位是发送和接收都支持的,比较常用的是MSG_DONTWAIT,像发送和接收函数是阻塞的,使能这个标志位可以让函数立即返回,不等待数据。

        参数5为目标地址信息,结构体如下:

struct sockaddr_in {u8_t            sin_len;sa_family_t     sin_family;in_port_t       sin_port;struct in_addr  sin_addr;
#define SIN_ZERO_LEN 8char            sin_zero[SIN_ZERO_LEN];
};
#endif /* LWIP_IPV4 */
  • sin_len:数据长度(一般不需要填);
  • sin_family:套接字类型,IPv4填AF_INET,IPv6填AF_INET6,其他填AF_UNSPEC;
  • sin_port:端口;
  • sin_zero:预留字节(不用管)。

        参数6为目标地址结构体长度。

4. 关闭连接

        调用close函数。传入套接字描述符即可。

        使用上位机时,数据引擎选择“RawData”,数据接口选择UDP,远程IP填写ESP32获取到的IP,本地端口要与ESP32发送报文的端口一致。设置好后,点击左上角的圆形按钮即可启动连接,在下面文本框能看到接收到的消息。

2.2 接收端

        这个例程创建一个UDP接收端,接收所有发送至指定端口的UDP包。 

#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "nvs_flash.h"
#include "sys/socket.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "netdb.h"
#include "arpa/inet.h"#include <string.h>#define TAG "app"
#define SERVER_PORT 20001static TaskHandle_t server_task_handle;static void udp_server_task(void *args)
{char rx_buffer[128];struct sockaddr_in dest_addr;dest_addr.sin_addr.s_addr = htonl(IPADDR_ANY);dest_addr.sin_family = AF_INET;dest_addr.sin_port = htons(SERVER_PORT);int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);if (sock < 0) {ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);}int opt = 0;setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(int));int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (err < 0) {ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);goto __exit;}ESP_LOGI(TAG, "Socket bound to port %d", SERVER_PORT);while (1) {struct sockaddr_in source_addr = {0};socklen_t socklen = sizeof(source_addr);memset(rx_buffer, 0, sizeof(rx_buffer));int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);if (len < 0) {ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);} else {ESP_LOGI(TAG, "Received %d bytes from " IPSTR ":%d, data: %s", len, IP2STR((esp_ip4_addr_t *) &source_addr.sin_addr), source_addr.sin_port, rx_buffer);}}__exit:close(sock);vTaskDelete(NULL);
}static void wifi_event_handler(void* arg,esp_event_base_t event_base,int32_t event_id,void* event_data)
{if (event_base == IP_EVENT) {if (event_id == IP_EVENT_STA_GOT_IP) {xTaskCreate(udp_server_task, "udp_server", 4096, NULL, 5, &server_task_handle);}} else if (event_base == WIFI_EVENT) {if (event_id == WIFI_EVENT_STA_DISCONNECTED) {vTaskDelete(server_task_handle);} else if (event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();}}
}int app_main()
{/* 初始化NVS */esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ESP_ERROR_CHECK(nvs_flash_init());}/* 初始化WiFi协议栈 */ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_create_default_wifi_sta();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL));ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL));wifi_config_t wifi_config = {.sta = {.ssid = "Your SSID",.password = "Your password",.threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK,},};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));ESP_ERROR_CHECK(esp_wifi_start());return 0;
}

         接收者的流程和发送者差不多,下面只介绍有差异的部分。

1. 创建套接字

        参考前面。

2. 配置套接字(可选)

        调用setsockopt函数。除了前面介绍到的配置,UDP还支持一个SO_BROADCAST的配置,用来使能广播包的接收,我这里是配置为禁用。

3. 绑定IP(可选)

        调用bind函数。参数1为套接字描述符,参数2为IP地址结构体,参数3为结构体长度。通过bind可以绑定监听的IP地址和端口,只有接收到的数据包目标IP和端口一致才会处理,我这里配置接收任意IP,端口为20001。

4. 接收数据

        调用recvfrom函数。传入参数和sendto一致,不同的是后面的IP地址结构体是输出参数,不需要初始化,它会返回数据包的源IP信息。

5. 关闭套接字

        参考前面。

        上位机的配置和前面基本一样,唯一的不同是远程端口要保证和ESP32绑定的端口一致

相关文章:

【ESP32】ESP-IDF开发 | WiFi开发 | UDP用户数据报协议 + UDP客户端和服务器例程

1. 简介 UDP协议&#xff08;User Datagram Protocol&#xff09;&#xff0c;全称用户数据报协议&#xff0c;它是一种面向非连接的协议&#xff0c;面向非连接指的是在正式通信前不必与对方先建立连接&#xff0c; 不管对方状态就直接发送。至于对方是否可以接收到这些数据内…...

【PyQt5】数据库连接失败: Driver not loaded Driver not loaded

报错内容如下&#xff1a; 可以看到目前所支持的数据库驱动仅有[‘QSQLITE’, ‘QMARIADB’, ‘QODBC’, ‘QODBC3’, ‘QPSQL’, ‘QPSQL7’] 我在网上查找半天解决方法未果&#xff0c;其中有一篇看评论反馈是可以使用的&#xff0c;但是PyQt5的版本有点低&#xff0c;5.12…...

Unity游戏(Assault空对地打击)开发(1) 创建项目和选择插件

目录 前言 创建项目 插件导入 地形插件 前言 这是游戏开发第一篇&#xff0c;进行开发准备。 创作不易&#xff0c;欢迎支持。 我的编辑器布局是【Tall】&#xff0c;建议调整为该布局&#xff0c;如下。 创建项目 首先创建一个项目&#xff0c;过程略&#xff0c;名字请勿…...

Rust:如何动态调用字符串定义的 Rhai 函数?

在 Rust 中使用 Rhai 脚本引擎时&#xff0c;你可以动态地调用传入的字符串表示的 Rhai 函数。Rhai 是一个嵌入式脚本语言&#xff0c;专为嵌入到 Rust 应用中而设计。以下是一个基本示例&#xff0c;展示了如何在 Rust 中调用用字符串传入的 Rhai 函数。 首先&#xff0c;确保…...

A星算法两元障碍物矩阵转化为rrt算法四元障碍物矩阵

对于a星算法obstacle所表示的障碍物障碍物信息&#xff0c;每行表示一个障碍物的坐标&#xff0c;例如2 , 3; % 第一个障碍物在第二行第三列&#xff0c;也就是边长为1的正方形障碍物右上角横坐标是2&#xff0c;纵坐标为3&#xff0c;障碍物的宽度和高度始终为1.在rrt路径规划…...

【C++】设计模式详解:单例模式

文章目录 Ⅰ. 设计一个类&#xff0c;不允许被拷贝Ⅱ. 请设计一个类&#xff0c;只能在堆上创建对象Ⅲ. 请设计一个类&#xff0c;只能在栈上创建对象Ⅳ. 请设计一个类&#xff0c;不能被继承Ⅴ. 请设计一个类&#xff0c;只能创建一个对象&#xff08;单例模式&#xff09;&am…...

单细胞分析基础-第一节 数据质控、降维聚类

scRNA_pipeline\1.Seurat 生物技能树 可进官网查询 添加链接描述 分析流程 准备:R包安装 options("repos"="https://mirrors.ustc.edu.cn/CRAN/") if(!require("BiocManager")) install.packages("BiocManager",update = F,ask =…...

多项日常使用测试,带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude

多项日常使用测试&#xff0c;带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude 注&#xff1a;因为考虑到绝大部分人的使用&#xff0c;我这里所用的模型均为免费模型。官方可访问的。ChatGPT这里用的是4o Ai对话&#xff0c;编程一直以来都是人们所讨论的话题。Ai的出现…...

每日一题-判断是否是平衡二叉树

判断是否是平衡二叉树 题目描述数据范围题解解题思路递归算法代码实现代码解析时间和空间复杂度分析示例示例 1示例 2 总结 ) 题目描述 输入一棵节点数为 n 的二叉树&#xff0c;判断该二叉树是否是平衡二叉树。平衡二叉树定义为&#xff1a; 它是一棵空树。或者它的左右子树…...

FLTK - FLTK1.4.1 - 搭建模板,将FLTK自带的实现搬过来做实验

文章目录 FLTK - FLTK1.4.1 - 搭建模板&#xff0c;将FLTK自带的实现搬过来做实验概述笔记my_fltk_test.cppfltk_test.hfltk_test.cxx用adjuster工程试了一下&#xff0c;好使。END FLTK - FLTK1.4.1 - 搭建模板&#xff0c;将FLTK自带的实现搬过来做实验 概述 用fluid搭建UI…...

《多阶段渐进式图像修复》学习笔记

paper&#xff1a;2102.02808 GitHub&#xff1a;swz30/MPRNet: [CVPR 2021] Multi-Stage Progressive Image Restoration. SOTA results for Image deblurring, deraining, and denoising. 目录 摘要 1、介绍 2、相关工作 2.1 单阶段方法 2.2 多阶段方法 2.3 注意力机…...

AWScurl笔记

摘要 AWScurl是一款专为与AWS服务交互设计的命令行工具&#xff0c;它模拟了curl的功能并添加了AWS签名版本4的支持。这一特性使得用户能够安全有效地执行带有AWS签名的请求&#xff0c;极大地提升了与AWS服务交互时的安全性和有效性。 GitHub - okigan/awscurl: curl-like acc…...

QT使用eigen

QT使用eigen 1. 下载eigen https://eigen.tuxfamily.org/index.php?titleMain_Page#Download 下载后解压 2. QT引入eigen eigen源码好像只有头文件&#xff0c;因此只需要引入头文件就好了 qt新建项目后。修改pro文件. INCLUDEPATH E:\222078\qt\eigen-3.4.0\eigen-3.…...

揭示Baklib企业内容管理系统CMS的核心功能与应用价值

内容概要 企业内容管理系统&#xff08;CMS&#xff09;是指通过一系列工具和技术&#xff0c;帮助企业高效地创建、存储、管理和分发数字内容的系统。这些系统在现代企业运作中发挥着至关重要的作用&#xff0c;尤其是在信息量大、业务流程复杂的环境中。Baklib作为一个突出的…...

如何跨互联网adb连接到远程手机-蓝牙电话集中维护

如何跨互联网adb连接到远程手机-蓝牙电话集中维护 --ADB连接专题 一、前言 随便找一个手机&#xff0c;安装一个App并简单设置一下&#xff0c;就可以跨互联网的ADB连接到这个手机&#xff0c;从而远程操控这个手机做各种操作。你敢相信吗&#xff1f;而这正是本篇想要描述的…...

flume和kafka整合 flume和kafka为什么一起用?

‌Flume和Kafka一起使用的主要原因是为了实现高效、可靠的数据采集和实时处理。‌‌12 实时流式日志处理的需求 Flume和Kafka结合使用的主要目的是为了完成实时流式的日志处理。Flume负责数据的采集和传输,而Kafka则作为消息缓存队列,能够有效地缓冲数据,防止数据堆积或丢…...

java.util.Random类(详细案例拆解)(已完结)

前言&#xff1a; 小编打算近期更俩三期类的专栏&#xff0c;一些常用的专集类&#xff0c;给大家分好类别总结和详细的代码举例解释。 今天是除夕&#xff0c;小编先祝贺大家除夕快乐啦&#xff01;&#xff01; 今天是第六个 java.lang.Math 包中的 java.util.Random类 我…...

Java后端之AOP

AOP&#xff1a;面向切面编程&#xff0c;本质是面向特定方法编程 引入依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>示例&#xff1a;记录…...

【信息系统项目管理师-选择真题】2008上半年综合知识答案和详解

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7~8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16~20题】【第21题】【第22题】【第23题】【第24题】【第25题…...

go到底是什么意思:对go的猜测或断言

go这个单词&#xff0c;简单地讲&#xff0c;表示“走或去”的意思&#xff1a; go v.去&#xff1b;走 认真想想&#xff0c;go是一个非常神秘的单词&#xff0c;g-和o-这两个字母&#xff0c;为什么就会表达“去&#xff1b;走”的意思呢&#xff1f;它的字面义或本质&…...

消费增值生态:从规则设计到商业价值实现

还在为用户复购低、留存弱、平台难长效而困扰&#xff1f;当多数商家还困在传统经营思路里止步不前&#xff0c;一套依托真实消费、贴合政策导向的增值生态已然崛起。它以合规为底、以价值为核、以闭环为骨架&#xff0c;正在重新定义平台与商家的增长逻辑&#xff0c;成为数字…...

AI赋能.NET开发:让快马平台智能生成Redis缓存与消息队列集成代码

最近在做一个电商系统的订单模块&#xff0c;发现缓存和消息队列这两个组件几乎是标配。但每次从零开始集成Redis和RabbitMQ都要查半天文档&#xff0c;配置各种连接字符串&#xff0c;写一堆样板代码。直到尝试用InsCode(快马)平台的AI辅助功能&#xff0c;才发现原来这些重复…...

[语音转文字工具] AsrTools:让音频转写效率提升300%的开源解决方案

[语音转文字工具] AsrTools&#xff1a;让音频转写效率提升300%的开源解决方案 【免费下载链接】AsrTools ✨ AsrTools: Smart Voice-to-Text Tool | Efficient Batch Processing | User-Friendly Interface | No GPU Required | Supports SRT/TXT Output | Turn your audio in…...

SerialLCD库深度解析:SerLCD v2.5串口LCD驱动实践

1. SerialLCD 库技术解析&#xff1a;面向嵌入式系统的 SparkFun SerLCD v2.5 串口 LCD 驱动深度实践 1.1 背景与工程定位 SerialLCD 是一个专为 SparkFun SerLCD v2.5 硬件模块设计的轻量级串口 LCD 控制库&#xff0c;其原始实现源自 Arduino.cc Playground 社区维护的 Ser…...

VS Code 通义灵码:从安装到实战编码的全方位指南

1. 通义灵码&#xff1a;你的AI编程助手 第一次听说通义灵码时&#xff0c;我正在为一个Python项目焦头烂额。那是一个需要处理大量数据清洗的脚本&#xff0c;我写了半天还是觉得效率太低。同事随口说了句"试试通义灵码吧"&#xff0c;没想到这个决定让我少加了三天…...

Linux 内核中的内存映射:从虚拟地址到物理地址

Linux 内核中的内存映射&#xff1a;从虚拟地址到物理地址 引言 作为一名深耕操作系统和嵌入式开发的工程师&#xff0c;我深知地址管理的重要性。在系统开发中&#xff0c;合理的地址管理可以提高系统的效率和安全性。在 Linux 内核中&#xff0c;内存映射是实现虚拟地址到物理…...

小米测试开发面试全解析:从理论到实战

1. 小米测试开发面试全流程解析 第一次参加小米测试开发面试的朋友可能会有点懵&#xff0c;不知道从哪开始准备。作为一个经历过完整面试流程的"过来人"&#xff0c;我来分享一下我的真实经历。小米的测试开发面试一般分为2-3轮&#xff0c;每轮侧重点不同&#xff…...

网盘下载加速工具LinkSwift:八大主流网盘直链下载解决方案

网盘下载加速工具LinkSwift&#xff1a;八大主流网盘直链下载解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / …...

基于CasRel的微信小程序开发:智能合同关键信息抽取工具

基于CasRel的微信小程序开发&#xff1a;智能合同关键信息抽取工具 1. 引言 你有没有过这样的经历&#xff1f;面对一份几十页的合同&#xff0c;需要手动找出甲方、乙方、合同金额、签约日期、违约责任条款……一页页翻&#xff0c;一行行看&#xff0c;不仅耗时费力&#x…...

新手入门:用快马生成第一个交易平台风格的前端页面

今天想和大家分享一个特别适合前端新手的练手项目——用InsCode(快马)平台快速搭建一个简易的交易平台前端页面。作为一个刚接触金融科技开发的小白&#xff0c;我发现这种模拟真实业务场景的项目特别能激发学习兴趣。 项目目标拆解 这个模拟交易账户页面需要实现几个核心功能模…...