core_framework —— 基于libev的轻量级lua网络开发框架

栏目: C · 发布时间: 5年前

内容简介:在发表这篇博文的前夕, 还有一些小伙伴在提问一些以下相关的问题:等等, 以上问题会在本文中一一介绍.首先来聊聊情怀这个东西! 相信每一个行业内的从业者都或多或少有过一个梦, 这个梦叫做: "我到时候要开发一个XXX"!其实作者当初也是一样.

在发表这篇博文的前夕, 还有一些小伙伴在提问一些以下相关的问题:

  1. 性能怎么样?

  2. 是否容易上手?

  3. 开发目标在哪?

  4. 如何反馈问题?

  5. 对比行业内的 lua 开源项目有何优势?

等等, 以上问题会在本文中一一介绍.

CF的起因

首先来聊聊情怀这个东西! 相信每一个行业内的从业者都或多或少有过一个梦, 这个梦叫做: "我到时候要开发一个XXX"!其实作者当初也是一样.

每当半夜(凌晨)在加班、看文档、调试的时候, 总会搜索到一些几年前或十几年前的框架或入门demo。例如: tinyhttp , 链接的源码是一些同学fork的镜像站。

每次看到这些内容或多或少都会激起心中那一丝丝快熄灭的热情, 也许这就是最后对技术的渴望?

就是在动手创建项目之前还反复问过自己是否要做? 能坚持下去么?也许被喷都是一种奢望?

在心里一一回答了这些问题后, 在2018年末创建了 本项目 .

说句实话! 一个网络开发框架最难的不是实现某个功能, 而是从零开始一步一步添砖加瓦的造轮子!

作为一个网络开发框架, 最重要的两个功能肯定是需要的! 定时器库、事件驱动库. 如何抉择?选项有2个: libev / libuv .

libev 成熟稳定、轻量级、unix like支持、容易嵌入;

libuv 比libev更加优秀,增加了许多功能(线程池、信号、同步、锁等等),封装更加完善, 并且增加了windows支持;
复制代码

从cf框架开发之初选型来看, libuv绝对是目前最优解. 但是作者偏偏选择了libev. 也从此开始, 艰辛的底层开发之路就此展开.

首先, 作者不让使用者C/C++进行实际业务开发! 这样做会让使用者有较高的开发成本与学习成本, 而选择一门较好的脚本语言就显得尤为重要.

作者对Lua还算是稍微熟悉一点, 所以就选了Lua作为业务脚本语言。至于Lua语言的优势这里就不说了, 网上大把文章夸它的.

现在既然脚本语言已经选定, 那么就开始写代码吧!Let's Lua.

CF的编写之路

1. 网络层

首先, 我们来看一段C封装给Lua调用的API代码:

LUAMOD_API int
luaopen_tcp(lua_State *L){
	luaL_checkversion(L);
	/* 添加SSL支持 */
    SSL_library_init();
    SSL_load_error_strings();
    // CRYPTO_set_mem_functions(xmalloc, xrealloc, xfree);
    // OpenSSL_add_ssl_algorithms();
	/* 添加SSL支持 */
	luaL_newmetatable(L, "__TCP__");
	lua_pushstring (L, "__index");
	lua_pushvalue(L, -2);
	lua_rawset(L, -3);
    lua_pushliteral(L, "__mode");
    lua_pushliteral(L, "kv");
    lua_rawset(L, -3);
	luaL_Reg tcp_libs[] = {
		{"read", tcp_read},
		{"write", tcp_write},
		{"ssl_read", tcp_sslread},
		{"ssl_write", tcp_sslwrite},
		{"stop", tcp_stop},
		{"start", tcp_start},
		{"close", tcp_close},
		{"listen", tcp_listen},
		{"connect", tcp_connect},
		{"ssl_connect", tcp_sslconnect},
		{"new", tcp_new},
		{"new_ssl", ssl_new},
		{"free_ssl", ssl_free},
		{"new_server_fd", new_server_fd},
		{"new_client_fd", new_client_fd},
		{NULL, NULL}
	};
	luaL_setfuncs(L, tcp_libs, 0);
	luaL_newlib(L, tcp_libs);
	return 1;
}
复制代码

以上是TCP实现的C代码的片段, 有兴趣阅读源码的小伙伴请点击 这里 ;

众所周知Lua没有原生的Socket. 那么就需要框架编写者自己抽象底层逻辑重新实现一套API.

简单的封装Lua C库谁都会, 而且也算不上是什么难事. 但是我们的目的是将底层同步阻塞Socket hook为非阻塞, 这时候难点就来了!

大家都知道libev是基于react模型的事件驱动网络库, 所有注册事件后的业务逻辑都是以回调的形式触发. 那不就变成node-lua代码了吗?(笑)

这时候, 作者想了个点子来解决这个问题! 执行流程如下:

  1. 每次需要做一些同步操作的时候, 就调用C API注册回调事件.
  1. 为当前注册的所有事件创建一个Lua协程保存上下文并让出当前协程执行权.
  1. 等到注册事件被触发后, 调用C API恢复协程继续执行.

简单来说就是将C层次的异步回调逻辑封装为Lua层的同步非阻塞, 保证不因为IO问题阻塞线程.

下面提供一段socket同步非阻塞的伪代码, 经供参考:

