Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

伺候 libuv 时踩过的那些坑 #66

Open
ssrlive opened this issue Aug 27, 2019 · 3 comments
Open

伺候 libuv 时踩过的那些坑 #66

ssrlive opened this issue Aug 27, 2019 · 3 comments

Comments

@ssrlive
Copy link
Member

ssrlive commented Aug 27, 2019

使用 libuv 阶段性总结, 提醒后来人少走弯路.

  • 支持 Android 平臺的 VPN 應用
    提交了一個 PR 由於 libuv 作者不願爲單一用戶的單一平臺增加一個新 API,這事一直被拒絕。如果你是個開發者,並且被同樣的問題困擾,可以到這個 PR 下留言,敦促 libuv 作者合併這個補丁。這個補丁是這樣的:libuv 的實現中,調用 socket 函數創建一個套接字後,就馬上連接遠端服務器;在 Android 中,如果你的手機正處於 VPN 環境,所有連接遠端服務器的連接都會劫持到本機的VPN監聽端口,除非你創建套接字後馬上調用 VpnService.protect(int socket) 函數,連接遠端服務器才會正常,這裏是個例子 toyvpn 。這個補丁就是給 用戶一個機會,當 套接字 甫一創建,就調用用戶的關於 protect 的代碼,然後才連接遠端服務器。希望大家都去那個 PR 下留言支持,讓它最終能夠合併到主分支。

  • 写入 socket 时的内存管理
    uv_write 函数写网口时, 写入数据的内存必须由你分配、管理, 在 回调函数 uv_write_cb 内部释放. 如果你不信邪, 在 uv_write 执行完以后马上释放, 恭喜你掉坑里了. 我就在这坑里呆了一星期. 因为这么干的结果是, 在 Windows 下一切正常, 在 Linux 下会随机写失败. 估计 Windows 对这块写内存复制了一份以增加安全性, 类 unix 平台就不管你死活了. 这点差异性足以逼你发疯痛不欲生了.

  • 接收数据包 回调函数 的状态值处理
    uv_read_start 函数的回调是 uv_read_cb , 它有参数 ssize_t nread, 这个 nread文档 里说得极其简略, 实际它非常重要, 每一种值都必须妥善处理. 当 nread 等于 0 时, 表示 socket 正忙, 你就啥也别干, 直接返回, 这时读取动作还会继续, 直到读成功 (nread > 0) 或读失败 (nreqd < 0) 或读完 (nread == UV_EOF) , 这个回调会再次被调用.
    我就是没有正确处理 nread==0 的情景, 被坑得很惨. 直接的后果就是, 刷推时老是刷不下来, 带图片发推时总是失败. 浪费巨量时间.

  • 连接服务器函数的返回值处理
    uv_tcp_connect 函数返回值的检查极其重要, 见 这个 isuue. 如果你不处理它小于 0 的情况, 释放为这个函数分配的资源, 那你永远没机会了, 因为回调函数 uv_connect_cb 再也不会被调用. 造成资源泄漏. 如果你网络碰巧不通, 恭喜你, 短时间内大量的连接请求从客户端涌进来又马上失败但没有释放内存,系统内存会迅速耗光, 蓝屏死机, BSOD. 耶! ✌️! 也!

  • 关于函数 uv_close
    文档里说得很清楚, 必须在 uv_close_cb 回调里 或者之后的某个时候 释放资源, 为了做到管理资源的自动化, 我们可以借用 COM 的理念, 采用 引用计数 和 AddRef / Release 大法 来管理资源. 即, 在调用 uv_close 之前对资源 AddRef, 在 uv_close_cb 里面 Release 释放资源.
    绝对不要给 uv_close 传入 NULL 空回调指针, 否则你会死得很惨.

  • 同步函数的跨平台陷阱
    uv_mutex_t 在 Windows 下其实就是 临界区, 临界区 是可以重入的. 而在类 unix 系统下是 pthread_mutex_t, 它是不可重入的. 一个代码块, 用同一 uv_mutex_t 多次锁定, 这在 Windows 下毫无问题, 在 unix 下就把你的程序卡得死死的.

  • 不要使用 uv_idle_t
    uv_idle_t 这玩意儿会导致事件循环退化成 busy loop, CPU 瞬间飙满 100%, 非常恐怖. 绝对不要在生产环境里使用. 想要实时监控你程序内的某状态值, 请以定时器 uv_timer_t 代替. 参看 未有代理连接时,树莓派4客户端 cpu 30% #19171fae15

如果你踩过其它什么坑, 欢迎回帖, 充当后来人的灯塔, 照亮大伙前进的路.

@ssrlive ssrlive changed the title 与 libuv 共处时踩过的那些坑 伺候 libuv 时踩过的那些坑 Sep 6, 2019
@twodom
Copy link

twodom commented Sep 20, 2019

大佬牛逼

@ssrlive
Copy link
Member Author

ssrlive commented May 18, 2020

另外一个大坑, 不是 libuv 的, 是 SOCKS5 的, 为方便检索, 链接放这里.
#68 (comment)

@jiakai1000
Copy link

http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb 文档里提到了的

@ssrlive ssrlive unpinned this issue Jun 1, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants