首页
苏兮影视
随笔记
壁纸
更多
直播
时光轴
友联
关于
统计
Search
1
v2ray节点搭建
849 阅读
2
软件添加id功能按钮
815 阅读
3
QQ扫码无法登录的解决方案
617 阅读
4
typecho非常有特色的模块
607 阅读
5
QQxml消息卡片生成源码
567 阅读
谈天说地
建站源码
经验教程
资源分享
动漫美图
登录
Search
标签搜索
java
rust
flutter
esp32c3
springboot
安卓
linux
vue
docker
joe
快捷键
git
fish shell
maven
redis
netty
dart
groovy
js
设计模式
尽意
累计撰写
109
篇文章
累计收到
39
条评论
首页
栏目
谈天说地
建站源码
经验教程
资源分享
动漫美图
页面
苏兮影视
随笔记
壁纸
直播
时光轴
友联
关于
统计
搜索到
93
篇与
的结果
v2ray节点搭建
快速开始:https://233boy.com/v2ray/v2ray-script/详细说明:https://bulianglin.com/archives/guide.html
2024年11月06日
849 阅读
0 评论
2 点赞
2024-11-06
esp32c3自动配网
在 esp32-c3 rust使用docker编译 新建项目的基础上,引入必要的依赖Cargo.toml[dependencies] log = { version = "0.4", default-features = false } esp-idf-svc = { version = "0.49", default-features = false } # 添加http的依赖 anyhow = "=1.0.86" embedded-svc = "=0.28.0" # json处理 serde = { version = "1.0", features = ["derive"] } # 序列化,支持多种,xml,json等 serde_json = "1.0" # 专门处理json格式 新建一个跟main.rs同级的配网文件,auto_set_wifi.rs然后在main.rs文件中引用mod auto_set_wifi;编写自动配网rust代码 // 引入配网页面的html文件 static INDEX_HTML: &str = include_str!("../index.html"); // 设置nvs存储的参数 static WIFI_INFO_KEY: &str = "WIFI_INFO"; static NAME_SPACE: &str = "ESP_WIFI"; // 默认ap模式下的配置信息 static AP_WIFO_INFO: WifiInfo<'static> = WifiInfo { ssid: "esp32_c3_wifi", password: "00000000", }; #[derive(Debug, Deserialize, Serialize)] struct WifiInfo<'a> { ssid: &'a str, password: &'a str, } pub fn start_auto_wifi() -> anyhow::Result<()> { // 自动配网,需要先开启ap模式,让手机连上esp32的热点 let peripherals = Peripherals::take()?; let sysloop = EspEventLoop::take()?; let nvs = EspDefaultNvsPartition::take()?; let mut wifi = BlockingWifi::wrap( EspWifi::new(peripherals.modem, sysloop.clone(), Some(nvs.clone()))?, sysloop.clone(), )?; wifi.set_configuration(&esp_idf_svc::wifi::Configuration::AccessPoint( AccessPointConfiguration { ssid: AP_WIFO_INFO.ssid.try_into().unwrap(), password: AP_WIFO_INFO.password.try_into().unwrap(), auth_method: esp_idf_svc::wifi::AuthMethod::WPA2Personal, ..Default::default() }, ))?; // 由于wifi,跟nvs在后面的函数也需要被调用,所有权不能丢弃,需要用安全的智能指针进行接管 let wifi = Arc::new(Mutex::new(wifi)); let nvs = Arc::new(Mutex::new(EspNvs::new(nvs, NAME_SPACE, true)?)); let temp_wifi = wifi.clone(); let temp_nvs = nvs.clone(); let mut buf = [0;128]; log::warn!("正在查找是否存在配网信息..."); if let Err(_) = nvs.lock().unwrap().get_raw(WIFI_INFO_KEY, &mut buf) { log::info!("不存在配网信息,开启ap模式"); let mut temp_wifi = temp_wifi.lock().unwrap(); temp_wifi.start()?; log::info!("开启wifi"); temp_wifi.wait_netif_up()?; log::info!("等待底层网络分配"); log::info!("WiFi信息为:{:?}", temp_wifi.wifi().ap_netif().get_ip_info()); } else { log::info!("存在配网信息,开启混合模式"); let _ = std::thread::spawn(|| start_muxt_mode(temp_wifi, temp_nvs)); } // 配网页面路由 let temp_nvs = nvs.clone(); let mut server = EspHttpServer::new(&ServerConfig::default())?; server.fn_handler("/", esp_idf_svc::http::Method::Get, |request| { request .into_ok_response() .unwrap() .write_all(INDEX_HTML.as_bytes()) })?; // 提交配网的表单信息 server.fn_handler( "/wifi", esp_idf_svc::http::Method::Post, move |mut request| { let len = request.content_len().unwrap() as usize; let mut buf = vec![0; len]; request.read_exact(&mut buf).unwrap(); let temp_nvs = temp_nvs.clone(); let mut response = request.into_ok_response().unwrap(); let raw = temp_nvs.lock().unwrap().set_raw(WIFI_INFO_KEY, &buf); if let true = raw.unwrap_or(false) { response.write_all(b"{\"msg\":\"success\"}").unwrap(); } else { response.write_all(b"{\"msg\":\"faiture\"}").unwrap(); } response.flush().unwrap(); Ok(()) }, )?; // 查看nvs里保存的配网信息 let temp_nvs = nvs.clone(); server.fn_handler("/nvs", esp_idf_svc::http::Method::Get, move |request| { let temp_nvs = temp_nvs.clone(); let mut buf = [0; 128]; let mut response = request.into_ok_response().unwrap(); if let Option::None = temp_nvs .lock() .unwrap() .get_raw(WIFI_INFO_KEY, &mut buf) .unwrap_or(Option::None) { response.write_all(b"{\"msg\":\"faiure\"}").unwrap(); } else { let end = buf.iter().position(|&x| x == 0).unwrap_or(buf.len()); let res = String::from_utf8_lossy(&buf[..end]); let wifi_info = serde_json::from_slice::<WifiInfo>(&buf[..end]).unwrap(); log::error!("WiFi信息为:{:?}", wifi_info); response.write_all(res.as_bytes()).unwrap(); } response.flush() })?; // 开启混合模式路由 let temp_wifi = wifi.clone(); let temp_nvs = nvs.clone(); server.fn_handler("/muxt", esp_idf_svc::http::Method::Get, move |request| { request.into_ok_response().unwrap().write(b"okk").unwrap(); let (temp_wifi, temp_nvs) = (temp_wifi.clone(), temp_nvs.clone()); let _ = std::thread::spawn(|| start_muxt_mode(temp_wifi, temp_nvs)); Ok(()) })?; // 删除nvs的配置信息 let temp_nvs = nvs.clone(); server.fn_handler("/del", esp_idf_svc::http::Method::Get, move |request| { let mut response = request.into_ok_response().unwrap(); let mut temp_nvs = temp_nvs.lock().unwrap(); if let Err(e) = temp_nvs.remove(WIFI_INFO_KEY) { response.write_all(format!("delete faiure,{e}").as_bytes()) }else{ response.write_all(b"delete success") } })?; forget(server); forget(wifi); Ok(()) } pub fn start_muxt_mode( wifi: Arc<Mutex<BlockingWifi<EspWifi>>>, nvs: Arc<Mutex<EspNvs<NvsDefault>>> )-> anyhow::Result<()> { // 启动混合模式 log::info!("延迟500毫秒执行"); FreeRtos::delay_ms(500); log::info!("开始配置"); let mut wifi = wifi.lock().unwrap(); let nvs = nvs.lock().unwrap(); // 重试连接的次数 let mut retry = 5; loop { if retry < 0 { log::error!("尝试剩余{retry}次后,连接失败"); break; } if wifi.is_started()? { if let Err(_) = wifi.stop() { log::error!("断开wifi连接失败,剩余{}次重试",retry); retry-=1; continue; } log::info!("断开wifi"); } let mut buf = [0; 128]; if let Option::None = nvs.get_raw(WIFI_INFO_KEY, &mut buf).unwrap_or(Option::None) { log::error!("获取WiFi信息失败,剩余{}次重试",retry); } let end = buf.iter().position(|&x| x == 0).unwrap_or(buf.len()); let wifi_info = serde_json::from_slice::<WifiInfo>(&buf[..end]).unwrap(); log::warn!("WiFi信息为:{:?}", wifi_info); let client_config = ClientConfiguration { ssid: wifi_info.ssid.try_into().unwrap(), password: wifi_info.password.try_into().unwrap(), ..Default::default() }; let ap_config = AccessPointConfiguration { ssid: AP_WIFO_INFO.ssid.try_into().unwrap(), password: AP_WIFO_INFO.password.try_into().unwrap(), auth_method: esp_idf_svc::wifi::AuthMethod::WPA2Personal, ..Default::default() }; wifi.set_configuration(&esp_idf_svc::wifi::Configuration::Mixed( client_config, ap_config, ))?; log::info!("启动wifi"); wifi.start()?; log::info!("等待网络连接"); if let Err(e) = wifi.connect() { log::error!("连接失败:{e},剩余{}次连接尝试", retry); retry -= 1; continue; } log::info!("等待底层网络驱动处理"); if let Err(e) = wifi.wait_netif_up() { log::error!("等待底层网络驱动处理失败,{e},剩余{}次重试",retry); } break; } log::info!("Ap模式信息为:{:?}", wifi.wifi().ap_netif().get_ip_info()); log::info!("Ip信息为:{:?}", wifi.wifi().sta_netif().get_ip_info()); Ok(()) } 在main.rs中调用fn main() { // It is necessary to call this function once. Otherwise some patches to the runtime // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 esp_idf_svc::sys::link_patches(); // Bind the log crate to the ESP Logging facilities esp_idf_svc::log::EspLogger::initialize_default(); start_auto_wifi().unwrap(); }配网的html页面代码<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>esp32配网页面</title> <style> body { font-family: Arial, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #f4f4f9; } .login-container { width: 300px; padding: 20px; background-color: #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); border-radius: 8px; } .login-container h2 { text-align: center; margin-bottom: 20px; color: #333; } .login-container input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } .login-container button { width: 100%; padding: 10px; background-color: #4CAF50; border: none; color: #fff; border-radius: 4px; cursor: pointer; font-size: 16px; } .login-container button:hover { background-color: #45a049; } </style> </head> <body> <div class="login-container"> <h2>配网页面</h2> <form id="loginForm"> <input type="text" id="username" placeholder="ssid" required> <input type="password" id="password" placeholder="密码" required> <button type="button" onclick="submitForm()">提交</button> </form> </div> <script> function submitForm() { const ssid = document.getElementById('username').value; const password = document.getElementById('password').value; fetch(window.location.origin + '/wifi', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ssid, password }) }) .then(response => response.json()) .then(data => { // 在此处理响应数据 alert(data.msg); if (data.msg === "success"){ fetch(window.location.origin + '/muxt'); } console.log('成功:', data); }) .catch(error => { console.error('错误:', error); }); } </script> </body> </html>
2024年11月06日
150 阅读
0 评论
3 点赞
配置和使用 CDN 加速网站
在现代网站建设中,为了提高访问速度和用户体验,使用内容分发网络(CDN)成为了一个普遍的选择。本文将带你了解 CDN 配置的基本流程,帮助你为网站实现高效的加速和稳定性。一、什么是 CDN?CDN,全称为内容分发网络(Content Delivery Network),是一种通过将网站内容分发到全球不同的节点来加速用户访问的技术。通过 CDN,当用户请求访问时,系统会将请求路由到离用户最近的服务器节点,减少响应时间并提高加载速度。二、CDN 配置的基本步骤以下是如何将 CDN 集成到你的网站的详细步骤:1. 注册并登录 CDN 平台首先,选择一个适合的 CDN 服务提供商,例如 腾讯云、阿里云、或本地云服务商。注册并登录 CDN 服务控制台。2. 添加加速域名在 CDN 管理平台上,添加你想加速的域名,例如 pan.example.com。CDN 平台会为你生成一个唯一的 CNAME 地址,例如 cdn.exampleprovider.com,这是用于 DNS 解析的。3. 配置源站源站域名:设置为网站服务器的实际域名或 IP 地址,如 pan.example.com 或服务器的公共 IP。回源 Host:通常设置为源站域名 pan.example.com。这确保了回源请求中的 Host 头与原始请求一致。如果有特殊需求,可根据情况调整。4. DNS 解析配置在你的域名服务商的 DNS 控制台中,将 pan.example.com 的 DNS 记录配置为 CNAME,并指向 CDN 提供的 CNAME 地址 cdn.exampleprovider.com。保存配置并等待 DNS 解析生效,这个过程可能需要几分钟到几小时。5. 调整回源设置回源方式:选择通过域名或 IP 进行回源。如果使用 IP,可以避免循环解析问题,但需要保证 IP 的稳定性。缓存策略:根据你的网站内容类型来设置缓存时间,例如静态资源可以长时间缓存,而动态内容应设置较短的缓存时间或不缓存。回源协议:设置为 HTTP 或 HTTPS,根据你网站的安全需求选择合适的协议。6. 检查配置和测试完成配置后,通过浏览器或网络工具访问 pan.example.com,确认访问流量已经通过 CDN 节点加速。同时,可以在 CDN 平台查看访问日志和缓存命中率,并根据需要优化缓存策略。三、常见问题及解决方案1. 加速域名与源站域名相同在某些情况下,你可能想将加速域名(如 pan.example.com)与源站域名设置为相同。这是可行的,但需注意以下几点:DNS 配置:确保加速域名正确解析为 CDN 提供的 CNAME 地址。回源避免循环:CDN 配置时,可以选择使用源站 IP 来避免请求回源至 CDN 本身。2. 回源 Host 的选择回源 Host 设置为源站域名(如 pan.example.com)即可。如果源站有特殊的 Host 验证需求,确保该 Host 设置能够被服务器接受和处理。3. 配置未生效或请求循环检查 DNS 解析是否正确指向 CDN 的 CNAME 地址。确认 CDN 配置中的源站地址无误,确保它不会导致回源请求指向 CDN 节点。四、优化 CDN 的使用分层缓存:根据网站的访问模式和流量来源设置多级缓存策略,以实现更高的缓存命中率。带宽和流量监控:定期检查 CDN 提供商的控制台,查看带宽使用和流量统计,避免超出预算。安全功能:使用 CDN 提供的额外安全功能,如 DDoS 防护和 Web 应用防火墙(WAF),来保护网站免受攻击。
2024年11月06日
126 阅读
0 评论
3 点赞
Rust智能指针与多线程同步
一、引言在Rust中,智能指针不仅简化了复杂的内存管理,还在并发编程中扮演了重要角色。本文将介绍Rust中的主要智能指针,包括Box<T>、Rc<T>、RefCell<T>、Arc<T>和Mutex<T>,并详细探讨它们的应用场景、线程安全性和代码实例。二、Box<T>:在堆上分配数据Box<T>用于在堆上分配数据,以适应递归类型或栈空间不足的情况。fn main() { let b = Box::new(5); println!("b = {}", b); }应用场景递归类型:Rust的编译器需要在编译期知道数据的大小,Box<T>可以存放递归结构的节点。减少栈空间占用:对于较大结构体,通过Box<T>放到堆中存储,可以减少栈内存占用,提高性能。三、Rc<T>:多所有者不可变数据共享Rc<T>(引用计数)允许多个所有者共享数据,但仅适用于单线程不可变数据。use std::rc::Rc; fn main() { let rc1 = Rc::new(5); let rc2 = Rc::clone(&rc1); println!("引用计数为: {}", Rc::strong_count(&rc1)); }应用场景不可变数据共享:多部分需共享同一数据时(如UI元素等),避免所有权转移。图结构或链表:如在多节点中共享相同引用,可用Rc<T>避免重复所有权管理。四、RefCell<T>:内部可变性RefCell<T>通过在运行时检查借用规则,允许在不可变引用的上下文中进行可变操作,但仅限单线程。use std::cell::RefCell; fn main() { let data = RefCell::new(5); *data.borrow_mut() += 1; println!("data = {}", data.borrow()); }应用场景不可变结构中的可变数据:在struct内定义不可变字段,但希望在方法中对其修改。单线程数据修改:适用于需要运行时借用检查的可变引用操作。五、Arc<T>:多所有者多线程共享Arc<T>是Rc<T>的线程安全版本,它通过原子操作来实现多线程共享的数据计数。Arc适合并发场景,但由于只支持不可变引用,通常和Mutex<T>搭配使用。use std::sync::Arc; use std::thread; fn main() { let arc_data = Arc::new(5); let arc_data_clone = Arc::clone(&arc_data); let handle = thread::spawn(move || { println!("arc_data in thread: {}", arc_data_clone); }); handle.join().unwrap(); println!("引用计数为: {}", Arc::strong_count(&arc_data)); }应用场景跨线程共享不可变数据:在多线程中共享相同数据。无锁队列或数据结构:适用于只读或有较少写操作的多线程场景。六、Mutex<T>:线程间的可变数据共享Mutex<T>提供了锁机制来保护数据的可变访问权。每次访问数据时,需要先锁住数据,确保不会被其他线程修改。use std::sync::{Arc, Mutex}; use std::thread; fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("计数结果: {}", *counter.lock().unwrap()); }应用场景线程间的可变共享数据:在多线程中共享可变数据,例如计数器、状态标记等。保护数据一致性:在操作共享数据前加锁,确保线程安全。七、智能指针的组合使用:Arc<Mutex<T>>Arc<T>和Mutex<T>通常搭配使用,Arc用于多线程共享,而Mutex用于加锁访问。use std::sync::{Arc, Mutex}; use std::thread; fn main() { let data = Arc::new(Mutex::new(0)); let handles: Vec<_> = (0..10).map(|_| { let data = Arc::clone(&data); thread::spawn(move || { let mut data = data.lock().unwrap(); *data += 1; }) }).collect(); for handle in handles { handle.join().unwrap(); } println!("计数结果为: {}", *data.lock().unwrap()); }应用场景多线程计数器:典型用法是实现线程间共享计数器,Arc确保引用,Mutex管理线程同步。并发任务管理:Arc<Mutex<T>>可以确保数据安全访问,是并发应用中的常用模式。八、总结Rust的智能指针使得内存管理既安全又高效,在多线程场景下,Arc和Mutex的组合更能保障数据安全。通过理解和掌握这些智能指针的使用场景和组合方式,Rust开发者可以写出更安全和高效的并发代码。
2024年10月26日
154 阅读
0 评论
2 点赞
2024-10-23
esp32-c3 rust使用docker编译
使用的环境:wsl2(alpine),docker参考官方文档:https://narukara.github.io/std-training-zh-cn/02_2_software.html1.使用docker pull拉取官方提供的docker imagedocker pull espressif/rust-std-training2.使用命令docker images查看image状态,拉取成功的输出:REPOSITORY TAG IMAGE ID CREATED SIZE espressif/rust-std-training latest 660e68996c1b 3 months ago 3.99GB3.启动容器:docker run --mount type=bind,source="$(pwd)",target=/workspace,consistency=cached -it rust-std-training /bin/bash 这行命令表示在当前文件夹作为映射目录,映射到docker容器的/workspace目录,并进入到容器内部终端4.执行命令构建项目,从官方提供的github模板仓库构建cargo generate --git https://github.com/esp-rs/esp-idf-template cargo这里创建项目可能会提示错误:Error: could not determine the current user, please set $USER解决方法export USER=root5.项目创建完成之后,直接编译 cargo build --release第一次编译可能时间会有点久,将近三分钟了编译完成之后回到wsl2的终端,或者使用powershellcd到映射的宿主机目录可执行文件在target/riscv32imc-esp-espidf/release/demo6.执行flash烧录命令espflash.exe flash ./demo --monitor烧录成功,打印了hello world。
2024年10月23日
174 阅读
1 评论
3 点赞
1
...
5
6
7
...
19