V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
0x676e67
V2EX  ›  Rust

Rust 编写的高性能 HTTP/HTTPS/SOCKS5 代理服务器

  •  
  •   0x676e67 · 29 天前 · 1498 次点击
    • 可配置并发限制
    • 服务绑定 CIDR 地址
    • 指定 CIDR 子网范围
    • 基本身份验证
    • 代理扩展

    repo: https://github.com/0x676e67/vproxy

    11 条回复    2025-02-22 08:16:21 +08:00
    dxatgp02
        1
    dxatgp02  
       16 天前
    学习一下
    heiher
        2
    heiher  
       14 天前
    支持~ 我有一个 C 语言写的 SOCKS5 Server https://github.com/heiher/hev-socks5-server ,用项目中同样的性能测试方法简单测了一下 SOCKS5 的 TCP 转发性能,Linux x86_64 平台,内存使用始终稳定在 77M ,1 路连接上传、下载速率都在 32GB/s 左右,CPU 使用 63-90%,10 路连接并发速率在 130GB/s 左右,CPU 使用 870-890%。
    proxyai
        3
    proxyai  
       14 天前
    基本的身份认证如何使用?
    0x676e67
        4
    0x676e67  
    OP
       12 天前
    @proxyai 查看`-h` or help 帮助命令就显示出来了,
    PTLin
        5
    PTLin  
       2 天前
    @heiher 老哥你这个挺牛逼呀,自己手撸了协程库,socks5 库,服务器库,代理库和隧道库。
    heiher
        6
    heiher  
       1 天前
    @PTLin Purely toys, just for fun. :)
    PTLin
        7
    PTLin  
       1 天前
    @heiher 这两天把你的协程库看了个大概。hev_task_execute 切换栈,hev_task_executer 和 hev_task_system_schedule 里 setjmp 前后对栈上 task/ctx 变量的维护和用其实现的协程切换确实很有意思。
    不过我有个疑问,比如 x86 下 hev_task_executer 中,setjmp/longjmp 只会保存和恢复保留寄存器以及 rsp rip ,怎么保证 longjmp 切换上下文后,hev_task_executer 后续读取 task 变量一定从栈上读的,确保 task 变量不会被优化成寄存器变量呢?
    0x676e67
        8
    0x676e67  
    OP
       1 天前
    @heiher 用 rust 的 tokio async runtime 已经到性能瓶颈了,大抵是要换 runtime 了,正好有数据对比一下。
    heiher
        9
    heiher  
       1 天前
    @PTLin 答案是各级函数调用的所有寄存器值切片都被保存并恢复了。具体展开来说,有通用寄存器的指令集架构一般会在调用约定中将寄存器分为 Caller-saved 和 Callee-saved 两类,在多级函数调用中每一级函数都可能会修改寄存器的值形成新的上下文状态。在函数中对于 Caller-saved 寄存器可以直接修改,因为 Caller 需要的寄存器旧值它自己保存了,而 Callee-saved 必须在修改前将旧值存入栈中。因此整个调用链绝大部分帧的寄存器值都已保存在栈中,只有最末级的 Callee 存在还未入栈的寄存器值。如果此时以这级作为 Caller 再调用 setjmp ,我们来考虑一下 setjmp 应该怎么实现,会发现它根本不需要保存 Caller-saved 寄存器,只需要保存 Callee-saved 寄存器以及一些并不属于以上分类且有可能被改变且影响上下文的寄存器,比如 sp 、pc 、各种 flags 等等。而后续 longjmp 回来恢复这个调用链的上下文时,也只需要再恢复 setjmp 中保存的那部分寄存器值,这样随着这个调用链再逐级弹出,所有寄存器值的完整切片均能被恢复出来。
    PTLin
        10
    PTLin  
       15 小时 57 分钟前
    @heiher 感谢回答,我也是太久没接触过调用规范了,一时间有点懵了。
    总结下,这分为三种情况
    1 变量在 setjmp 后从栈读取。
    2 变量在 setjmp 前后都是从保留寄存器( callee saved )读取。
    3 变量在 setjmp 前后都是从临时寄存器( caller saved )读取。
    第一种情况自然万事大吉。
    第二种情况,setjmp 会保存 callee saved ,longjmp 会恢复 callee saved ,所以寄存器值始终正确。
    第三种情况,在 call setjmp 前就会把变量所在的 caller saved 寄存器压栈,而在 setjmp/longjmp 返回后会把变量代表的 caller saved 寄存器弹出。所以寄存器值始终正确。
    PTLin
        11
    PTLin  
       15 小时 38 分钟前
    @PTLin 当然不是说 2 3 这些变量 setjmp 前后一定就在寄存器里,也可能一开始由寄存器表示,随着指令的执行因为某些原因被压入到了栈中,但是最后当使用的时候总是会正确的从栈中复原出来。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2402 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 15:54 · PVG 23:54 · LAX 07:54 · JFK 10:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.