# darkdragon **Repository Path**: ddengine/darkdragon ## Basic Information - **Project Name**: darkdragon - **Description**: 轻量级,跨平台,高并发的 lua actor开发框架 - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2019-10-16 - **Last Updated**: 2023-07-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 黑龙 - 跨平台,高并发,轻量级,易开发的服务端框架 - 支持 udp,tcp,http,websocket 协议 - 支持 mysql 驱动 - actor 模型 + lua协程可以化异步为同步,减少开发难度。 ## 构架 框架采用多线程加消息队列方式获得并发,消息队列以单个服务为单位进行执行,发消息需要知道发到某个服务中。 框架启动固定多个线程从全局服务队列中获取,再执行服务中多条消息。 服务直接互相可以发送消息通讯,单个服务消息执行永远都是单线程的不用考虑资源竞争问题。 每个服务上层都单独包装一个 lua 虚拟机ss,每个协议执行都采用 coroutine 包装起来。 ## 开始 ```lua local core = require "lddcl.core" local service = require "ddcl.service" core.init({ worker = 2, -- 工作线程数量 }) core.open_all() -- 打开所有模块 service.start(function() -- 逻辑和任务代码必须在此方法里面执行 print("hello world!") end) ``` ## 服务相关 每个服务都是一个新的虚拟机,所有每个服务都必须执行一遍 service.start 方法 - 启动一个新服务 service.new(script, param), 返回新服务的数字ID - service.start(func) 启动服务,比设置初始化函数回调 - service.callback(func) 设置当前服务接收消息的函数回调 - service.send(id, ...) 可以向某个服务发送消息 - service.call(id, ...) 向某个服务发送消息并等待回复 - service.resp(...) 对于当前消息,回复给发送者 ```lua service.start(function() service.callback(function(msg, ...) print("callback:", ...) service.resp("ret") end) local id = service.new([[require "testsvr"]], "start") service.send(id, "send") service.call(id, "call") --方法会挂起,直到接收服务回复消息 end) ``` ## 定时器和协程 - `service.sleep(ms)` 当前函数会挂起 ms 毫秒 - `service.timeout(ms, func)` 注册 ms 毫秒后会执行一次 func - `service.fork(func)` 在新的协程中执行 func,fork函数不会挂起 - `service.running()` 返回当前协程句柄 - `service.resume(co, ...)` 继续执行挂起的协程 - `service.yield(...)` 挂起当前协程 ## socket 框架接管所有网络连接,并向上层暴露id进行操作 ```lua local socket = require "ddcl.socket" 获得socket模块 protocal = socket.SOCKET_UDP or socket.SOCKET_TCP family = socket.SOCKET_IPV0 or socket.SOCKET_IPV4 or socket.SOCKET_IPV6 -- 绑定地址和端口,指定协议和协议簇,默认为 tcp/ipv4 local fd = socket.bind(host, port, protocol, family) socket.listen(fd) --监听绑定的fd if not forward then -- 普通模式,手动读取 accept while true do local nfd, addr = socket.accept(fd) if not nfd then break -- error end end else socket.forward(fd, function(msg, nfd, addr) -- forward 模式,注册一个回掉函数,每有连接进来都会回掉此函数 end) end --读取指定大小的数据,此函数会挂起,直到有数据读取或者出错 -- size为0表示读取任意大小数据 local data = socket.read(fd, size) socket.send(fd, data) -- 向fd发送数据 socket.close(fd) --强制关闭fd -- 连接的 forward模式,一有数据就会调用回掉函数,不用主动 read。 -- 如果连接关闭,回调参数 data 为 nil -- 如果是udp模式,在bind获得fd后可以直接进行forward进行收取数据 socket.forward(fd, function(msg, data) end) --发起tcp连接请求,connect会自动获取 host的family local fd,addr = socket.connect(host, port) ``` 库提供一个方便读取数据的 api:`tcp_channel` ``` lua local tcp_channel = require "ddcl.tcp_channel" local channel = tcp_channel(fd, { forward = false, --是否forward模式 close_fn = function() --连接关闭时回调 end, }) channel.read(size) -- 读取指定大小数据 channel.read_line(rep, max_len) --读取一行,rep:分隔符,max_len最大长度 ``` 对于某些请求回应的模式,库提供 `tcp_request` 快速开发 ```lua local tcp_request = require "ddcl.tcp_request" local connect_fn = function(request, channel) end -- 当连接成功回掉 local close_fn = function(request) end -- 当连接关闭时回调 local param = { host = "localhost", port = 8000, connect_fn = connect_fn, close_fn = close_fn, } -- 队列模式,例如 http。 local request = tcp_request.queue(param) -- session模式,根据消息回复内容确定哪次请求 -- 需要传递一个解包回掉函数,需要返回 session, data param.response_fn = function(request, channel) return session, data end local request = tcp_request.session(param) -- 请求 -- 队列模式,需要传递一个解包函数, local ret = request.request(data, function(request, channel) return channel.read_line() end) -- session模式, 第二个参数为 session. session可以是任何类型 local ret = request.request(data, session) ``` ## http ```lua -- 请求 local http_client = require "ddcl.http.client" local httpc = http_client({ host = "localhost", port = 8000, }) local ret = httpc.get(url, header, body) -- get请求 local ret = httpc.post(url, header, body) -- post请求 -- httpc 可以重复使用,会自动重连。 -- server local http_server = require "ddcl.http.server" local execute_fn = function(connection, request, response) print(request.url, request.header, request.body) response.resp("hello world!") end local server = http_server({ host = "localhost", port = 8000, execute_fn = execute_fn, --每次有请求都会执行回调 }) server.listen() -- 开始监听 ``` ## websocket ```lua local ws_server = require "ddcl.websocket.server" local message_fn = function(s, connection, data) print("data") end local connect_fn = function(s, connection) end local server = ws_server({ host = "localhost", port = 8000, message_fn = message_fn, --有数据回调 connect_fn = connect_fn, -- 有连接回调 }) server.listen() ``` ## mysql ``` lua local mysql_client = require "ddcl.mysql.client" local mysqlc = mysql_client({ host = "localhost", port = 3306, user = "root", password = "", database = "", }) mysqlc.connect() local ret = mysqlc.query("select * from `mysql.user`") ```