function TCP:recv(bytes)
    local current_co = co_self()
    self.read_co = read_ev(function()
    -- do action
    -- stop timer_ev
    -- wakeup(current_co) 恢复执行权
    end)
   self.timer_co =  self.timer_ev(function()
    -- do action
    -- stop read_ev
    -- wakeup(current_co) 恢复执行权
    end)
    tcp_start(io, EV_READ, self.read_co)
    timer_start(timer, 3秒超时, self.timer_co)
    return co_yield() -- 让出执行权
end
复制代码

一个Lua版的Socket EV_READ伪代码大致的处理流程如上, 想看实际处理逻辑请看 这里

同理, Socket write/connect/listen等等API直接照抄就行(UDP也大同小异). (其实这里有个小插曲就是SSL SOCKET的坑, 但是由于篇幅问题就不说了.)

细心的小伙伴可能发现代码同时注册了Socket与Timer事件, Socket非阻塞操作不能解决read与connect超时的问题. 所以cf框架干脆就封装彻底一点.

至此, Socket算是已经算是基本hook与封装完成了. 接下来就可以开始写应用层协议了.

2. 应用层协议

现在Socket终于能正常使用了, 那么面临的新问题就又来了。

libev没有自带异步dns

dns都还需要使用者自己封装, 这个坑真是填的无比难受! 好在网络上有前辈实现了Lua版的异步dns, 作者稍微看明白之后就借用了过来封装内部使用.

这样cf也算是有了深度定制的 异步dns 库了吧!(虽然并不完善, 但是足够使用)

一个网络库是否流行, 基本上就得看生态. 那么协议层的轮子又得造起来:

  1. httpdhttpc
  2. mail
  3. mysql
  4. redis
  5. mqtt
  6. websocket

其中一些协议为各位前辈那边借过来适配后定制的, 简单的协议则是直接花1-2小时直接手写出来的。

3. 封装与易用性

为了不让API那么封闭与提升cf的可用性, 作者决定将 mysqlredis 进行初步封装.

封装包括大家常用的功能, 连接池、面向对象操作、无需手动管理session生命周期等等. 简化编程思想包袱来提升开发效率.

至于内部Socket更是让框架来解决释放问题确保文件描述数量限制的情况下也是可以正常使用. (其实是不喜欢依赖gc被动close fd与free内存)

CF是啥?

如果你耐心看完了第一部分介绍, 那么你就应该对cf有了一个大概的了解.

cf全称为: CoreFramework, 是一个基于libev的Lua网络开发框架. 在其内部实现了多种网络协议与第三方库用来帮助使用者进行项目原型的快速开发.

cf 在httpd使用上尊崇前、后端分离的解决方案, 仅实现了基本的view路由并且不支持rest风格的API路由. 虽然这样可能会引来宇多人的诟病.

cf 的httpd内嵌websocket支持, 方便使用者在复用端口的同时也可以享受长连接编写的乐趣.

更多的介绍, 请大家项目地址的 Wiki

CF能做什么?

  • 基于容器技术的微服务场景(swarm/kubernetes); —— 推荐

  • 游戏服务器的前端代理层; —— 推荐

  • 内存/CPU资源较为紧缺的云服务器; —— 推荐

  • 对性能要求较高的无状态集群; —— 推荐

  • 海量长连接(websocket)Agent集群; —— 推荐

CF使用到的技术栈?

传输层: TCP/UDP

会话层: SSL Client支持

协议层: dns/webocket/http/mqtt/redis/mysql/smtp

工具库: Timer/TASK

第三方库: Libev、openssl/libressl、lua-5.3、jemalloc/tcmalloc(可选)

CF如何安装?

cf 目前支持绝大部分Unix like操作系统, 作者是在Mac上进行开发, 所以Mac支持是必须的.

cf测试的 Linux 为Centos, 所以基本上基于Linux内核的操作系统编译后的运行也没什么问题(export 增加/usr/local/lib)

同时,作者还贴心的为大家做了一个简单Dockerfile. 文件在项目根目录下, 大家下载直接使用即可。

当然, 如果你不想制作Dockerfile,也可以使用 Docker 命令直接拉去作者制作好放在docker hub的镜像. candymi/cfweb

使用详情与使用方法请参考 Docker安装编译安装

CF 如何运行呢?

测试运行

bash#: ./cfadmin

后台运行

bash#: ./cfadmin

退出

killall cfadmin

ctrl + c

文档在哪?

作者为大家贴心的写了一篇详细到不能再详细的 文档 , 以此来获取大家的点赞与关注.

作者还为喜欢阅读源码的同学准备了充足的中文注释与英文注释, 结合起来方便大家快速了解CF工作方式(中/英注释结合易于理解一些专属词汇).


以上所述就是小编给大家介绍的《core_framework —— 基于libev的轻量级lua网络开发框架》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入Linux内核架构

深入Linux内核架构

Wolfgang Mauerer / 郭旭 / 人民邮电出版社 / 201005 / 149.00元

众所周知,Linux操作系统的源代码复杂、文档少,对程序员的要求高,要想看懂这些代码并不是一件容易事。本书结合内核版本2.6.24源代码中最关键的部分,深入讨论Linux内核的概念、结构和实现。具体包括进程管理和调度、虚拟内存、进程间通信、设备驱动程序、虚拟文件系统、网络、时间管理、数据同步等方面的内容。本书引导你阅读内核源代码,熟悉Linux所有的内在工作机理,充分展现Linux系统的魅力。 ......一起来看看 《深入Linux内核架构》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具