在 skynet 框架中提供了一个控制台服务 debug_console
由于启动控制台服务后,需要借助 nc
或 telnet
来远程连接控制台,所需需要确保机器上已安装了此类工具,这里我使用的是 nc 6.40
,可以先查询本地是否已安装了该工具:
$ nc --version Ncat: Version 6.40 ( http://nmap.org/ncat )
假如未安装,直接使用 yum
工具进行安装:
$ yum install nc
在 skynet 的启动会服务(通常是在 skynet 启动时,也就是在 config 启动配置文件所指定的运行时第一个服务 start = "main"
,即 main.lua
)中新增一句代码即可启动控制台服务:
skynet.newservice("debug_console", 8000)
第二个参数指定了远程连接的端口号,此端口可以根据自己需要进行修改,在启动 skynet 服务时看到如下 log 输出代表控制台启动成功:
[:0100000a] LAUNCH snlua debug_console 8000 [:0100000a] Start debug console at 127.0.0.1:8000
然后在新的 shell 窗口中连接控制台,连接成功如下:
$ nc 127.0.0.1 8000 Welcome to skynet console
官方建议:
出于安全考虑,调试控制台只能监听本地地址 127.0.0.1 ,所以如果需要远程使用,需要先登录到本机,然后再连接。
安装使用 telnet 并连接控制台服务其实也不难:
$ yum install telnet $ telnet 127.0.0.1:8000 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. Welcome to skynet console
直接使用 help
指令查询帮助文档,了解所有可用的指令 :
[root@localhost ~]# nc 127.0.0.1 8000 Welcome to skynet console help call call address ... clearcache clear lua code cache cmem Show C memory info debug debug address : debug a lua service exit exit address : kill a lua service gc gc : force every lua service do garbage collect help This help message info info address : get service infomation inject inject address luascript.lua kill kill address : kill service list List all the service log launch a new lua service with log logoff logoff address logon logon address mem mem : show memory status ping ping address service List unique service shrtbl Show shared short string table info signal signal address sig snax lanuch a new snax service start lanuch a new lua service stat Dump all stats task task address : show service task detail <CMD OK>
直接在当前 shell 窗口输入对应的指令并带上参数即可,官方文档介绍参数格式:
命令的一般格式是 命令 地址 ,有些命令不带地址,会针对所有的服务。当输入地址时,可以使用 :01000001 这样的格式指代一个服务地址:由冒号开头的 8 位 16 进制数字,也可以省略前面两个数字的 harbor id 以及接下来的连续 0 ,比如 :01000001 可以简写为 1 。所有活动的服务可以输入 list 列出。
服务的 lua 源码在 service\debug_console.lua
中,从 skynet.start
方法开始:
skynet.start(function()
local listen_socket = socket.listen (ip, port)
skynet.error("Start debug console at " .. ip .. ":" .. port)
socket.start(listen_socket , function(id, addr)
-- 返回执行结果给指令请求端
local function print(...)
local t = { ... }
for k,v in ipairs(t) do
t[k] = tostring(v)
end
socket.write(id, table.concat(t,"\t"))
socket.write(id, "\n")
end
socket.start(id)
skynet.fork(console_main_loop, id , print)
end)
end)
这里启动了一个 Socket 监听:
local listen_socket = socket.listen (ip, port)
监听的 ip 和端口可以在启动服务时传入:
local ip = (arg.n == 2 and arg[1] or "127.0.0.1") -- 默认是本地 ip 127.0.0.1 ,或者是传入两个参数时的第一个参数
local port = tonumber(arg[arg.n]) -- 传入参数的最后一个
启动完监听端口后,启动一个协程来运行一个死循环,用于监控 socket 连接端输入的命令,并解析运行命令,将结果通过 socket 返回给 socket 连接端:
skynet.fork(console_main_loop, id , print)
此处传入的最后一个参数 print
是一个 function ,用于向 socket 连接端返回执行指令的打印结果,以文本的形式,这里可以简单地理解为:socket 监听端与连接端的一种聊天模式。
在协程中的死循环用于监听命令请求端输入的命令,基本逻辑如下:
pcall(function()
while true do
local cmdline = socket.readline(stdin, "\n")
if not cmdline then
break
end
-- http 命令数据解析
if cmdline:sub(1,4) == "GET " then
-- http
local code, url = httpd.read_request(sockethelper.readfunc(stdin, cmdline.. "\n"), 8192)
local cmdline = url:sub(2):gsub("/"," ")
docmd(cmdline, print, stdin)
break
end
-- nc 或 telnet 命令数据解析
if cmdline ~= "" then
docmd(cmdline, print, stdin)
end
end
end)
通过 socket.readline
读取最新的命令行,没有新命令则结束本次;
有新命令,则解析命令,这里接续要区分 nc
或 telnet
传入的 socket 数据和通过 Http 请求发过来的数据。
docmd
是根据解析结果调用具体执行接口的方法:
local function docmd(cmdline, print, fd)
local split = split_cmdline(cmdline)
local command = split[1]
local cmd = COMMAND[command]
local ok, list
if cmd then
ok, list = pcall(cmd, table.unpack(split,2))
else
cmd = COMMANDX[command]
if cmd then
split.fd = fd
split[1] = cmdline
ok, list = pcall(cmd, split)
else
print("Invalid command, type help for command list")
end
end
if ok then
if list then
if type(list) == "string" then
print(list)
else
dump_list(print, list)
end
end
print("<CMD OK>")
else
print(list)
print("<CMD Error>")
end
end
info address
查看指定服务详情的接口
inject inject address
热更时常用到的接口
在 skynet 的 debug_console 中不能使用键盘的上下键来追溯之前的输入历史命令,每次都要重新输入命令。想优化这个操作,需要使用到 readline 的 history 特性,可以通过安装 rlwrap
工具来实现。具体的安装步骤如下:
安装 readline
,因为 rlwrap
依赖于此工具,在 skynet 编译的时候也依赖与此工具:
$ yum -y install readline-devel
安装 rlwrap
,这是一个开源的工具,源码在 Github hanslub42/rlwrap 上可以找到,最新的版本是 v 0.43 ,可以下载源码来进行编译安装,但这里为了节省时间还是建议直接到 这里 下载安装包 rlwrap-0.43.tar.gz ,然后解压安装:
$ tar -zxf rlwrap-0.43.tar.gz $ cd rlwrap-0.43 $ ./configure -q # -q表示静默不打印配置日志 $ make && make install
检查安装成功:
$ rlwrap --version rlwrap 0.43
rlwrap
常用的快捷:
Ctrl+L 清屏,实际是将当前行置顶
Ctrl+P 上一条命令
Ctrl+N 下一条命令
Ctrl+U 从光标处删除到行首
Ctrl+W 向前删除一个单词
Ctrl+B 光标向前移动一个位置
Ctrl+T 光标处字符与前一个字符交换位置
Ctrl+Z 后台运行,使用fg调出
Ctrl+H 相当于删除键
Ctrl+J 相当于回车键
Ctrl+O 相当于回车键
Ctrl+M 相当于回车键
需要在 nc
中使用到 rlwrap
的功能,连接时的指令需要加上 rlwrap
前缀,变成:
rlwrap nc 127.0.0.1 8000
不加前缀的话,rlwrap
工具是不起作用的。