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

大道至简, 返璞归真.

前言

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

  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注册回调事件.
  2. 为当前注册的所有事件创建一个Lua协程保存上下文并让出当前协程执行权.
  3. 等到注册事件被触发后, 调用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的可用性, 作者决定将mysql与redis进行初步封装.

封装包括大家常用的功能, 连接池、面向对象操作、无需手动管理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工作方式(中/英注释结合易于理解一些专属词汇).


回答之前的问题:

Q. 性能怎么样?

A. 性能还不错, 但是具体数值请自行测试.

Q. 是否容易上手?

A. 学习lua 一小时入门 -> cf 一小时入门

Q. 开这个项目的初衷是什么?

A. 其实在前面已经回答过了.

Q. 开发目标在哪?

A. Wiki 里有TODO

Q. 如何反馈问题?

A. Wiki 里有Q & A

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

A. CF对比其它lua开发项目更深入改变用户使用习惯! 简化框架上手难度, 将框架都黑盒子透明化. 无需学习复杂的设计模式与理念.

Q. CF的开发理念是什么?

A. CF项目的目标不是竞争, 而是明白明白简单为美. 当你习惯了它, 也许你就会上瘾.


使用示例

精彩截图

希望

也许你正在使用其它开发框架, 但是这不妨碍你对cf的督促.

也许你正在试用它, 这不妨碍你与作者沟通你的想法.

也许你正在吐槽它的缺点,请来issue尽情吐槽.

文档与地址

项目文档

项目地址

原文地址:https://blog.51cto.com/10160495/2380377

时间: 2024-10-13 00:07:06

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

RestExpress 一个基于Netty的轻量级Rest服务开发框架

RestExpress 原文的定义是这么说的: RestExpress is the easiest way to create RESTful web services in Java. An extremely Lightweight, Fast, REST Engine and API for Java. Supports JSON and XML serialization automagically as well as ISO 8601 date formats. A thin wr

轻量级的Java 开发框架 Spring

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来.它是为了解决企业应用开发的复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架.Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Sprin

基于DDD的现代ASP.NET开发框架--ABP系列之7、ABP Session管理

点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之7.ABP Session管理 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 简介 如果一个应用程序需要登录,则它必须知道当前用户执行了什么操作.因此ASP.NET

【Android】自己写的轻量级安卓网络框架——能够控制网络连接,支持缓存

1原因: 之所以写这个框架是因为网上的好多的网络框架都没有很好的对网络连接进行控制,比如当你点击取消的时候只是对话框取消了,后台网络请求还是在继续,这样就造成了activity的无法释放,更严重的情况是降低APP流畅度,所以就结合自己的需求写了个这样轻量级的网络框架 2解决方案: 我已经开源了,放在了OSC上,框架目前还不是很完善,所以需要慢慢改善,不过这个流程目前感觉是非常不错的,当activity销毁的时候基本不会存在无法释放问题.当你点击取消的时候也不会出现后台网络请求还在继续的情况. h

基于 TCP/IP 协议的网络编程

在说明基于 TCP/IP 协议的网络编程之前,先来了解一下 Socket(网络套接字): 利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准 通信的两端都要有 Socket,是两台机器间通信的端点(API 原话) 网络通信其实就是 Socket 间的通信 Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端 网络编程某种程度上可以称作"Socket 编程" T

基于DDD的现代ASP.NET开发框架--ABP系列之8、ABP日志管理

点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之8.ABP日志管理 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 本文由东莞-天道提供翻译 Server side(服务器端) ASP.NET Boilerplat

基于DDD的现代ASP.NET开发框架--ABP系列之6、ABP依赖注入

点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 本文由 上海-半冷 提供翻译 什么是依赖注入 如果你已经知道依赖注入的概念,构造函数和属性注入模式

基于DDD的现代ASP.NET开发框架--ABP系列之5、ABP启动配置

点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之5.ABP启动配置 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 本文由 东莞-天道 提供翻译 译者注:在看这一节的内容之前,建议大家先下载module-zero这

基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程

点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://gith