Sucha's Blog ~ Welcome

18年6月24日 周日 10:53

Timer、FastLZ & Erasure Codec

上次说到网络库的 timer,总觉得直接塞入网络库不是个好主意,一方面不是所有 的程序都需要 timer 来协助,另外一方面 timer 用途其实更广泛,可以放到更底 层的逻辑里。

实际是将其实现在 m_foundation 里了,接口提供创建多个 timer 序列,往具体 某个序列加入 timer 及其回调的时候,保证有序,这样每次 update timer 列表, 可以直接检查排在最前面的 timer 是否超时,不需要检查全部;另外,如果到期 时间冲突,解决的办法是开链表,同个到期时间的 timer 可以都排在一起。

保证有序的方案算法是使用 skiplist,时间复杂度为 O(log2n)。

另外,虽然是 timer,但实际设计是不考虑时间单位的,时间单位都由外面提供, 外部在 update timer 时,同时更新最新的时间单位就好;使用了 64bit 来表示 时间单位,表达空间应该足够了。

FastLZ 是个有很长时间未更新的库,这里的压缩,将其放在了 m_tunnel 这一层, 与 kcptun 不同。主要是看到了 snappy 用的 C++,包含太多文件,效果未必必 FastLZ 好多少,因为数据量少,CPU 耗费也不大,所以就没有采用。

其实后来还看到更好的 lz4,没有更换的原因是,实际跑起来,大部分都是 HTTPS, 这些压缩其实绝大部分用不上。

FastLZ 最少需要使用 66 byte,感觉放在 UDP 长度 14xx 的 playout 里,太浪 费了,是没有放到 m_kcptun 的考虑之一。

还有另外一点是,不能压缩的数据在跑 compress 的时候,返回的长度要比实际来 源更长,这个时候可以果断抛弃不压缩,在 m_tunnel 协议里,有命令字可以区分 这段 data 是否需要解压,这样对协议双方来说,至少有一方可以少走一次 decompress 了,而传输数据量可以保证最少。

粗看了一下,lz4 没有说压缩时最少需要多少字节,以及 dest buffer 需要比src 大多少,貌似需要探测,这点不如 FastLZ;另外,snappy 及 lz4 的解压速度是 亮点,但实际上对于数据量少的,没啥影响;就 CPU 耗费以及压缩率来看,折衷 方案更好的是 zstd,可这个不是单线程的,代码量复杂度都会上去太多,不好管 理。

Erasure Codec 用的是 Reed-Solomon,当然不是最新最先进几乎触摸到香浓极限 的算法。本来找到一个可用的,但是太耗 CPU 了,最后是找到一个使用 Cauthy 码的 cm256,网络上传输太不确定,TCP 仅保证了传输次序,内容校验有限,如果 上层发现数据错误,要么抛错误,要么重新传输,后者意味着又得重新发一次数据, 以及来回的时间耗费,不够经济。

另外,如果链路上一定会发生错误,就需要 Erasure Codec 了,要不会一直失败。 最后是使用了 payload 较高的 RS(11, 2),接近经典的 RS(239, 16),由于协议 本身也需要保证,因此 Erasure Codec 放到了最底层,UDP 之上直接装载。

多个协议下来,UDP 14xx 实际可以使用的数据量,payload 就更少了,也是没办 法。

CategoryProgramming / Permalink

18年6月9日 周六 00:58

老笔记本换 CMOS 电池 & Nexus 7 换 USB 尾插

这台笔记本是工作还不到半年,信用卡下来之后,透支买的,那块 CMOS 电池到现 在已经撑过了 10 年。最开始是作为开发用的机器,后来慢慢淡出,最后是安装了 Linux 变成不常开机的服务器。

最近是烦了那开机后必响的 BB,琢磨着应该是电池的问题,淘宝 ¥15 了一排 CR2032,百度了一下 BIOS 电池的位置,当然是开腔才能具体位置,换了之后其实 还是会响,需要重新设置一下 BIOS 时间才行。

Neus 7 是 12 年的一代,当时是因为分辨率才下定了觉醒,这个价格这个分辨率 是可以的,因为是给家里人用,电量变得越来越不济,后面干脆是 mini USB 口接 触不良,充不上电了。

同样是淘宝,同样是 ¥15,只是 Nexus 7 不好打开外壳,费了一点劲;还有就是 螺丝都太小了,华强北 ¥25 的小工具盒太勉强,当然最后还是换了。

CategoryMisc / Permalink

18年5月1日 周二 22:30

m_dnscnt 和 lua-web

前一阵子写了一个 m_dnscnt,一个并发多个 DNS 请求的客户端、库接口。

有这个需求的原因,在于系统提供的 DNS 请求是一个同步接口,开始请求后,得 等着 DNS 结束才能走下一步。

