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

推荐一个不错的 Cplusplus 网络库

  •  
  •   justanetizen · 2022-09-03 14:58:51 +08:00 · 2401 次点击
    这是一个创建于 819 天前的主题,其中的信息可能已经有所发展或是发生改变。
    22 条回复    2022-09-13 11:53:13 +08:00
    laoyur
        1
    laoyur  
       2022-09-03 17:15:20 +08:00
    链接不对
    cnbatch
        2
    cnbatch  
       2022-09-03 17:24:09 +08:00
    目录列表有个醒目的“粘包处理”

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

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

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

    客户端的重心不在并发——所以觉得没必要用系统自己的异步 API ,也不想用已有的各大异步网络库
    而在 gui 的 fluent——所以只想关注 GUI 的交互,不想手动处理报文细节,也不想处理 TCP 流数据
    多线程是必需的——由于没用到系统异步 API ,只能选择多线程去处理
    justanetizen
        6
    justanetizen  
    OP
       2022-09-03 23:31:13 +08:00
    @cnbatch 我是一个 emacs 用户,对 C/C++原生桌面软件比较熟悉的也就 emacs 了,虽然经验不算资深,但断断续续接触 emacs 也快十年了(扯远了),之所以说到多线程,刚好 emacs 很大一部分的卡顿原因或者问题源头就是因为其单线程架构,emacs 社区(包括中文社区)最近也在讨论其单线程架构和解决方向,至于你说的其他什么异步 API 、粘包之类的,我相信不是什么难点,而之所以推荐那个库,我主要也是看到了其多线程、异步 IO 的特点,至于如何实现,我没有细看哈,我不🦌Cpp 的。
    cnbatch
        7
    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
        8
    justanetizen  
    OP
       2022-09-04 19:52:56 +08:00
    @cnbatch 爱用不用吧,那库也不是我写的,与其在这里和我硬杠,不如直接去人家 repo 提 pr
    cnbatch
        9
    cnbatch  
       2022-09-04 20:01:32 +08:00
    @justanetizen 并不是在杠,而是觉得你的关注点(是各个库都有的共性,只不过 yasio 列了出来而已)完全偏离了人家原作者的关注点(游戏行业的痛点),人家原作者并不是仅仅为了“多线程”而多线程、为了“异步”而异步。

    我列了这么一堆字是告诉你原作者的关注点是什么。
    justanetizen
        10
    justanetizen  
    OP
       2022-09-04 20:03:02 +08:00
    @cnbatch talk is cheap, 上代码吧,只要能证明你说的是对的就行
    cnbatch
        11
    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
        12
    justanetizen  
    OP
       2022-09-05 12:37:58 +08:00
    @cnbatch 周末在忙其他的,没空看你的回复,我搞不清楚你到底在反驳什么,或者在质疑什么,好像一方面你觉得那个库 ok ,但是,一方面又要告诉我别人关注的是什么,我之所以分享那个库,真就是觉得你们搞游戏那一行有点过于个人主义了,对待好东西就像你对待那个库的 attitude 一样,有点自我矛盾。
    cnbatch
        13
    cnbatch  
       2022-09-05 16:15:28 +08:00   ❤️ 1
    事先声明,我不是游戏行业。

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

    第二,再看看链接,显然连接到错误页面了( 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
        14
    justanetizen  
    OP
       2022-09-05 16:35:10 +08:00
    @cnbatch 你说的对,以后不乱推荐了 :)
    deal11
        15
    deal11  
       2022-09-06 00:02:25 +08:00 via Android
    异步只是结果或效果,epoll/kqueue/io_uring/iocp/poll/select+非阻塞 socket 可以实现,线程+阻塞 socket 也可以实现,协程也可以实现
    deal11
        16
    deal11  
       2022-09-06 00:27:31 +08:00 via Android
    游戏里的处理耗时事务,例如大量资源加载,分帧加载也是实现异步的一种思路,可有效避免界面卡顿。
    不管是 iocp/epoll 等,还是 select/poll 都是实现多路 io 复用模型的方式,只是前者适用于实现高并发的服务器,后者多数情况下更适合适用于客户端,但无论如何,离开 nonblocking io(socket),高并发是空谈,异步 io 也是空谈。
    deal11
        17
    deal11  
       2022-09-06 00:33:04 +08:00 via Android
    当然,线程+阻塞 socket 也能实现异步,但线程资源更昂贵,这也是个各操作系统提供类似 epoll/kqueue/iocp/io_uring/select/poll+非阻塞 socket 多路 io 复用模型的原因。
    deal11
        18
    deal11  
       2022-09-06 00:43:48 +08:00 via Android
    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
        19
    deal11  
       2022-09-06 00:45:55 +08:00 via Android
    @deal11 YOPT_S_NO_NEW_THREAD
    deal11
        20
    deal11  
       2022-09-06 16:12:41 +08:00
    我猜题主之所以关注到 yasio ,是因为该库 github 标题提到: "any client applications"
    deal11
        21
    deal11  
       2022-09-06 16:20:08 +08:00
    @deal11 看 yasio 的源码,正是使用的 select + nonblocking socket 多路 io 复用模型,select api 几乎可以跨所有操作系统平台。
    deal11
        22
    deal11  
       2022-09-13 11:53:13 +08:00 via Android
    所谓系统级的异步 API, 目前已知:iocp 和 io_uring 吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2604 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 06:25 · PVG 14:25 · LAX 22:25 · JFK 01:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.