V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  kuanat  ›  全部回复第 9 页 / 共 12 页
回复总数  233
1  2  3  4  5  6  7  8  9  10 ... 12  
342 天前
回复了 shuiguomayi 创建的主题 Linux 这是对 Linux 正确的使用方法么?
分区话题比较复杂,一般性的建议是用发行版默认的文件系统和分区表。

另外 ESP 比较特殊,取决于 firmware 支持,大部分要求是 FAT32 ,在苹果电脑上要苹果的那个格式。挂载点现在推荐 /efi 或者 /boot ,特别是多系统引导环境,绝大多数情况下 /boot/efi 一样用。

发行版的 Point/Rolling Release 现在的分界线不是特别明显了,往严格里面说 Debian 这种算 Point Release ,而 Arch 这种算 Rolling ,像 Ubuntu/Fedora 介于二者之间。可能看 LTS 支持会更靠谱一些。我个人的分类是看官方维护的内核是只 backport 补丁,还是会追 mainline 版本。Rolling Release 也可以假装当 Point Release 来用,只要把官方内核版本锁了就行。

如果你希望系统层面上支持回滚,可以考虑 Fedora Silverblue 这类基于 ostree 的,或者 NixOS 这种声明式的,核心思想都是 Immutable system partition ,升级过程类似安卓设备上常见的 A/B partitions 。
344 天前
回复了 Befehishaber 创建的主题 Linux 请教下不同系统间的硬中断响应时间
这个事情优先看 jitter 容忍阈值,其次才是 latency 。如果几百毫秒延迟可以接受的话,我估计 RT-Preempt 内核是可以做到的。RH 系还有 Ubuntu 都有相应的发行版,只是都是收费的。

音频相关对实时性要求比较高,一般现场回放延迟容忍大概在 20ms 以内,如果是舞台耳返的话,大概是 5~10 毫秒左右。目前还是很难用 linux RT 做实时效果合成的。

我印象 x86 RT 大概 99% 的话可以做到 30ms 上下,这个要看具体硬件情况。
如果没有硬件级别的漏洞,一般来说 TEE Attestation 是无法伪造的。

但是能用 TEE 的场景很少,因为你要在设备出厂的之前就把私钥写入 TEE 里面,所以基本上只有手机厂商和微信(支付)这种会用。使用的方式主要是用 TEE 内置密钥在 TEE 内进行加密解密,或者在 TEE 内用内置密钥对一段信息进行签名。

你说的这个场景,属于 TEE 签名应用的一种,这个结果是无法伪造的。

在无法伪造 TEE 结果的情况下,要伪造 BL 设备信息等等,用的方法是降级。某些早期设备并不具备 TEE 硬件,所以能够通过 hook 这个校验请求,欺骗系统对于硬件型号的识别,使其认为该设备不具备 TEE 能力,于是降级到非硬件的检测方式上,从而绕过相关的检测。
@kuanat #1

这个方法不一定全适用,看堡垒机是什么样的,能 ssh 的话才可以。
344 天前
回复了 sampeng 创建的主题 程序员 一个疑问,现在是人均一台开发机了?
我翻了一下楼主的提问记录,没有别的意思,只是想判断你是不是有能力自己回答这个问题。

我觉得你想问的只需要几看一遍官方简介就够了,这个文档甚至不满一页。使用场景、延迟这些关键点都回答到了,完全不需要思考。

https://code.visualstudio.com/docs/remote/remote-overview
应用自己不体面,操作系统想让它体面可太难了。

我用折叠屏两个月了,这个功能说实话除了保持前台有点意义,其他应用场景都是产品经理想象出来的,聊胜于无。
我用 GoLand 非常少,印象里有几个方面比 VS Code 要好:

1. 自动补全更加“智能”,或者说排序、展示形式更人性化更符合预期
2. 重构支持 interface/implementation ,而 gopls 还在 symbol 层面
3. 代码跳转( navigation )更舒适
4. Debugger 更好用?
5. 自带 vim 键位比 VS Code 插件好用

这里面 1 是短时间 VS Code 追不上的,这个需要投入比较多的人工打磨,不是个技术问题。

