推荐一个不错的 Cplusplus 网络库

2022-09-03 14:58:51 +08:00
 justanetizen

https://yasio.github.io/yasio

2412 次点击
所在节点    程序员
22 条回复
laoyur
2022-09-03 17:15:20 +08:00
链接不对
cnbatch
2022-09-03 17:24:09 +08:00
目录列表有个醒目的“粘包处理”

很好,看来又开启了 V2EX 流量密码
cnbatch
2022-09-03 17:39:10 +08:00
看了下 FAQ ,又发现“TCP 粘包处理”。这是 V2EX 老生常谈的话题,略。

再粗略搜了下源码,发现它并不使用各系统的异步 API (IOCP / kqueue / epoll / io_uring 全都未使用),而是使用 O_NONBLOCK + std::thread 来达到“异步”的效果。

重新看了下介绍,“专注于客户端”。原来如此。
justanetizen
2022-09-03 19:52:41 +08:00
@cnbatch 客户端的重心不在并发,而在 gui 的 fluent ,多线程是必需的
cnbatch
2022-09-03 22:19:21 +08:00
行吧,我来拆拆潜台词:

客户端的重心不在并发——所以觉得没必要用系统自己的异步 API ,也不想用已有的各大异步网络库
而在 gui 的 fluent——所以只想关注 GUI 的交互,不想手动处理报文细节,也不想处理 TCP 流数据
多线程是必需的——由于没用到系统异步 API ,只能选择多线程去处理
justanetizen
2022-09-03 23:31:13 +08:00
@cnbatch 我是一个 emacs 用户,对 C/C++原生桌面软件比较熟悉的也就 emacs 了,虽然经验不算资深,但断断续续接触 emacs 也快十年了(扯远了),之所以说到多线程,刚好 emacs 很大一部分的卡顿原因或者问题源头就是因为其单线程架构,emacs 社区(包括中文社区)最近也在讨论其单线程架构和解决方向,至于你说的其他什么异步 API 、粘包之类的,我相信不是什么难点,而之所以推荐那个库,我主要也是看到了其多线程、异步 IO 的特点,至于如何实现,我没有细看哈,我不🦌Cpp 的。
cnbatch
2022-09-04 18:13:30 +08:00
仅仅是因为“多线程”和“异步 IO”啊……

对于 yasio 的 FAQ 提到的其它网络库库 (asio libevent libev libuv) 来说,“异步 IO”本身同样就是标配,这没什么好说的。这几个库一样都支持多线程,其中部分默认多线程的库可以配置成单线程异步 IO 模式,默认单线程的库也提供多线程环境的支持。

可以说,如果仅仅只是“多线程”和“异步 IO”,那么另外那几个库同样达标,而且做得更好。

yasio 的“亮点”在于“粘包处理”(从 TCP 流数据中自动拆出所需数据),要不然它也不会醒目地单独放在目录列出来;以及内置 KCP 库(游戏行业比较喜欢使用 KCP 传数据),在“预处理器”那里有提到;还有跟部分游戏引擎的交互支持,在 Github 说明那里有提到。
这些显然不是你的关注点。
justanetizen
2022-09-04 19:52:56 +08:00
@cnbatch 爱用不用吧,那库也不是我写的,与其在这里和我硬杠,不如直接去人家 repo 提 pr
cnbatch
2022-09-04 20:01:32 +08:00
@justanetizen 并不是在杠,而是觉得你的关注点(是各个库都有的共性,只不过 yasio 列了出来而已)完全偏离了人家原作者的关注点(游戏行业的痛点),人家原作者并不是仅仅为了“多线程”而多线程、为了“异步”而异步。

我列了这么一堆字是告诉你原作者的关注点是什么。
justanetizen
2022-09-04 20:03:02 +08:00
@cnbatch talk is cheap, 上代码吧,只要能证明你说的是对的就行
cnbatch
2022-09-04 20:42:48 +08:00
真奇怪,代码本身就是开源的,介绍也是现成的,完全可以自己看的呀……
而且我前面那些,哪句话说错了?

也行,那就列一次出来,包括代码和它们各自的说明:

yasio:
首页自己的介绍:“专注于客户端和基于各种游戏引擎的游戏客户端网络服务”

内置 KCP:
https://github.com/yasio/thirdparty/tree/0264931f4af65f9532863d37c2cc206604d16918

游戏引擎支持:
https://github.com/yasio/yasio_unity
https://github.com/yasio/yasio_unreal

TCP 流数据拆包(“粘包”):
https://yasio.github.io/yasio/3.39.4/unpacking/

以上都是其它异步网络库不具备的。


C++asio:
https://think-async.com/Asio/asio-1.24.0/doc/asio/using.html
预定义 ASIO_DISABLE_THREADS 可关闭多线程支持。
即默认使用多线程。
至于“异步”,名字就说明一切了。

libev:
https://github.com/enki/libev/blob/master/ev.c#L768
https://stackoverflow.com/questions/14621261/using-libev-with-multiple-threads
http://blog.leanote.com/post/simon88/2f29107bd8dc (第三方博客)
https://developer.aliyun.com/article/801557
可以看出,能够自行选择多线程还是单线程模式

https://metacpan.org/dist/EV/view/libev/ev.pod
说明文档,搜索“async”可以看见异步的说明

