首页
苏兮影视
随笔记
壁纸
更多
直播
时光轴
友联
关于
统计
Search
1
软件添加id功能按钮
708 阅读
2
v2ray节点搭建
508 阅读
3
typecho非常有特色的模块
460 阅读
4
QQxml消息卡片生成源码
421 阅读
5
Linux下提权常用小命令
366 阅读
谈天说地
建站源码
经验教程
资源分享
动漫美图
登录
Search
标签搜索
java
flutter
springboot
rust
安卓
linux
vue
docker
joe
快捷键
git
fish shell
maven
redis
netty
dart
groovy
js
设计模式
rpc
尽意
累计撰写
95
篇文章
累计收到
38
条评论
首页
栏目
谈天说地
建站源码
经验教程
资源分享
动漫美图
页面
苏兮影视
随笔记
壁纸
直播
时光轴
友联
关于
统计
搜索到
30
篇与
的结果
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日
32 阅读
0 评论
2 点赞
java浅拷贝深拷贝
在Java中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两个常见的对象拷贝方式。它们的主要区别在于它们处理对象中的引用类型字段的方式。1. 浅拷贝(Shallow Copy)浅拷贝仅拷贝对象本身以及对象中所有的基本数据类型字段,对于引用类型字段(如对象、数组等),仅复制其引用(即指针),而不复制实际的对象。这意味着原对象和拷贝对象中的引用类型字段指向同一个内存地址,因此改变一个对象中的引用类型字段可能会影响到另一个对象。实现方式:实现Cloneable接口并重写clone()方法。代码示例:class Address { String city; public Address(String city) { this.city = city; } } class Person implements Cloneable { String name; Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // 浅拷贝 } } public class ShallowCopyExample { public static void main(String[] args) throws CloneNotSupportedException { Address address = new Address("New York"); Person person1 = new Person("John", address); Person person2 (Person) person1.clone(); System.out.println(person1.address.city); // New York System.out.println(person2.address.city); // New York person2.address.city = "San Francisco"; System.out.println(person1.address.city); // San Francisco System.out.println(person2.address.city); // San Francisco } }应用场景:浅拷贝适用于对象结构简单且不包含复杂的嵌套对象的情况。因为浅拷贝的速度较快,适合对性能有较高要求但不涉及深层嵌套结构的场景。2. 深拷贝(Deep Copy)深拷贝不仅拷贝对象本身,还会递归地拷贝对象中所有引用类型字段所指向的对象。这意味着原对象和拷贝对象中的引用类型字段互不影响,修改一个对象中的引用类型字段不会影响到另一个对象。实现方式:重写clone()方法,手动拷贝所有的引用类型字段。使用序列化和反序列化实现深拷贝。代码示例:class Address implements Cloneable { String city; public Address(String city) { this.city = city; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { String name; Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { Person clonedPerson = (Person) super.clone(); clonedPerson.address = (Address) address.clone(); // 深拷贝 return clonedPerson; } } public class DeepCopyExample { public static void main(String[] args) throws CloneNotSupportedException { Address address = new Address("New York"); Person person1 = new Person("John", address); Person person2 = (Person) person1.clone(); System.out.println(person1.address.city); // New York System.out.println(person2.address.city); // New York person2.address.city = "San Francisco"; System.out.println(person1.address.city); // New York System.out.println(person2.address.city); // San Francisco } }应用场景:深拷贝适用于对象结构复杂且包含多个嵌套引用类型字段的场景,尤其是在这些引用类型字段是可变对象时。深拷贝确保拷贝后的对象与原对象完全独立,不会互相影响。总结浅拷贝:仅复制对象及其基本数据类型字段,引用类型字段只复制引用。适用于简单的对象结构。深拷贝:复制对象及其所有引用类型字段所指向的对象。适用于复杂对象结构,确保深层次的独立性。根据具体需求选择合适的拷贝方式可以有效地避免不必要的副作用并提高程序的性能。
2024年08月25日
32 阅读
0 评论
1 点赞
groovy调用node执行js
目前好像没有更好的方案去实现在node环境下执行js,这种方案需要配合js代码,目标js只能为这个groovy服务groovy代码// Groovy script to execute Node.js script static def runJsScript(String scriptPath, String argument) { // Create a command def command = ["node", scriptPath, argument] // Create a ProcessBuilder with the command def processBuilder = new ProcessBuilder(command) // Start the process def process = processBuilder.start() // Capture the output of the process def output = new StringWriter() def error = new StringWriter() process.consumeProcessOutput(output, error) // Wait for the process to complete process.waitFor() // Return the output and error streams return [output.toString().trim(), error.toString().trim()] } // Path to the JavaScript file def scriptPath = "./a.js" // Argument to pass to the JavaScript function def argument = "World" // Call the JavaScript function def (output, error) = runJsScript(scriptPath, argument) if (error) { println "Error: $error" } else { println "Output: $output" } js代码function greet(name) { return `Hello, ${name}!`; } console.log(greet(process.argv[2]));需要传参多少个参数,需要在js块拼接 process.argv[2] process.argv[3]执行多个参数groovystatic def runJsScript(String scriptPath, String... arguments) { def command = ["node", scriptPath] arguments.each {command.add(it)} def processBuilder = new ProcessBuilder(command) def process = processBuilder.start() def output = new StringWriter() def error = new StringWriter() process.consumeProcessOutput(output, error) process.waitFor() return [output.toString().trim(), error.toString().trim()] }jsfunction greet(name,value) { return `Hello, ${name}: ${value}`; } console.log(greet(process.argv[2],process.argv[3]));{dotted startColor="#ff6c6c" endColor="#1989fa"/}其实还是有个小坑 传参json会被解析成js对象,就导致js拿到的数据已经是处理过的了,后面的流程是会受影响的。 解决方案:可以在添加额外参数时进行检验,判断当前字符串是否可以被转换为json对象,如果可以就做转义处理,str.replace('"','\"') 可以封装成一个工具类使用 class Execute { static def js(String scriptPath, String... arguments) { def command = ["node", scriptPath] // 如果是json格式,就进行转义,防止传参过程中被解析 arguments.each { if (isValidJson(it)) { command.add(it.replace('"','\\""')) }else command.add(it) } def processBuilder = new ProcessBuilder(command) def process = processBuilder.start() def output = new StringWriter() def error = new StringWriter() process.consumeProcessOutput(output, error) process.waitFor() if (error!=null && (error as String) != ""){ throw new Exception("js脚本出错:+$error") } return output.toString().trim() } // 判断字符串是不是json格式 static private boolean isValidJson(String str) { def s = new JsonSlurper() try { s.parseText(str) return true } catch (Exception e) { return false } } }
2024年08月12日
51 阅读
0 评论
4 点赞
2024-08-11
js逆向xhs
首先需要先确定目标接口打开开发者工具选择网络网络请求比较多,不太好定位,先Ctrl+L清空一下网络日志随便点击一个标签,从上往下看可以看到 hoomfeed 的响应是有我们要的数据可以多刷新几次,看一下请求头里面的参数哪些是固定的然后右键复制,以curl bash格式到这个网站生成一下请求代码测试一下能不能跑通https://curlconverter.com/我使用的okhttp不过有一点需要注意,请求体的json字符串不能带有空格,还是要注意一下,一般还是要看下负载源代码给格式,保持一致就没问题了 OkHttpClient client = new OkHttpClient(); String jsonBody = "{\"cursor_score\":\"\",\"num\":18,\"refresh_type\":1,\"note_index\":32,\"unread_begin_note_id\":\"\",\"unread_end_note_id\":\"\",\"unread_note_count\":0,\"category\":\"homefeed.fashion_v3\",\"search_key\":\"\",\"need_num\":8,\"image_formats\":[\"jpg\",\"webp\",\"avif\"],\"need_filter_image\":false}"; // 注意这里是json格式 RequestBody requestBody = RequestBody.create(jsonBody,MediaType.parse("application/json; charset=utf-8")) Request request = new Request.Builder() .url("https://edith.xiaohongshu.com/api/sns/web/v1/homefeed") .post(requestBody) .header("authority", "edith.xiaohongshu.com") .header("accept", "application/json, text/plain, */*") .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6") .header("cache-control", "no-cache") .header("content-type", "application/json;charset=UTF-8") .header("cookie", "abRequestId=e3bdcd27-e1b5-5f53-89b5-7e2802d396e0; xsecappid=xhs-pc-web; a1=1913b4ae942vlubadspzq6n0dzv1sn1s16vme85li50000892240; webId=f51031180df1b91abeef5db1d71629e1; web_session=030037a184491809ffa8205bcf214a315d86ed; gid=yjyqD40iYWyfyjyqD40djKY24Jh17D0fMUuAh13KI8fuh628yMIyMd888YjJJ488KD82yj0y; webBuild=4.28.5; unread={%22ub%22:%2266986e9b0000000003027356%22%2C%22ue%22:%226699c440000000000d00fd0f%22%2C%22uc%22:23}; acw_tc=7c07ab06520fd63e04c63f0273004a3337c1cd30cc32b06c921ddff420388b1e; websectiga=3fff3a6f9f07284b62c0f2ebf91a3b10193175c06e4f71492b60e056edcdebb2; sec_poison_id=8ef6b86b-8ad1-4aa5-9ec4-e3309f2368b3" ) .header("origin", "https://www.xiaohongshu.com") .header("pragma", "no-cache") .header("referer", "https://www.xiaohongshu.com/") .header("sec-ch-ua", "\"Chromium\";v=\"122\", \"Not(A:Brand\";v=\"24\", \"Microsoft Edge\";v=\"122\"") .header("sec-ch-ua-mobile", "?0") .header("sec-ch-ua-platform", "\"Windows\"") .header("sec-fetch-dest", "empty") .header("sec-fetch-mode", "cors") .header("sec-fetch-site", "same-site") .header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0") .header("x-b3-traceid", "1c3f0fbf2fac047b") .header("x-s", "XYW_eyJzaWduU3ZuIjoiNTMiLCJzaWduVHlwZSI6IngyIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6ImQ3ZTU0NWYyNTMzM2I2MWYxMjFlMmJmZGI4ZThhMGZkMDg2Mzg0NWY2ZTU3MzEyM2IzN2JmMjIyZDU5MGE4ZDg2NjQ3ODEyMzBkYWU5ODVjMjMzYzdiNDUxNjBkYmQ3NDdkZWY5ZDBmZDBhNWQ0YzAzMzE3OGRlNGYyYmQ3YTgyNGNkZTYxZDgzNDMxNmQ3OWQ1NTFjY2Q5YjJlYTEyZWM2YWNlMjM3ZjVjZjQzMDllZTg0OGU5NTQwZGEwY2NhN2IyZWJlNjMzODdhOGE3ZTAwNDM2Yzk2NmI5OWM4MWUzM2IxNDMyYjk0MDEyOGY3ZjcwMWU4Yjc2MTYyOTFiZDBmN2UxNDYxNWFhZjJiZDExMDBiYWRiNWM5NTFiZjc2N2M1ZWM5NDkxYWJiOTUzOGYwMzc5ZTY1YzgzOGQ1ZGVjODdkMjZlZmQzM2M5OGY0NGVlMjQzODlmNDE4YjUyNWY4ZmEyYzE0YjU4ZmZkOWZhMmYxZTcwMzhiNjQ1YTVlODhhOTBlYTRlYjRiZmM1NGJiMWIyODlkY2ExNDExYTk5In0=" ) .header("x-s-common", "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") .header("x-t", "1723275130800") .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); def res = response.body().string(); println res } 直接运行是没有问题的,然后就要看哪些参数是会影响请求的结果在请求头可以看到像 x-s x-s-common 等这一类的参数明显就是加密过的,而且一般情况也会作为必要参数,x-t很明显是个时间戳可以试一下将这几个参数注释掉运行,发现只有x-s的值不正确或者没有的情况下是拿不到请求结果的,现在也就明确了要找x-s的加密函数可以跟栈去找加密函数,找到在那两个函数或者文件内容由明文变成密文,或者直接搜索关键字勾选上正则匹配,只有7个匹配项可以一个个都看一下,不放心的话也可以都先打上断点,明显可以看到只有这里才有赋值语句,那就在这打上断点,看到调用了l(a && void 0 !== window._webmsxyw ? window._webmsxyw : encrypt_sign)(c, i) || {};三元表达式调用了window._webmsxyw函数,传参c,i在控制台调用这个函数现在加密函数已经差不多确定了进入到函数内部查看经过了大量混淆,这段代码想要扣下来还是比较麻烦的,基本上是没有一点可读性那就直接整个文件都拿下来,补环境,只要能跑通里面的window._webmsxyw就能拿到加密的值了新建一个包xhs,将复制下来的源代码粘贴到course.js文件中,为了更好的解耦,我们准备三个js文件,course存放源代码,env作为补环境的代码,xhs则写我们输入加密函数的代码跟逻辑然后在xhs文件里面引入require("./env")require("./sourse")注意一下要先引入环境,不然sourse会因为没有环境报错env使用代理看到哪些函数方法被调用了,却少什么补充什么就行了 function setProxy(proxyObjs) { for (let i = 0; i < proxyObjs.length; i++) { const handler = `{ get: function(target, property, receiver) { if (property!="Math" && property!="isNaN"){ if (target[property] && typeof target[property] !="string" && Object.keys(target[property]).length>3){ }else{ console.log("方法:", "get ", "对象:", "${proxyObjs[i]}", " 属性:", property, " 属性类型:", typeof property, ", 属性值:", target[property]);}} return target[property]; }, set: function(target, property, value, receiver) { console.log("方法:", "set ", "对象:", "${proxyObjs[i]}", " 属性:", property, " 属性类型:", typeof property, ", 属性值:", value, ", 属性值类型:", typeof target[property]); return Reflect.set(...arguments); } }`; eval(`try { ${proxyObjs[i]}; ${proxyObjs[i]} = new Proxy(${proxyObjs[i]}, ${handler}); } catch (e) { ${proxyObjs[i]} = {}; ${proxyObjs[i]} = new Proxy(${proxyObjs[i]}, ${handler}); }`); } } setProxy(['window', 'document', ' navigator', 'screen', 'localStorage', 'location']) 补环境的代码env.js// 补环境 window window = global delete global delete Buffer // document document = { createElement: function(x){ if (x === "canvas"){ return { getContext: function(){} } } }, documentElement:{}, cookie:'abRequestId=e3bdcd27-e1b5-5f53-89b5-7e2802d396e0; xsecappid=xhs-pc-web; webId=f51031180df1b91abeef5db1d71629e1; web_session=030037a184491809ffa8205bcf214a315d86ed; gid=yjyqD40iYWyfyjyqD40djKY24Jh17D0fMUuAh13KI8fuh628yMIyMd888YjJJ488KD82yj0y; webBuild=4.28.5; unread={%22ub%22:%2266986e9b0000000003027356%22%2C%22ue%22:%226699c440000000000d00fd0f%22%2C%22uc%22:23}; acw_tc=7c07ab06520fd63e04c63f0273004a3337c1cd30cc32b06c921ddff420388b1e; websectiga= sec_poison_id=8ef6b86b-8ad1-4aa5-9ec4-e3309f2368b3' } // localStorage localStorage = { getItem: function (){ // return '{"signVersion":"1"}' return '{"validate":true,"commonPatch":["/fe_api/burdock/v2/note/post","/api/sns/web/v1/comment/post","/api/sns/web/v1/note/like","/api/sns/web/v1/note/collect","/api/sns/web/v1/user/follow","/api/sns/web/v1/feed","/api/sns/web/v1/login/activate","/api/sns/web/v1/note/metrics_report","/api/redcaptcha","/api/store/jpd/main","/phoenix/api/strategy/getAppStrategy"],"signUrl":"https://fe-video-qc.xhscdn.com/fe-platform/bccb34c4f2976c51b565494c0a760c42d962b25b.js","signVersion":"1","url":"https://fe-video-qc.xhscdn.com/fe-platform/a1c872577b980b890b0850cef89371b35125649a.js","reportUrl":"/api/sec/v1/shield/webprofile","desVersion":"2"}' } } // navigator navigator = { appCodeName: "Mozilla", appName: "Netscape", appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36' } xhs.jsrequire("./env") require("./sourse") const c = '/api/sns/web/v1/homefeed' const i = { "cursor_score": "", "num": 18, "refresh_type": 1, "note_index": 32, "unread_begin_note_id": "", "unread_end_note_id": "", "unread_note_count": 0, "category": "homefeed.fashion_v3", "search_key": "", "need_num": 8, "image_formats": [ "jpg", "webp", "avif" ], "need_filter_image": false } function getX(){ return window._webmsxyw(c,i) } console.log(getX()['X-s'])至此加密函数补环境就结束了{dotted startColor="#ff6c6c" endColor="#1989fa"/}不过还是有点小坑localStorage.getItem 直接返回一个空函数是会诱导生成错误的数据,我一开始就是返回的空函数,然后验证发现加密值是错的,因为使用了代理,可以看到最近的函数就是localStorage.getItem可以通过hook getItem函数拿到传参是多少localStorage.getItem_ = localStorage.getItem;localStorage.getItem = function(x){console.log(x);localStorage.getItem_(x);}再执行window._webmsxyw函数就能看到getItem传参有了参数,直接在控制台 localStorage.getItem("sdt_source_storage_key")拿到参数即可,现在就能正确拿到正确的加密值了
2024年08月11日
204 阅读
2 评论
4 点赞
2024-05-17
记录一下flutter的值传递细节
最近在实现一个类似qq相册的功能,点击右上角图片的小圆圈框选。思路也很简单,当image控件的值发送改变时,重新rebuild渲染,当然是局部渲染,所以要封装这么一个控件,构造函数: final File file; final BottomImageChanged isChanged; final VoidCallback onPress; 图片显示使用的FileImage,传递一个回调函数,用来处理区选对应的widget,由于dart的传参对于基本变量都是值传递吗,所以也就造成了父控件值改变了,但是子组件不能监听到,所以使用类包装一下基础变量值,提供get set方法。也可以使用ValueNotifier包装基础变量,List.filled 和 List.generate 都是用于创建固定长度的列表List.filled:列表中的所有元素都是相同的对象,适用于需要多个相同对象引用的情况。List.generate:每个元素都是独立的对象,适用于需要为每个列表项创建不同对象的情况,例如为每个列表项创建独立的 ValueNotifier。
2024年05月17日
30 阅读
0 评论
0 点赞
1
2
...
6