第 2 点 gopls 是可以做功能支持的,但是需要 VS Code 插件端提供一套 UI 流程,确认哪些要改哪些保留,我个人觉得是无所谓的。第 3 点也差不多,VS Code 是个 editor ,UI/UX 是不如 IDE 的,但这一点说实话我觉得不影响,但是还是列出来了。第 4 点,我周围的人说 GoLand 好用,但我个人觉得是个习惯问题,现在来说 Delve 做得越来越好了。最后第 5 点,现在都用 VS Code 集成一个 neovim 实例,我觉得已经反杀了。

除了第 1 点,剩下的优势其实是源于插件功能受限于 VS Code 界面机制,不如 IDE 那么灵活。



我是 old school 派的,所以对 editor+plugin 的好感远大于 IDE 。自从 VS Code 出来,标准化了 LSP/DAP 之后,我的就开始 vim/VS Code 并用,原因是我可以花时间为开发用的语言做配置,但是很多时候要阅读那些我不写的语言的代码,VS Code 提供了很好的默认配置。再后来微软的 Remote 开发成熟了,我就彻底转向了 VS Code ,同时用 neovim 替代了 vim 。

GoLand 我自己在 2021 年前后短暂用过。个人观点是,在 2022 年之前,GoLand 优势还是比较明显的,但是 2022 年之后,GoLand 的优势只在细节层面了。技术层面无论是当下还是未来,可能都追不上 VS Code 了。

2021 这一年,VS Code Go 体验有了质的飞跃。一是实现了 Testing API ,二是和 Delve 合作支持了 DAP 。没有多长时间,又实现了 Testing/Benchmark 的可视化,DAP 也支持了远程 attach 。测试 Debug 成了真正可用的特性。

之后 2022 年都是些细节改善,比较大的功能就是 inlay hints 。到现在体验已经非常好了。
我觉得单独拿出来一个语法细节做比较是没有意义的,异常处理的模式要放到语言设计层面去考虑。没有什么优劣之分,更多是一种取舍。

在我看来,Go 的整体设计思想是降低开发者的认知负担。前段时间 V2EX 就有个帖子,讨论并发模型里的内存可见性。对于 Go 开发来说,不知道内存可见性这个概念一点不影响写出正确的多线程代码,因为这个模型非常符合直觉。但是对于写 C 的来说,不了解这样的抽象就会踩很多坑。

但是做类似的抽象是有代价的,Go 的主要思路是“协作”(这个概念是我自创的),就是在无关紧要的地方都做一点小妥协,换取整体的简洁。比如 goroutine 就是这样,没有机制让你主动 kill 一个 goroutine ,但是可以提前沟通一个 context 机制,gouroutine 可以在获知意图的时候主动退出。

回到错误和异常处理的话题上,Go 选择了简化控制流,从机制上减少因为错误处理又引入新的错误的风险。代价是,异常处理流程的参与者都要主动确认自己的职责。本质上 if err!=nil 不是异常处理,而是判断这个事情要不要我来处理。这样设计的前提是 Go 从思想层面重新定义了“错误”和“异常”,能恢复的都叫错误,不能恢复的都交给 panic/recover ,楼上也有不少人提到了,Rust 的设计思路也是这样,这里就不展开讨论了。

再说一下语法层面的事情。前两天还有帖子讨论为什么 Go 直到 1.21 才提供 Min/Max 的标准实现。当一门语言的设计目标包含了简洁、高效和向后兼容的时候,增加新特性就变成了需要慎重考虑的事情,泛型这个事情 Go 讨论了接近十年。设计者知道 Min/Max 是个常见需求,泛型也是很必要的特性,在没有标准库实现之前,还是通过 math 包提供了浮点类型的 Min/Max 功能。其他类型需要开发者自己写,毕竟浮点比较很容易出错,但其他类型几乎写不错的。还是那个“协作”的思想,在可以接受的地方做些妥协,是为了整体更高效。

所以说到底这是个取舍的问题,Go 自始至终就是忠于“总体简洁”这个思路的,不够理想的错误处理就是代价。一些看似简单的语法变动,在编译器层面就是极其复杂的问题。Rust 内存安全,但是开发者要理解复杂的编程范式,编译器又慢又复杂。Java 写起来语法糖够多,虚拟机也自由,代价就是效率不够高。Go 相对平衡,开发者和编译器各自妥协一下,花一点小代价为对方解决一些棘手的问题。在这个事情上,不能既要又要,所以我才说单独比较错误处理这个点没有意义,一定要放到语言设计的整体层面上来讨论。