这带来两个问题,第一个问题是,如果我同时有 3 个 DNS 请求,总共花费的时间, 是这 3 个请求加起来的总和;第二个问题是,因为底层的网络库是异步的,不能 因为 DNS 请求是同步的,就将整个循环给阻塞住,因此实际是多开了线程才能用 好这个 DNS 请求接口,也因此多了一个 STM 同步操作。

并发、异步的 DNS 请求库,则没有这个问题。

当我将 m_dnscnt 以源代码接口的形式用到了 m_tunnel 上去后,感觉服务端 DNS 请求加快了不少,毕竟之前得一个一个顺序请求 DNS,现在则是同时请求多个,总 的花费时间大大缩短了。

另外呢,也将这 DNS 以库的形式用到了 lua-web 上去。以库的形式加入 lua-web 的原因是,m_net 本身已经用库的方式提供了 Lua 绑定,无法在同一个库里面暴 露接口给 m_dnscnt 使用。所以 lua-web 底层使用了两份 m_net 代码,其中一个是 单独用于 DNS 请求的。

这样 lua-web 就支持了 HTTP request,之前不支持域名,只支持 IP,现在则没 有这个问题了。

而在架构上,HTTP 层的支持算是完整了,如果以 web-framework 的要求看的话, 后续还需要 HTML 的支持。如果还需要加上一点,那就是 HTTPS 的支持,以及 websocket。HTTP/2 呢,就算了,那完全是另外一个东西。

还有,这些个东西,往后再说吧,目前的目标,并不是做一个 production-ready 的东东,而只是做一个类似教学用的工具,做个小巧,但五脏六腑清晰明了,可以 一眼看穿,但又确实可用的东西。

CategoryProgramming / Permalink

18年3月30日 周五 23:49

换回 suchang.net

再次换回 suchang.net

CategoryThisSite / Permalink

18年3月19日 周一 01:06

True Life

前几天在推上看到这个新闻蛮惊讶的,当时看的是英文来源,里面的信息跟 中文报道有很大的不同。

想起二十多年前听到信息高速公路时是完全不理解,十多年前开始慢慢接受电脑进 入普通生活,改善工作效率的同时,也开始沉迷虚拟游戏中的各种。

可是现在呢,微博、微信、抖音、视频,各种虚拟场景占据了一天中那么多时间后, 也许网络中过得好不好要比被微信、工作IM撕裂的所谓现实生活更重要吧。

自从微信变成工作IM,特别是各种下班后,以及类似今年情人节那样被硬生生被拉 到一个微信群里解决bug到晚上九点多,我也终于理解自己不喜欢微信的原因。

还好家人都爱打电话,再说家人的微信群我也不爱看,根本都不回,打字太累了, 就像这篇打了大概有2个小时。

所以,看到这篇新闻后先是惊讶,对照自己的生活后觉得羡慕,也知道再也不可能 回退到,如新闻中加纳人的史前生活。​​​​

CategoryReading / Permalink

18年3月5日 周一 00:06

m_net 支持 FreeBSD

使用家里旧电脑配件新搭了一台 FreeBSD 后,开始跑程序,因为 FreeBSD 在网络 接口层面跟 MacOS 是很相似的,同样是 kqueue,所以修改比较小,只需要新开一 个宏定义,包起来的区域跟 MacOS 一样就行。

在这个基础上 m_net 开始支持 FreeBSD 了,同样的 m_tunnelm_kcptun 也开始 支持 FreeBSD 了。

其实不用修改啥,想着其实还不如支持大端需要修改的东西多,可是目前没有平台 跑大端,所以这个想法等实际需要后再说吧。

CategoryProgramming / Permalink

18年3月4日 周日 23:53

开始接触 FreeBSD

过年在家发现了两台旧电脑,是之前给家人安装新电脑后,各种拆装后剩下的,清 点了一下,CPU 是 I3 2300 之类的,主板华擎,内存 4G DDR3,这个配置感觉还 是可以的,MicroATX 架构,就想着不如搬到深圳,搭一台 FreeBSD 学习一下。

还带上了大学时就开始服役的 80G 希捷硬盘,由于是 IDE 口,这个硬盘没条件在 家测试了,其他部件包括电源,正常跑起了 BIOS。

到深圳后,只需要淘宝一个不带电源支持 MicroATX 的小机箱,大概 70 块这样, 因为忘记电源线,因此多破费了 20 块,不到 100 机器就可以跑起来了,感觉还 可以。

计划之外的是,那个 80G IDE 接上了淘宝的 IDE 转 SATA 小板,还是没法使用; 还好手头有一个 320G 的 USB 移动硬盘,说是用来备份的移动硬盘,可是很少使 用,年龄也很大了,10 年买的。

于是拆了硬盘盒,欣喜地看到了 SATA 口,愉快接上吧。

FreeBSD 的安装很傻瓜,我唯一不理解的是分区,貌似不能像我在 Linux 那样 给 home 单独分区,这样随便我折腾系统都没关系了。

pkg install 用起来也很溜,开了 samba 后,同样可以当成一台备份服务器,就 是速度要比用 USB 口传输慢了许多,好处是之前的 USB 口其实接触很不稳定,经 常跑不起来,所以其实我也不太想用这个备份的移动硬盘。

CategoryLinux / Permalink

18年1月1日 周一 23:56

电影芳华

今天安利家人电影,被迫接收了十几分钟的评论,脑袋要炸,下次不能随便安利了。

我评五分的电影被家人跟战狼2并列,说当时能进文工团的都不是普通人,且军分 区的子弟都能进部队,部队条件也很好。

所以影片表现的是当时极好的条件了,相比呢故事比较一般,都是普通的小事,戏 剧性不够,还不如我们普通人的生活。

我认同最后一点,可也许导演是故意的呢,毕竟整个主线是表现那个时代的风貌, 里面的任何人都不能被聚焦太多。而整个大的故事框架,是在类纪录片平静的语调 里展开的,基调是不能大褒大贬,这也就限制了里面人物的戏剧表现力了吧。

里面的很多镜头挺美的,有很多现场感很强烈的手持镜头,小可惜是开头那个镜头 没有一镜到底,另外画面风格被特殊处理为那种胶片的风格(也许就是胶片机拍的 吧),小缺点是里面的艺术表现被拔高了,毕竟这是文艺片而不是纪录片吧。

总的来说,比战狼2给我的观后感更为强烈,评分也就更高了。

CategoryLife / Permalink

17年12月2日 周六 11:56

Emacs 升级到了 25.3.1

Emacs 升级到了 25.3.1,因为许久没有写这个 blog,忘记了应该用什么命令来加 入 entry,还以为是 emacs-wiki-journal 用不了了,不兼容了,开始杞人忧天。

升级 Emacs,是因为黑苹果想升级 10.13 而不得,不得已重装了系统,又回到了 10.12,然后看到了一个不错的模块,貌似是可以保存窗口大小的,依赖于新版的 Emacs,之前一直觉得蛮需要这个的。

只可惜,重装完系统后,这个模块叫啥名字,又忘记了,蛋疼。

不过 Emacs 总算跟上了新的版本,记录一下吧。

CategoryMisc / Permalink

17年12月2日 周六 11:49

More Than Human

​​这几天接连看了几个机器人相关的报道,比如后空翻的 这个,以及机器狗,不得 不感叹就机体性能而言,这个进化速度实在太快了,如果再考虑能量效率,就更不 用说。

想起前一阵子看的《银翼杀手2049》,复制人K随着故事不断推进逐渐丰满,最后 让我隐约觉得某种意义上他比人类更像人类。

在现实中,随着软(硬)件行业不断重新规范整个人类社会,机器能接受、处理信 息的能力越来越强,逐渐数字化的社会将越来越有效率,只是这样的迭代发展真的 太恐怖。

完全数字化的社会,代表着未来人类从摇篮开始,将方方面面被数字包围,我们的 每一个毛孔、每一个行为都将被数字所记录、表达,数字就是我们,我们就是数字。

我们现在就已经非常依赖于这些流动的信息,它们太方便,太智能,太有效率。只 是这些流动的信息,会让我们不知不觉生活在楚门的世界。没有数字化的信息,甚 至被认为是不够准确、真实的。

这些信息的重要,在于它记录了我们的过去、预测我们的将来。所谓的过去,不只 是过去的行为,它们还将深入了解我们的基因,我们上一代的方方面面;所谓的将 来,不只是我们当下可能的选择,还有我们未来的方向。

这些信息,包含了我们坐椅的高低,空调的温度、鞋子的尺码、衣服的款式及材质、 软硬舒服程度、上班的时间线路、午饭的餐品喜好,我们获取信息的方式、跟陌生 人打交道的方法,还有每天跟父母、恋人的电话次数、说的每一句话、在微信里发 的每一个字、每一个表情,我们会如何表达爱意,期待着对方的回应是有趣、深邃、 严肃、活泼、认真、机智、幽默、浓烈、冷淡、走心还是走肾的。

我们会很开心、并最后习惯于每天这么方便的生活,每一句谈话都这么舒服,每一 次交流都这么温暖,再好的上帝也不过如此吧。可也许我们有意无意间终会知道, 我们所面对的,可是掌握了我们相关的所有信息,体测500KM起,几乎不休息,也 不挑食,一顿饭的时间以秒计,吃完了可以再跑500KM的机器人。

在任何一个方面,人家可根本不把我们看在眼里。​​​​​

CategoryReading / Permalink

17年9月5日 周二 00:59

有关 m_net 跨平台的小型网络库

最近一直在玩 m_net,当然总是处于修修改改当中。

很早就有参考 dyad 这个优雅到不行的网络库,C89 的语法,接口设计清晰明了; 仅针对 TCP 抽象为 Stream;对于 socket 的状态变化,设置为事件监听接收处理; 简单粗暴的 SDK 接收数据再发通知,buffer 地址以及数据 size 直接送到用户手 上,接收部分则随着数据增大,而不断 realloc 出来;读写接口还加上了方便的 基于 C string 的处理。

基于这一套网络库构造的 demo,简明得不行,比如首页的 echo server。

且后者还提供了 timer。这个 timer 的实现,其实基于 select 对于阻塞 socket 的监听。

m_net 历史,最早是从 13 年做游戏时弄的一个单独处理 socket 的接口,当时写 得很挫先不说。后来慢慢发展,看到了 dyad 后,大量参考了 dyad 的设计。比如 抽象了 win 下的接口,使用 select 处理三个平台的 socket 事件,不同的是, 一开始就包含了 TCP、UDP 的支持,一开始就是非阻塞的接口,对于 socket 则命 名为 channel,简称 chann。

但后来 m_net 在不同平台采用了 kqueue、epoll 的实现,接口以及处理上就很不 同了,代码量也增加了很多。状态关注点少了不少,从事件数量上就可以看出来。

最近 m_net 的更改,是将 C 这一层的接口整理了一下,增加了两个 utils。一个 是用于 resolve host 的函数处理 host name 到 ip 的转化(DNS);另外是单独 对于 ip:port 这样的字串,加入一个 parse 的接口,分割拿到 ip 跟 port。

把 C 的这一层命名为 core 之后,在 C 接口的基础上,抽象了 C++ 的 wrapper 对象,有三种 ChannAddr,Chann 和 ChannDispacher。

分别用来处理地址部分,chann 的数据、状态处理,以及所有 chann 的事件监听、 分发。抽象的结果,是在 C++ 这一层,比如针对 client、server 的处理,可以 类似 C 一样设置一个事件函数,或者继承 Chann 父类,封装专门处理 client、 server 的子类,所有的事件、数据都在子类的内部流转,容易理解,易看易懂。

C++ 支持了闭包后,单纯的 listen 接口不需要外建函数,或者派生子类,只需构 造一个闭包处理就好,方便了很多。

但是跟 dyad 还是有很大差距的,巨大的差距,在于对于数据的处理,m_net 不会 在 recv 事件(数据到达)的时候帮用户接收数据,所以用户任何时候去 recv 数 据,都需要自己准备一个 buffer,跟平常的 socket recv、send 没有什么不同。

这个代码量就出来了,且 buffer 处理的优雅与否,比如针对不同的 protocol 抽 象,是巨大的考验,我目前没有好的想法。

暂时是不想跟 dyad 一样帮用户处理了,我觉得这样也不好,比如不断读取然后 append 到已有的 buffer 上,大小不够了向系统要,不断 realloc 也很颓。

m_net 没有对 recv 先接收处理,但是对于 send 部分,如果 socket 只是反馈 would block,而不是其他的不可恢复的 error,则 SDK 会构造 buffer 存入用户 数据,待 socket 可写后再慢慢 drain 数据。

目前没有设置阈值,上层可以一直写,一直到内存耗尽,不知道底层其实 socket 虽未断开但已经无法写入很久很久了。

可以考虑设置某个阈值,比如 16M 的时候,给上层一个 EAGAIN 之类的,目前先 不管。

另外重要 feature,比如 timer 部分目前是没有的,由于所有 socket 都是非阻 塞,如果仅仅在事件循环的时候获取当前时间,并走一次 timer chain,极端情况 下,CPU 时间片占用是很可观的,这也是我一开始避免加入 timer 的原因。

如果要加入 timer,那在这种情况下,我觉得,需要定一个最小的时间分割,一次 循环,不多不少,就走一个 timer circle,比如 10ms,每 10ms 获取一次事件, 或者多次循环获取一次,然后矫正,这个问题不大。

这种方案下,CPU 时间片占用方面才可以接受,上层事件的精确度也能够保证。

只是目前 timer 部分接口,如果 mnet_poll() 上面增加调用,感觉也不不是很好, 毕竟很多时候,是不需要这个 timer 的。目前一个 -1 的值设过去,有事件就突 击处理一下,没事件就死等待好了。

所以 timer 部分的接口,是集成在 mnet_poll() 之上,还是给用户一个选择,单 独的设置并处理,还需要斟酌一下。

CategoryProgramming / Permalink