V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  kuanat  ›  全部回复第 3 页 / 共 12 页
回复总数  233
1  2  3  4  5  6  7  8  9  10 ... 12  
171 天前
回复了 ChristopherY 创建的主题 程序员 怎么样快速解析好几个 G 的 pcap 文件
@ChristopherY #18

用什么都可以,取决于你哪种语言比较熟练。C 版本的 libpcap 我没用过,考虑到是 tcpdump 在维护的,肯定是没问题的。Go 版本虽然两年没更新了,但协议这个东西又不会变……

另外我觉得你其实考虑复杂了,gopacket/libpcap 都是强在抓包,至于你是不是用它做解析不关键,用它做解析的原因就是它们把协议相关的数据结构都定义好了。

换个表达方式,你现在以字节形式读取到某个包(忽略到 pcap 文件格式解析),它一定是代表着某个多层嵌套的数据结构:

[ L1_Header : L1_Payload [ L2_Header : L2_Payload [ L3_Header : L3_Payload [ ... ] ] ]

然后假设 L1 是来自三层的,然后有 IP/ICMP/IGMP 几种协议,就拿 IP/ICMP/IGMP 的数据结构去套上面的字节流,匹配到就可以拆包了,L1_Payload 就是 [] 里面 L2/L3... 的内容,继续下一层解析就是了。

像 dpkt 这种数据不足,肯定是各种协议 Header 的数据结构定义不完善。scapy 我用过但是印象不深了,我估计慢的主要原因是它没法做到像 C/Go 这样可以手动分配内存,然后 one pass 把多层结构一次解析出来。但是 scapy 大概每次都要遍历匹配所有协议,来判断下一层是什么。

这个解析过程本质上和按照某个特定格式读取二进制文件没什么区别。

提高解析效率除了解析单个包层面的优化,主要是靠多线程。特别是实时抓包实时处理,靠内核 AF_PACKET 机制扇出,分配个多个线程来解析。如果是单线程肯定会非常慢。
AQC113 应该是 14nm 的吧,能效比好了非常多。Marvell 家早些年 28nm 节点的电模块,低负载起步就是 70 度。

这种芯片和模块的散热,正常有点风就不至于热死。但你要纯被动,没有个 1kg 的散热器当热容怕是扛不住。

很多设施水平一般的机房里,环境温度就接近 40 ,用 40 度的空气给 50 度的硬盘,70 度的模块和 90 度的处理器散热也没什么压力,关键就是风量要够。
171 天前
回复了 ateist 创建的主题 Linux LinuxQQ 强制占用我的快捷键
腾讯软件的 Linux 版本都是应付事的,如果不是要适配国产系统,绝对不会主动开发。

X11 的设计逻辑里,任何应用不管在不在焦点,都可以读取针对其他任何应用的键盘输入。注册快捷键就变成了随便一个应用都去监听键盘输入事件,然后抢过来自己处理。

按照这个逻辑,我估计你用一个没有 input 组访问权限的用户去运行,就能避免它读取并绑定快捷键,但是程序本身可能会选择摆烂。我没有试过,只是提供一个思路。
本来想回复有可能是 headless 导致的,结果看到你已经找到答案了。

虽然 ssh 环境不能访问键盘鼠标显示器这些远程设备,但是 kmsgrab 这种访问 dri 还是可以的,包括很多 headless 环境访问显卡也是一个道理。

如果你需要在无头环境下或者远程主机无输出的环境下录屏,Gnome 新版本身支持创建虚拟显示器(主要是为 gnome 那个 rdp 实现服务的),让远程主机输出到这个虚拟显示器就可以了。
@Kinnikuman #10

这个场景我也没什么经验,结合 #9 #11 楼的引用随便说说。

1. 硬盘、内存速度

目前常见的硬件,即便是机械硬盘,其加载速度也远大于被加载视频的播放速度,更不用说内存了。

2. 硬盘文件的缓存机制

我在前面的回复里解释了一部分。再进一步说,你的应用不会直接读写硬盘,操作系统内核替你“智能”完成硬盘文件在内存中的缓存工作。

当然你也可以手动申请内存,然后读取硬盘文件内容之后保存在申请到的内存中,同时自己编写缓存内容更新的逻辑。这样做只适用于非常有限的场景,比如磁盘 IO 长期被后台应用占用,或者需要反复在多个超大(超过内存容量)文件之间切换。对于一个视频播放器而言,不需要考虑这些事情。

3. 缓存容量设定

我理解你设想中的方案都有一个隐式前提,视频文件非常大,需要尽可能多缓存。但是一般来说,除非你要提供“保存视频文件到本地以备无网络时观看”这个本质上名为“下载”功能,绝大多数时间只缓存一定量的数据即可。换个说法,下载功能可以是按需( on-demand )的,填满缓存容量就可以暂停。

也就是说,内存、硬盘的二级缓存机制是没有必要的。用内存缓存的唯一目的就是避免硬盘读写,硬盘缓存是解决内存缓存不够的才用的,一旦使用硬盘作为缓存就没必要再做内存缓存。

4. 缓存的内容取决于来源协议或者格式

根据上面的分析,本地文件技术上说是不需要缓存的,或者说不需要你手动缓存的。

网络视频有可能是以网盘作为后端,本质上还是特定格式视频文件的形式,也有可能是基于某种流媒体协议。对于前者,缓存的就是文件。对于后者,缓存的是视频流意义上的 packet (非网络意义的 packet )。

5. 播放器本身不关心缓存后端的来源是什么,只关心从特定的来源流式读取。

比如桌面浏览器可以指定缓存后端是内存还是硬盘,但内嵌播放器是无需关心的。播放器这类本地应用,也只需要为数据流的消费者提供一个来源。即播放逻辑永远是固定的,至于来源(缓存)与播放行为是无关的。

6. 下载、解码和播放之间解耦

前面有人引用 mpv 处理缓存的逻辑,它缓存的对象是 packet 经过 demuxer 处理后的数据,即缓存发生于 demuxer 和 decoder 之间。前面 3/4/5 点综合起来说的也是这个意思,下载并不是直接对接播放的,缓存发生于中间解码的部分。不需要对下载和播放逻辑做特殊处理,所有的特殊行为都在中间解码阶段。

7. 缓存的底层数据结构

缓存确实可以用 FIFO 数据结构表达,考虑到播放器的使用场景,固定容量的缓存一定会遇到周期性完整替换的需求。

可以考虑 ring buffer ,这样就需要控制生产者写入速率与消费者播放速率一致。或者考虑 double buffering ,用手动切换缓存后端简化速率匹配。
171 天前
回复了 ChristopherY 创建的主题 程序员 怎么样快速解析好几个 G 的 pcap 文件
还有楼上说得不对,网络包是一层一层嵌套的,必须从外向内解析。

当然理论上可以通过某层协议的标志从二进制的某个偏移开始解析,无视下层协议,但是这样做会损失很多信息,也不保证解析结果正确,与最初的目的不符。

gopacket 这个库是可以自己写未知协议扩展的,比如原版里面没有 pppoe/ppp 的支持,我在自己的项目里加上了,可能也就二三十行代码。就是写清楚字节流多少偏移对应该协议的某个字段。如果是那种非定长编码的格式,需要先解析头部的长度信息,再解析对应的字段。
171 天前
回复了 ChristopherY 创建的主题 程序员 怎么样快速解析好几个 G 的 pcap 文件
https://github.com/google/gopacket

我之前在 go 经验的帖子里写过,这个库配合一些手动内存管理的技巧,在 10Gbps 网络上做实时处理没什么问题。

如果是 pcap 离线文件,直接按照示例写就好了。
174 天前
回复了 saveai 创建的主题 程序员 某私服地下城手游抓包协议咨询
游戏的核心逻辑肯定不会走 http 协议,大多数是在 tcp/udp 基础上自定义协议。最近这些年的游戏多数都会用 protobuf 类似协议来简化开发。

如果是比较小众的游戏私服,大概率是内部泄漏的,可能是服务端程序,也可能是代码文档。如果是比较火的游戏,才比较有可能是人力重建。

如果以逆向工程的方式来重建服务器端,主要是两个工作。一个是逆向客户端,提取客户端发包和收包的数据结构定义,然后实现一个协议兼容的服务器端。另一个就是重建游戏逻辑,这个事情比想象中简单,只是工作量巨大。

要是做过类似的正向开发,这个事情不难理解。具体到你的问题上,能逆向出协议定义的话(无论是静态解密还是动态追踪),抓到 tcp/udp 包就等于 http 抓到请求。
还限制使用区域,是怕卖二手吗哈哈,看来实在是太小众了。

“不需要听用 app 对时虐耳的噪音”,如果目标频率是 40/60 kHz 这个水平的话,估计是用高次谐波实现的吧。一般高频单元也就上到 20kHz 了,基频大概就是 15~20 kHz 这段。假如你一个周对时一次的话,可能也不是多大个事。
我从来没有见过哪个安卓设备支持你说的功能,原因就是一楼指出的安卓平板不支持 RNDIS 输入。

原理层面就是两个设备之间通过 USB 建立以太网连接,而 USB 又是 Master/Slave 机制的,所以一套协议加上主从两套实现才能运作。

协议层面上,主流的是 Windows 的 RNDIS ,基本上所有操作系统都支持了。USB 自己有一套类似的,但是应用不太多。

RNDIS 的从端实现,几乎所有的安卓设备都支持。主端实现,基本只有桌面系统才支持,比如 Windows/Linux 。

Linux 的支持是通过 usbnet 这个内核模块完成的,理论上可以用于安卓。但是从来没有见过,要么是 Android 的内核砍掉了,要么就是单纯没有人做。
@Kinnikuman

如果是本地文件,缓存进度条可能和内存没有太大关系。

缓存的真实量取决于内核管理的 page cache ,假如剩余空间足够大,这个 page cache 会在第一次访问文件的时候把存储中的内容全部加载,不内存不足的话会加载一部分。在应用程序看来,fd 已经在了,stream 读取也开始了,就看你读多少。

这个 page cache 的容量主要影响拖动进度条,超出去了就会去读存储,没超的话,内核会有自己算法加载新的内容进有限的 page cache 里。
183 天前
回复了 kuanat 创建的主题 分享发现 一个好用的、纯软件的扩展屏方案
@swordsmile #1

Hyprland 目前还不支持 multi-seat 功能 https://github.com/hyprwm/Hyprland/issues/1731

这也是我一直主用 sway 的原因。其他方面 hyprland 易用性好太多了,不得已我还给 sway 写了个简陋的 master stack 布局管理器……

另外还有些 layer-shell 协议的应用(悬浮显示状态、通知和关机菜单这一类)也是硬编码了 seat0 的,有可能会导致显示位置或者输入焦点异常。对我影响比较大的是 tofi (一个 wofi 的改版)会有输入焦点问题。
187 天前
回复了 swordsmile 创建的主题 Linux archlinux hyprland swaylock-effects wayvnc 自动退出
@swordsmile #2

我看了一下,hyprland 支持创建 headless 的。

https://wiki.hyprland.org/Configuring/Using-hyprctl/#output

但我不确定 hyprland 启动的时候是不是能 headless ,不过看 hyprctl instances 似乎是可以这么用的,你可以试一下。

实在有需要可以考虑 sway 啊,我用这个方案已经很久了,也不用欺骗头。

我用 sway 的方式是

WLR_BACKENDS=headless WLR_LIBINPUT_NO_DEVICES=1 sway

然后

swaymsg create_output

最后

wayvnc --output=HEADLESS-1

你可以试试看能不能把类似方法用在 hyprland 上面。
188 天前
回复了 digd 创建的主题 分享发现 GPD 新曝光的双屏变形本
不只是 GPD ,所有依赖差异化竞争的电子、硬件厂,受出货量限制研发成本难以均摊,即便设计层面不翻车,品控方面能过关的都很罕见。

就这个设计来说,我觉得以 GPD 现在的能力,屏轴、排线会是品控灾难。我能理解做 13 寸的技术理由,但我不理解做这个产品的商业决策。
你的疑问是对的。一旦离开 UEFI/grub 之后,之前 ventoy 虚拟出来的光驱设备就不存在了。

然后魔改 grub2 也是对的,只是如果你去看修改的代码 https://github.com/ventoy/Ventoy/tree/master/GRUB2/MOD_SRC/grub-2.04 会发现这些改动都是表面的,跟启动机制没有关系。

所以 ventoy 并不是用 grub2 loopback 加载 iso 完成引导的。

“除非系统内有对应的驱动程序去专门去访问这段内存及模拟驱动器”这句话不完全对,Win/Linux 内核都有 loopback 加载机制,也就是你说的“驱动”。真正的问题,去哪里加载。这里需要的是逻辑意义上的地址,不管它背后是内存还是硬盘文件。

如果你大致浏览一下 ventoy 的代码,肯定会注意到 vtoyjump 这个与众不同的名字,其他目录要么是一些基础功能,要么是 ventoy 的功能。另外 ventoy 是可以输出 log 的,你会在日志中看到 vtoyjump 相关功能的调用。

以下是我根据之前的印象总结的,我估计原理应该没问题,细节可能有出入。

如果是引导 Linux ,会首先引导 ventoy.cpio ,完成虚拟光驱初始化之后再链式引导 initrd 。

如果是引导 Windows ,会用 vtoyjump 替代 Windows 的引导文件(大概名字是 winpeXXX 的一个文件),然后原版在内存中保留一份副本。(这个“替代”是 overlay 的意思,并非修改原始文件,相关的 injection 功能也被 ventoy 做成了插件)此时还处于 grub 阶段,以你描述的 loopback 方式引导 boot.wim ,完成内核初始化。此时 grub 阶段虚拟的光驱设备就访问不到了。

原本下一步是引导 winpe 进入安装程序,这时被 vtoyjump 替代,vtoyjump 利用 NT 内核 API 加载原始 iso 成为 loopback 设备。 之后 vtoyjump 再引导 winpe 那个程序,就进入正常安装过程了。
189 天前
回复了 swordsmile 创建的主题 Linux archlinux hyprland swaylock-effects wayvnc 自动退出
你这个组合我没有用过,估计需要排查一下是谁崩了。从描述来看 wayvnc 晚于 hyprland ,是不是与 swaylock-effects 有关不清楚,看一下各自的 log 吧。

不启动 hyprland 这个应该做不到,就像 x11 一定要有 x server 一样。我估计你说的应该是 headless 模式? wayvnc 应该支持,hyprland 不清楚。如果 hyprland 不支持 headless 模式的话,可以用一个 hdmi 欺骗头让 hyprland 输出到这个 hdmi 上。
190 天前
回复了 Bo0 创建的主题 程序员 电脑抓包 APP 的请求失败
这个话题搜 ssl pinning 会有很多信息。

如果抓包的时候 App 看不到相关数据了,这种一般只是简单拒绝走代理,或者拒绝了中间人证书,导致连不上了。如果 App 看到的数据正常,说明有 fallback 机制,多数都是非平台默认的 ssl 实现。

不管哪种方式,常规应对策略基本上是 frida hook 掉类似证书加载、证书验证和代理之类的调用。有比较通用的脚本,支持常见的 ssl 库。

但这样做的前提是应用本身没有混淆,调用的方法名没变过,或者有能力推断出混淆过的名字和地址。混淆一般是通过加壳完成的,除了少数基于 vmp 的方案,大多数都有比较通用的应对思路。

脱壳之后一般还会需要绕过 root/签名检测,拦截客户端异常汇报等等,比起脱壳来说要简单。


非常规的应对策略是类似 eCapture 这种非入侵式的方案,可以绕开证书校验。配合虚拟机效果会更好。
192 天前
回复了 noisywolf 创建的主题 程序员 Linux 启动自己的 GUI 应用,不进桌面
取决于用途和场景,大致有几个思路,你可以按照关键词去搜对应的做法。

如果以安装的包来划分,整个显示框架大概有:Framebuffer 层( DRM/KMS ),Display Server 层( X.org/Wayland ),窗口管理器,桌面附加组件四层。FB 层肯定都有也不需要关心,Display Server 层必须要有一个,根据你的应用来选。按照你的描述,桌面( KDE/Gnome )这些都可以不要,窗口管理器可以有也可以没有。

这里以 X11 作为显示后端为例:

在某个 tty 启动 X session 。用到的命令就是 `startx`,后面可以直接跟你的 x11 应用,也可以跟 `xterm` 之类的 vte 终端,之后可以在终端里面按需启动 x11 应用。

这里对于 tty 的分配,以及对应到显示器需要你手动配置。如果你是 ssh 连接到远程服务器,需要 ssh x11 tunneling 。

如果需要窗口管理器,可以 `startx` 先启动窗口管理器,然后再启动对应的应用。
193 天前
回复了 XdpCs 创建的主题 Go 编程语言 如何更好的打印日志
以打印日志的方式来 debug ,在开发阶段和生产阶段是有区别的。正好前两天我在 https://v2ex.com/t/1038327 这个帖子里有个回复,可以参考一下。

以我的经验来看,日志 debug 这个话题表面上看是个技术问题,然而我更倾向于把它们定义为工程问题。把问题聚焦在代码怎么写上面很难形成有效的思路,想明白动机和目标之间的联系,才能得出如何正确实现的方法。



我就针对生产环境日志打印做个补充,这里就拿一般 go 服务器后端的场景来说明。

- 日志采集的方式

一般要么写本地文件,然后有 agent 负责汇总到日志服务器。要么直接根据配置向日志数据库来写。也就是说一般生产环境里日志排错主要靠数据库查询。

- 日志生成方式

上面帖子里有提到,生产环境的日志是“共享”的,也就是说日志主数据库很可能是全链路的信息都在,而某个 go 模块的信息只是一部分。这个主日志里面,多数时间理论上只包含业务信息,无法用于 debug 。

所以在我接触的项目里,会构建 release/debug 两个版本,线上部署 release 版本。当出现故障需要排错的时候,切一部分流量进入 debug 版本,debug 版本单独输出详细日志。这个日志包含程序运行信息,stack trace 等等。

- 日志记录的内容

生产环境排错主要是回答两个问题:首先是判断是不是该模块的错误,其次才是为什么出错。利用日志作为 debug 手段属于某种意义上的“异步”,感到困难的主要原因是,这个异步行为很难在本地开发工作流中复现。

如果能方便且顺利地在本地复现,困难可能就解决了一半。为了达到复现的目的,需要 debug 级日志中一定要包含进入本模块的输入,以及离开本模块的输出。



回到代码的层面,要做的就是把上面的思路具体化。

- 构建测试用例

当拿到输入和输出的时候,就可以在本地开发流程构建测试用例了。考虑到 go 实现的功能模块会涉及其他模块的调用,那就需要以 mock 的方式,直接引入其他模块的输入输出结果。这里就能看出来,debug 级别的日志,一定要包含和其他模块交互的输入输出。

这里顺便一提,mock 实现本地测试应该是开发流程中就要做的。

- 日志可读性

如果 go 实现的模块比较复杂,要记录各种输入输出就需要一定的组织规范,这就是你提到的问题。如果直接回答如何做,可能很难帮助你解决问题。

由于异常分析要在请求层面上,所以要求整个系统必须有统一的 traceID 之类的标志,不然就会可能拿着不匹配的输入与输出做调试。多数时候这个 traceID 是以中间件控制,或者在各个模块之间显式传递,无论哪种实现方式,都一定要有。

大的层面上,一定要记录 stack trace 即调用栈的回溯信息。它的作用是帮助你快速定位出问题的子模块,我个人比较倾向使用的方式类似于 error wrapping 的方式,可以参考 https://go.dev/blog/go1.13-errors 这篇文章。

这样对于错误,可以输出类似于 `调用方法 A ,入参 XXX : 调用方法 B ,入参 XXX : ...` 这样形式的字符串,冒号用于分隔。怎么记录不重要,标准一致即可。如果有需要,可以本地额外做一个更加 verbose 的 debug 版本,利用反射机制输出调用代码的行数等等。(这个事情主要是 API 接口相关的,模块内部流程的底层错误建议 wrap ,到达模块边界只返回定义好的 sentinel 错误。)

对于非错误的情况,一般在每个调用的入口和出口,根据调用的状态来输出不同等级的信息,比如某个方法调用的入口,输出 log.Info("XXX"),如果是走的正常分支,就在出口处再记录 log.Info("XXX"),如果走的是异常分支,可以在出口处记录 log.Warning("XXX")。这样最终会形成类似

```
INFO: 调用 A 开始
INFO: > 调用 B 开始
INFO: >> 调用 C 开始
INFO: << 调用 C 分支 C1
WARN: < 调用 B 分支 B2
INFO: 调用 A 结束
```

这个样子的日志记录,可以肉眼观察也可以利用文本工具来筛选。

这个日志的主要作用是帮助你确定异常发生时,对应的逻辑流程是什么,免去了你动态调试跟踪的麻烦。即便后续需要动态调试,也可以很准确地在目标位置下断点。

- 其他细节

我暂时能想起来一部分,如果以后想起来再补充。

日志层面一定要使用结构化的方式来记录,这样无论是写入数据库,还是查询筛选都会方便很多。

代码层面不要忽略任何错误,所有的错误都要有相应的处理(忽略也是一种处理,但一定要有对忽略错误这个行为的日志记录)。

模块内部对于所有外部输入都做 mock ,以提高测试覆盖率,方便后期 debug 。

这个事情的终极目标就是,出问题的时候,日志数据库筛一下就知道业务层面上是否有异常。有的话,立即切 debug 版本就能复现输入输出。拿到输入输出直接扔给本地 mock 版本,跑一下流程就知道是自己模块的问题,还是涉及其他交互模块的问题。如果确定是自己的问题,看 verbose 日志快速确定是哪个方法哪一行的错误。

写日志本质上就是以上述思路为目标做准备。
193 天前
回复了 qinconquer 创建的主题 程序员 app 软件中的热门榜单怎么做的呢
榜单如果只有 10~20 个这样,更新频率不高的话,建议人工。

程序只负责筛选出一定量的备选。
1  2  3  4  5  6  7  8  9  10 ... 12  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1076 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 27ms · UTC 19:17 · PVG 03:17 · LAX 11:17 · JFK 14:17
Developed with CodeLauncher
♥ Do have faith in what you're doing.