关于一些改善错误处理的思路:

1. 为 error 设计额外的类型

这个方案其实有过非常多的讨论,包括 Go 没有 enum 类型说到底是同一个问题。核心原因还是增加复杂的类型和 Go 的设计思路不符,而且实现起来和接口冲突,所以放弃了几乎所有非算术类型的支持。对于 error 类型的需求建议用接口和类型断言来实现。代价是类型断言是运行时特性,不如编译时实现安全。

2. 函数式 monad

除非换一种语言,几乎没有可能从底层支持函数式编程范式。另一个思路是基于泛型来模拟,这个方案只能说有希望,进标准库估计要讨论的东西很多。

3. Go 现在推荐的思路

就因为错误处理这个事,Go 很长时间标准库里都没有结构化日志。和基于泛型的 cmp 一样,slog 也是 1.21 才进的标准库。

对于错误类型的定义,用接口和类型断言。像 call stack 这类信息,从 runtime 取回来按照需求用接口封装一下。
对于错落处理的传递,用自定义 Logger 或者 Context 。比如 tracing 这类信息追加一下。

这里额外提一句,Context 就是非常好的“协作”机制,调用方的举手之劳,整个调用链都受益的。让被调用方绞尽脑汁汇报……只能说一将无能累死三军。

最后做个总结,不要脱离语言背景谈语法细节。用一门语言就学习它的思想,然后把精髓用在最合适的场景里。
@zhwguest #8

git tag 是与 repo 相关的,/old/dep 和 /new/dep 是相互独立的,我不确定你说的冲突,只要同一个 repo 里面 tag 唯一就可以。

一般不建议 => 左边带版本,除非你的项目永远不升级依赖。如果左边带版本 v1.2.3 ,就代表只有这个特定版本会被替换,但是上游更新 v1.2.4 然后你 go get -u 升级了依赖,那 v1.2.3 的替换就失效了。不带版本就是所有版本都会替换。

右边只有替换成本地 repo 的时候才可以不带版本。
351 天前
回复了 Kholin 创建的主题 分享创造 我写了个类 Hacker News 的社区
chi 确实非常好用,无依赖,兼容 net/http 。小项目里极其灵活,大项目里无缝替换。
352 天前
回复了 hkhk366 创建的主题 程序员 everything 索引原理探讨
@hkhk366 #20

我知道问题出在哪里了,是“全文搜索”这个词有歧义,我理解成了 document retrieval 而你想表达的是 substring indexing 。

回到“建索引”这个事情上,我说下 everything 的做法。很早之前逆向过,有个大致的印象,不保证适用于现在的版本。即使不逆向,很多思路也能推理出来。

1.
持久化层面上,本地数据库就是 MFT 解析之后换了个私有格式,文件夹和文件分开,排序之后保存。目的是加速冷启动之后的数据重建。这个排序反正是一次性的,后续根据 Journal 来更新。

重点在于它是用什么样的数据结构来描述文件系统的树型关系,考虑到查询是经常需要按某个子路径做筛选的,所以文件和文件夹都会记录 parent 的指向。这里 parent 就是比较重要的索引之一。

2.
其他可以检索的字段的索引都是在内存中重建的,比如文件大小、扩展名和时间戳这些。

就是类似 sql 那种对某个字段建索引,说白了就是换个结构重写了一份。印象用的是 B+ 树而不是 hash ,因为 hash 不太适合做范围查询。

3.
字符串匹配明显是基于正则的。所以像文件名、路径名是没必要做“索引”的,都是全量匹配。

一般来说,解释型的正则引擎都比较慢。编译型的正则引擎要么是编译成 bytecode 然后 JIT 运行,要么是编译时就把所有匹配路径都预先编译好。后面这个方式只适用于正则比较简单的情况,everything 是支持 \n 回溯的,生成的二进制文件也很小,不太可能是后面的做法。

手写正则引擎这个事情我没做过,理论上要建 NFA 然后转成 DFA ,这个过程比较麻烦。运行的时候只需要对 pattern 做一次,然后就可以匹配所有字符串了,对于文件名 substring matching 这个场景是非常合适的。

4.
everything 没有用 pcre 的原因应该是它不需要“通用”的正则引擎(没有替换的需求,也就不需要记录中间状态),自己写一个性能会更好。

另外它不支持模糊查询,我理解这里不是个性能问题,计算 Levenshtein 距离没有太大开销,但是结果排序的开销会很大。



顺便一提逆向的事情。具体到 everything 上面,主要还是靠静态分析。因为这个程序写得非常好,又没有刻意做混淆,尽管 c 程序非 debug 版是不带符号表的,但是通过字符串 xrefs 很容易理解并还原调用逻辑,特别是你大概能猜到作者思路的情况下。

另外用逆向手段还原算法有两种,比如加密狗之类的逻辑一般需要硬怼,但像 everything 这种主要靠猜,根据传参和返回还有逻辑,从语义上理解操作过程,毕竟它大概率是某个已知算法,而不是作者自创的。
做个不负责任的猜测。

我印象 Windows 微信自带的那个图片查看器是单独用 C 写的,底层是 GDI+,内部实现是支持 DPI 缩放的。

这就意味着它不是以物理 pixel 的方式来显示图片的,所以缩放的时候会存在逻辑像素和物理像素的比例转换,由此内部会有 rounding ,如果要正常显示图片其实是需要插值的。

除非图片恰好位于画布的 (0,0) 位置,按 Windows 显示的坐标系就是左上角。这个逻辑在大部分时候会感知不到,因为对于不需要缩放的场景,画布和图片是一样大的,没有插值过程。严格来说还是会走一遍插值流程,但是没有 rounding 。

但是对于需要缩放的场景,图片不会位于 (0,0) 位置,这时候插值的效果就体现出来了。默认的插值逻辑是 Linear 算法,这个很容易察觉到模糊。

这个行为比较反直觉,把图片放到左上角,它就是清晰的。一旦相对画布有个 (x,y) 偏移,即使没有任何缩放,也会导致模糊。

上面都是凭印象写的,要验证的话看一下那个图片查看器的导入函数,如果没有 SetInterpolationMode 的调用基本就是这个问题没跑了。


PS

其实像文本编辑器、图片查看器这类应用都是很难写的,细节非常多而且原理都非常基础,不是简单调用个 API 的事情。上面说的这个问题,正常科班出身的话,有一点图形学基础大致就能反应过来问题出在哪里,但是没有接触过就几乎想象不到。

话说回来,反正大家都是草台班子,又不是不能用……
352 天前
回复了 hkhk366 创建的主题 程序员 everything 索引原理探讨
其实你这个思路偏了啊,当你意识到 5ms 连文件 IO 都完成不了的时候,应该考虑这不是个算法问题而是个策略问题。



官方页面上已经说得很清楚了,因为关键内容不多,我就直接复制过来:

来自 https://www.voidtools.com/support/everything/searching/

Content Searching

Warning: content searching is extremely slow.

File content is not indexed.

Please combine content: functions with other filters for the best performance.

Content search functions:
content:<text> Search file content using the associated iFilter. If no iFilter exists UTF-8 content is used.
ansicontent:<text> File contents are treated as ANSI text.
utf8content:<text> File contents are treated as UTF-8 text.
utf16content:<text> File contents are treated as UTF-16 (Unicode) text.
utf16becontent:<text> File contents are treated as UTF-16 (Big Endian) text.

另外 https://www.voidtools.com/forum/viewtopic.php?t=9793 这里有更详细的说明。

Everything will keep content in memory.
Content indexing is intended for indexing user documents only.
I do not recommend indexing over 1GB of text.
For the best performance, set an include only folder.

By default, Everything will index the following file types for content:
*.doc;*.docx;*.pdf;*.txt;*.xls;*.xlsx



这 5ms 就做了一个内存数据库的检索,而且数量级并不是你想象中的 100 万。你在没有验证的情况下,就认为它扫描了文件,所以思路跑偏了。即使没有一点逆向基础,也有很简单的办法知道一个程序运行的时候打开读取了哪些文件,如果你验证了这一点,估计已经找到答案了。

所有的“索引”类算法,核心思想并不在“算”上面,而在于将原始数据结构以一种易于被检索的数据格式存储。换句话说,之所以索引可以加速搜索,是因为提前生成了要查询的结果。

Windows 自身有个索引服务,但是绝大多数文件格式都是二进制的,在不了解它的文件结构的情况下,是没有办法进行文本搜索的。所以 Windows 提供了一个 IFilter 机制,由文件格式的创建者,主动暴露可以被索引的信息。然后再通过后台服务对于相关的文件格式进行索引,首次全盘索引完成之后,只有文件内容发生变化,才会触发索引更新。几大操作系统的索引都是相同的机制。

Everything 的说明就是这样一个意思,它会在内存索引少数路径下的特定格式的文件,为其建立文本内容索引。后续的搜索只是内存搜索引。至于全文匹配到底用了什么算法,是不是有指令集优化,是另外的事情,到了这个层面,只要思路对,算法是不是最优化已经不重要了。( Everything 是 C 写的,但是没有什么混淆加密,稍微逆向一下大概就能弄清楚。)
353 天前
回复了 happmaoo 创建的主题 Linux 终于可以登陆网页微信了
353 天前
回复了 happmaoo 创建的主题 Linux 终于可以登陆网页微信了
@pakro888 #56

我又重新看了一下,实际上只有登录过程有校验,实际使用的时候是没有的。所以只需要匹配 /cgi-bin/mmwebxxxx-bin/webxxxxnewloginpage 这个路径做修改就可以了。

估计腾讯现在比较后悔,当初就不该做 web 版本,做了 web 版不说,失误就失误在又套壳 web 做了 UOS 版,这下彻底摆脱不掉了。结果就是现在所有的微信机器人都是走的 UOS 这个协议。

腾讯不想让人用 web 版,就从账号上做限制,明明有 web 版就是不给用。但是腾讯没法限制 UOS 这个客户端,好在用 UOS 的人还是比较少的,只是这样还是管不住机器人。顺便一说,UOS 这个版本还是 MIT 协议发布的。

UOS 版本是有发行版校验的,这也就是 extspam 这个字段的来源。

所以去年的时候,有人把 UOS 版本重新打包给其他发行版用,就把 /etc/lsb-release 给改了。之前 V2EX 上有过讨论帖子 https://v2ex.com/t/858659

研究一下就会发现,这个特殊的 extspam 竟然是静态的……这个失误就比较离谱了,也就是说根本起不到防滥用的作用。所以现在用简单的网页扩展,修改一下请求头就能一直用。

估计是当初负责 UOS 版本的人没有什么网络开发经验,缺少基本的校验要动态化的常识。另外本地防逆向的水平也很弱,生成逻辑都在一个 so 库里,只做了字符串混淆,混淆还是最简单的 xor 。
@zhwguest #4

可能之前没表达清楚,这里应该不存在冲突的。


比如说你一开始用的 /old/dep 依赖,那么在 go.mod 里面就会有

require github.com/old/dep v1.2.3

只要你不升级依赖,那么整个项目一直会用 /old/dep v1.2.3

然后你 fork 了 /new/dep 出来,并且给 /new/dep 打了版本 v1.2.3
这个时候增加一句

replace github.com/old/dep v1.2.3 => github.com/new/dep v1.2.3

就可以了。

假如 /old/dep 更新过后,你发现没有必要用 /new/dep 了,那就把上面的删掉,然后更新依赖到比如说 /new/dep v1.2.4 ,不管是 go get -u 还是手动修改 go.mod ,最终 go.mod 都会是

require github.com/old/dep v1.2.4

假如你还是要用 /new/dep ,不管你是继续在 /new/dep 上修改,还是合并了 /old/dep 的上游更新,然后打了 v1.2.4 的版本,只需要修改 replace 这一句变成

replace github.com/old/dep v1.2.3 => github.com/new/dep v1.2.4

但是 require 那一句还保持

require github.com/old/dep v1.2.3



也就是说,只要你不主动升级 /old/dep 的版本,那就只需要修改 replace 的目标版本。至于 /new/dep 怎么打版本 tag 是随意的。

之前说保持版本号一致只是应对两种场景,一种是 /new/dep 作为临时开发测试分支,有可能被 /old/dep 合并,当 /old/dep 更新之后又会回到 /old/dep 上面去。另一种是 /new/dep 是因为某些原因不可能被 /old/dep 合并,但是修改可以通过 patch 的方式自动化,上游 /old/dep 发布一个版本,下游 /new/dep 就发布一个对应的修改版。



默认情况下,github 的 fork 功能,是不带 tag 的,所以你可以在 fork 里面重新任意标记版本。假如你不想处理 tag 相关的事情,也可以完全不理会。这种情况下,replace 后面改成 /new/dep 就行了,go.sum 会用 v0.0.0-timestamp-commit_hash 的方式来唯一确定。
354 天前
回复了 happmaoo 创建的主题 Linux 终于可以登陆网页微信了
@BaiLinfeng #41

前面是手机回复的,开电脑看了一下。

登录链接用:

https://wx.qq.com/?&lang=zh_CN&target=t

然后用个可以改 header 的扩展,匹配一下 https://wx.qq.com/* 的请求,添加两个字段

client-version = 2.0.0

extspam =
Go8FCIkFEokFCggwMDAwMDAwMRAGGvAESySibk50w5Wb3uTl2c2h64jVVrV7gNs06GFlWplHQbY/5FfiO++1yH4ykCyNPWKXmco+wfQzK5R98D3so7rJ5LmGFvBLjGceleySrc3SOf2Pc1gVehzJgODeS0lDL3/I/0S2SSE98YgKleq6Uqx6ndTy9yaL9qFxJL7eiA/R3SEfTaW1SBoSITIu+EEkXff+Pv8NHOk7N57rcGk1w0ZzRrQDkXTOXFN2iHYIzAAZPIOY45Lsh+A4slpgnDiaOvRtlQYCt97nmPLuTipOJ8Qc5pM7ZsOsAPPrCQL7nK0I7aPrFDF0q4ziUUKettzW8MrAaiVfmbD1/VkmLNVqqZVvBCtRblXb5FHmtS8FxnqCzYP4WFvz3T0TcrOqwLX1M/DQvcHaGGw0B0y4bZMs7lVScGBFxMj3vbFi2SRKbKhaitxHfYHAOAa0X7/MSS0RNAjdwoyGHeOepXOKY+h3iHeqCvgOH6LOifdHf/1aaZNwSkGotYnYScW8Yx63LnSwba7+hESrtPa/huRmB9KWvMCKbDThL/nne14hnL277EDCSocPu3rOSYjuB9gKSOdVmWsj9Dxb/iZIe+S6AiG29Esm+/eUacSba0k8wn5HhHg9d4tIcixrxveflc8vi2/wNQGVFNsGO6tB5WF0xf/plngOvQ1/ivGV/C1Qpdhzznh0ExAVJ6dwzNg7qIEBaw+BzTJTUuRcPk92Sn6QDn2Pu3mpONaEumacjW4w6ipPnPw+g2TfywJjeEcpSZaP4Q3YV5HG8D6UjWA4GSkBKculWpdCMadx0usMomsSS/74QgpYqcPkmamB4nVv1JxczYITIqItIKjD35IGKAUwAA==

估计搜一下“微信 extspam”就能找到,基于 UOS 的都应该是这个方法。
354 天前
回复了 happmaoo 创建的主题 Linux 终于可以登陆网页微信了
我一直在用模拟 UOS 那个 electron 版本的方式,大概一年了没有问题。

登录请求抓下来印象是三个特殊 header 字段,然后登录链接加个 &target=t 就行。
354 天前
回复了 abcfreedom 创建的主题 Android note12turbo 刷哪个系统比较靠谱
@justincnn #11

厉害的是做 rom 的人啊,其他机型上 xda 看一下,基本上找到一个就能全找到了。

我这是更新一批开发测试机,特意挑的刷机最方便的 n12t ,其他机型可能没这么多选择。
1  2  3  4  5  6  7  8  9  10 ... 12  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1143 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 28ms · UTC 18:47 · PVG 02:47 · LAX 10:47 · JFK 13:47
Developed with CodeLauncher
♥ Do have faith in what you're doing.