libevent:
https://libevent.org/
人家首页直接就说了:Libevent can also be used for multi-threaded applications, either by isolating each event_base so that only a single thread accesses it, or by locked access to a single shared event_base.
关键部分—— [也] 能支持多线程
意思就是默认单线程,但同样可以多线程
更进一步的说明: https://quant67.com/post/ioevent/multithread-libevent.html (第三方网站)
如何使用 libevent 实现异步网络编程:
https://gist.github.com/ajhwb/3685796

libuv:
https://github.com/libuv/libuv
项目说明直接就写了出来:
Asynchronous TCP and UDP sockets
Asynchronous DNS resolution
Asynchronous file and file system operations
Threading and synchronization primitives
清清楚楚。
justanetizen
2022-09-05 12:37:58 +08:00
@cnbatch 周末在忙其他的,没空看你的回复,我搞不清楚你到底在反驳什么,或者在质疑什么,好像一方面你觉得那个库 ok ,但是,一方面又要告诉我别人关注的是什么,我之所以分享那个库,真就是觉得你们搞游戏那一行有点过于个人主义了,对待好东西就像你对待那个库的 attitude 一样,有点自我矛盾。
cnbatch
2022-09-05 16:15:28 +08:00
事先声明,我不是游戏行业。

首先,推荐某样东西,肯定需要跟大家说“为什么”、“好在哪”吧?尤其是标题写着“不错”两个字,那么是哪方面的“不错”?然而重新看看这个帖子,除了贴了个链接,什么都没讲。这给人一种很莫名其妙,甚至有一种“广告”的感觉。

第二,再看看链接,显然连接到错误页面了( 1 楼就有提到),会给人一种“敷衍”的感觉。不清楚这是 V2EX 的自动替换还是怎样。


既然没说好在哪,那就进去看看它的各种特点,并随意点评。

1, “TCP 粘包”这种说法早就被 V2EX 的各种讨论贴吐槽过很多次,总地来说大家的观点是,讲出“TCP 粘包”这种字眼等于主动引战,属于不专业的表现。

2 ,使用 O_NONBLOCK + std::thread 算不上“不错”,这纯粹为了省事,“能用就行”。再看一眼介绍,“专注于客户端”,难怪。由于是在客户端跑,一般只会建立个位数的连接,所以大多数情况下都无所谓,察觉不出。

3, 为了搞清楚为什么作者会“偷懒”,自然要进去看看它的介绍,包括 Github 页面。看完后发现,原来作者的着重点并不是单纯的“异步”,而是为了给游戏同行提供一个集成化的、一站式的解决方案,免得每次使用其他异步库时都需要重新手写代码处理诸如“TCP 流数据拆包”、叠一层 KCP 库、游戏引擎交互之类的麻烦事。

看得出,作者的精力都放在游戏引擎交互、游戏脚本语言的交互、游戏行业常用网络功能的整合。

结论就是,这个库是专门为游戏行业量身打造的。它所带的特色功能,其他人几乎用不上。



接下来,你从 emacs 解释了为什么会关注这个库,原来是因为“多线程”和“异步 IO”的支持。

既然如此,那我就只好作出提醒,支持多线程和异步 IO 支持是各大 C++网络库的基础性操作,并不是特色、特点,也不是专属优点。
除了前面提到的另外 4 个库,实际上其他的 C++网络库,或者带网络支持的 C++库,也是这样。

比如阿里巴巴的 PhotonLibOS:
https://github.com/alibaba/PhotonLibOS/blob/main/net/kernel_socket.cpp
搜索下就可以看到,用了 pthread (多线程),epoll (异步 IO )
justanetizen
2022-09-05 16:35:10 +08:00
@cnbatch 你说的对,以后不乱推荐了 :)
deal11
2022-09-06 00:02:25 +08:00
异步只是结果或效果,epoll/kqueue/io_uring/iocp/poll/select+非阻塞 socket 可以实现,线程+阻塞 socket 也可以实现,协程也可以实现
deal11
2022-09-06 00:27:31 +08:00
游戏里的处理耗时事务,例如大量资源加载,分帧加载也是实现异步的一种思路,可有效避免界面卡顿。
不管是 iocp/epoll 等,还是 select/poll 都是实现多路 io 复用模型的方式,只是前者适用于实现高并发的服务器,后者多数情况下更适合适用于客户端,但无论如何,离开 nonblocking io(socket),高并发是空谈,异步 io 也是空谈。
deal11
2022-09-06 00:33:04 +08:00
当然,线程+阻塞 socket 也能实现异步,但线程资源更昂贵,这也是个各操作系统提供类似 epoll/kqueue/iocp/io_uring/select/poll+非阻塞 socket 多路 io 复用模型的原因。
deal11
2022-09-06 00:43:48 +08:00
O_NONBLOCK + std::thread 算不上“不错”,这句话有误导。任何程序都离不开线程,libuv,asio 等离开 thread 也啥都干不了,任何进程至少有一个线程不是。std::thread 只是一种封装接口。看 yasio 文档,可以通过 YOPT_S_NO_THREAD 禁用内部创建线程,这样,所有网络消息和事件都在 io_service.run 调用者线程执行,至于这个线程是进程主线程还是其他线程,就取决于用户业务了。

tips: asio 的多路 io 复用模型 backend 也有 select 的实现,只是默认都用各平台高并发模型 epoll/kequeue/iocp/io_uring ,但可通过编译选项禁用他们,然后 fallback 到 select
deal11
2022-09-06 00:45:55 +08:00
@deal11 YOPT_S_NO_NEW_THREAD
deal11
2022-09-06 16:12:41 +08:00
我猜题主之所以关注到 yasio ,是因为该库 github 标题提到: "any client applications"

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/877455

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX