Sucha's Blog ~ Archive for January, 2015

15年1月30日 周五 12:42

有关 GLFW

这段时间做的项目是使用 GLFW 来做跨平台的播放器,大体上框架已经好了,音视 频也同步了,大概花了快两周时间,然后也是今天才知道 cocos2dx 3.x 系列是用 glfw 来做 opengl 窗口管理的,我是没有继续深究了,不过因为看到这个,忽然 有种我选得没错的感觉。

GLFW 横跨 Mac/Win/Linux 三个平台,提供基于 OpenGL 渲染窗口,消息机制,这 点很不错,大体上统一了三个平台基础 OpenGL 的创建,销毁,以及鼠标、键盘消 息。

我之前因为想学习 OpenGL,看到的很多国内教程都是 glut 来入门,而且还是 OpenGL 2.x 系列的 API,实际上,现在都已经是 3.x 系列的 API 了,当然系统 总是向下兼容的,老的 API 也能用就是。

若是现在开始涉及到桌面 OpenGL 部分的,强烈推荐呀。

15年1月15日 周四 01:34

获取默认网卡的 IP 地址

目前在做一个简单的服务端程序,需要客户端发现服务端的 IP 地址,然后请求链 接。发现部分是用 UDP 的广播来做了,但是服务端获取 IP 地址部分,遇到了问 题。

服务端里面 TCP bind 时,地址是可以为 INADDR_ANY 的,意味着不管是哪个网络 过来的数据,只要路由到系统,端口对应上,我的服务端程序就可以 accept。看 起来美好,但是流程上走不通,这时候程序其实是不知道 IP 包是从哪个网卡过来 的,所以即便接收到了客户端的 UDP 广播请求,也仍然无法发送可以连接的 IP 地址给客户端,因为从系统里面获取地址的 getsockname() 获取的其实是之前 bind 的地址,也就是 "0.0.0.0"。

路由都已经通了,但却无法获取路由过的网卡 IP 地址。如果这一切都只能通过之 前的 bind 来显式地指定只接收某个网络过来的包,确实是太折腾了。

简单点,不如就是用系统默认网卡的 IP 地址好了,至少系统保证这个是最为可用 的地址。

MacOS 下获取系统网络设备名称以及地址跟 Linux 下的相似,都是 getifaddrs(), 搜到了一篇中文介绍;然后获取系统默认网卡的信息,我是从 stackoverflow 上 面搜到的。

这样,bind 的时候仍然可以为 INADDR_ANY,客户端 UDP 广播请求的时候,服务 端大方发送可连接的 IP 地址。扯远点,复杂点的情况,多个网卡,多个异构网络, 服务端可以根据具体的请求发送不同的 IP 地址,只要能路由过来,都可以 accept。

大概就是这个意思了吧。

15年1月3日 周六 11:19

HTTP Downloader

忙了两天多那个 HTTP Downloader,原来只是想实现一个 keep-alive 的连接的 socket,当时也想到这个东西不会简单,因为一方面底层的是 low level 的 socket,另外一方面呢,需要处理一层 http 协议,还有一个 dns。

后来是因为找到了 dns 的代码,就开工了,才发现复杂呀,一方面 c 的部分我觉 得我大意了,编码不够小心,各种折腾。

另外就是 c 的 string 库太不好用了,所以不得不封装了一个,至少得有 split 这个函数吧,没有的话啥都不用玩了。

其实大概一天不到基本的 http get 已经完成了,只是代码太糟糕,我觉得需要改 进一下,最主要的就是 string 库,于是昨天折腾了快一天呀,代码清晰了很多。

这个 string 库是有 gc 的,从 head 操作产生的其他 object,都会随着 head 的 destroy 而 destory。新建 head 的 interface 就那么几个,很有限,所以其 实可以在开始复杂操作时新建 head,之后后清除掉那个入口的 head。

新建 head 的接口除了 malloc 一段 cstring,还可以 map 一段 cstring 地址给 它作为操作的空间,这时候内部标记 clone,就是这个 mstring 的 cstr 地址不 是自己保存的,之后的 destroy 不用释放这个空间,对于像 http head 或者 body 的分析时,这个就很有用了。

由于新建 mstring 的空间其实是堆上的,对于各种小操作时产生的 mstring,不 大好,还不如 cloudwu 那个栈上的方式,栈上的方式新建轻松,而且没有碎片的 产生。

不过呢,就是得随时注意,这些栈上的对象何时销毁,需要的时候需要转成堆上的 对象。

我有个想法,其实这些小碎片,不如申请一个专用的堆来操作,比如这个堆绑定在 head 的 allocator 上,从 head 产生的所有 object 都是用这个 allocator,这 样就避免了大量的小对象,对于内存碎片的控制是有益的,特别是对于那种 map cstring 过来的对象,因为本身 cstring 空间是不用释放的,这时候就很有用了, 因为 mstring 自己控制用的结构,空间占用不大。

不过呢,新建的 heap 多大才有用而又不至于浪费,那就又是另外一回事了,以及 这个接口如何提供的问题,这个想法还得斟酌一下。