本教程将详细介绍如何在不同操作系统上安装和配置 Skynet 框架,并编写第一个 Hello World 服务。
系统要求
在安装 Skynet 之前,请确保你的系统满足以下要求:
操作系统支持
- Linux:Ubuntu 18.04+, CentOS 7+, Debian 10+(推荐)
- macOS:10.14+ (Mojave 及以上)
- Windows:需要通过 WSL2 或 Docker 运行(不推荐原生 Windows)
硬件要求
- CPU:多核处理器(Skynet 是多线程框架)
- 内存:至少 2GB RAM
- 磁盘:至少 1GB 可用空间
软件依赖
- GCC/Clang:C 编译器(GCC 4.8+ 或 Clang 3.4+)
- Make:构建工具
- Git:版本控制工具
- Lua 5.4:Skynet 内置,无需单独安装
Linux 安装
Ubuntu/Debian
# 1. 更新系统包
sudo apt update
sudo apt upgrade -y
# 2. 安装依赖
sudo apt install -y \
build-essential \
git \
autoconf \
automake \
libtool \
libreadline-dev \
zlib1g-dev \
libssl-dev
# 3. 克隆 Skynet 源码
cd ~
git clone https://github.com/cloudwu/skynet.git
cd skynet
# 4. 编译
make linux
# 5. 验证安装
./skynet examples/config
如果看到类似以下输出,说明安装成功:
[:00000001] LAUNCH logger
[:00000002] LAUNCH snlua launcher
[:00000003] LAUNCH snlua gate
[:00000004] LAUNCH snlua cdummy
[:00000005] LAUNCH snlua datacenterd
[:00000006] LAUNCH snlua service_mgr
[:01000004] KILL self
按 Ctrl+C 停止服务。
CentOS/RHEL
# 1. 安装 EPEL 仓库
sudo yum install -y epel-release
# 2. 安装依赖
sudo yum groupinstall -y "Development Tools"
sudo yum install -y \
git \
autoconf \
automake \
libtool \
readline-devel \
zlib-devel \
openssl-devel
# 3. 克隆和编译(同 Ubuntu)
cd ~
git clone https://github.com/cloudwu/skynet.git
cd skynet
make linux
# 4. 验证
./skynet examples/config
Arch Linux
# 1. 安装依赖
sudo pacman -S base-devel git readline zlib openssl
# 2. 克隆和编译
cd ~
git clone https://github.com/cloudwu/skynet.git
cd skynet
make linux
# 3. 验证
./skynet examples/config
macOS 安装
使用 Homebrew(推荐)
# 1. 安装 Homebrew(如果未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 2. 安装依赖
brew install \
git \
autoconf \
automake \
libtool \
readline \
openssl
# 3. 克隆 Skynet
cd ~
git clone https://github.com/cloudwu/skynet.git
cd skynet
# 4. 编译(macOS 使用 macosx 目标)
make macosx
# 5. 验证
./skynet examples/config
常见问题解决
问题 1:找不到 readline 头文件
# 设置环境变量
export LDFLAGS="-L$(brew --prefix readline)/lib"
export CPPFLAGS="-I$(brew --prefix readline)/include"
# 重新编译
make clean
make macosx
问题 2:找不到 openssl
# 设置环境变量
export LDFLAGS="-L$(brew --prefix openssl)/lib"
export CPPFLAGS="-I$(brew --prefix openssl)/include"
# 重新编译
make clean
make macosx
Windows 安装(通过 WSL2)
Windows 用户推荐使用 WSL2(Windows Subsystem for Linux 2)来运行 Skynet。
安装 WSL2
# 在 PowerShell(管理员)中执行
wsl --install
# 重启电脑后,WSL2 和 Ubuntu 会自动安装
在 WSL2 中安装 Skynet
# 1. 打开 WSL2 Ubuntu 终端
# 2. 更新系统
sudo apt update
sudo apt upgrade -y
# 3. 安装依赖
sudo apt install -y \
build-essential \
git \
autoconf \
automake \
libtool \
libreadline-dev \
zlib1g-dev \
libssl-dev
# 4. 克隆和编译
cd ~
git clone https://github.com/cloudwu/skynet.git
cd skynet
make linux
# 5. 验证
./skynet examples/config
使用 Docker(替代方案)
如果不想使用 WSL2,可以使用 Docker:
# 1. 安装 Docker Desktop for Windows
# 下载地址:https://www.docker.com/products/docker-desktop
# 2. 创建 Dockerfile
mkdir skynet-docker
cd skynet-docker
cat > Dockerfile << 'EOF'
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
build-essential \
git \
autoconf \
automake \
libtool \
libreadline-dev \
zlib1g-dev \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
RUN git clone https://github.com/cloudwu/skynet.git .
RUN make linux
EXPOSE 8888
CMD ["./skynet", "examples/config"]
EOF
# 3. 构建镜像
docker build -t skynet .
# 4. 运行容器
docker run -it -p 8888:8888 skynet
配置文件详解
Skynet 使用配置文件来定义框架的运行参数。让我们详细解析 examples/config 文件:
-- examples/config 配置文件
-- 线程数量(工作线程池大小)
thread = 8
-- 启动脚本
start = "main"
-- Lua 代码搜索路径
luaservice = "./service/?.lua;./service/?/init.lua;./test/?.lua;./examples/?.lua"
-- Lua 模块搜索路径
lua_path = "./lualib/?.lua;./lualib/?/init.lua"
-- C 模块搜索路径
lua_cpath = "./luaclib/?.so"
-- 日志文件(可选)
-- logpath = "./logs"
-- loglevel = "debug"
-- 启用控制台
console = "127.0.0.1:8000"
-- 启用调试端口(可选)
-- debug_port = 8000
-- debug_enable = 1
配置项说明
thread
thread = 8
设置工作线程池的大小。建议设置为 CPU 核心数的 1-2 倍。
-- 根据 CPU 核心数动态设置
-- 4 核 CPU:thread = 4 或 8
-- 8 核 CPU:thread = 8 或 16
start
start = "main"
指定启动时加载的 Lua 脚本(不包含 .lua 扩展名)。Skynet 会在 luaservice 路径中查找 main.lua。
luaservice
luaservice = "./service/?.lua;./service/?/init.lua;./test/?.lua;./examples/?.lua"
定义服务脚本的搜索路径。使用 ? 作为占位符,Skynet 会将服务名替换到 ? 的位置。
-- 示例:启动服务 "gate"
-- Skynet 会按顺序查找:
-- 1. ./service/gate.lua
-- 2. ./service/gate/init.lua
-- 3. ./test/gate.lua
-- 4. ./examples/gate.lua
lua_path
lua_path = "./lualib/?.lua;./lualib/?/init.lua"
定义 Lua 模块的搜索路径,用于 require 语句。
-- 示例:require "skynet"
-- Lua 会按顺序查找:
-- 1. ./lualib/skynet.lua
-- 2. ./lualib/skynet/init.lua
lua_cpath
lua_cpath = "./luaclib/?.so"
定义 C 扩展模块的搜索路径。
-- 示例:require "skynet.core"
-- Lua 会查找:./luaclib/skynet/core.so
console
console = "127.0.0.1:8000"
启用调试控制台,可以通过 telnet 连接到该端口进行调试。
# 连接到调试控制台
telnet 127.0.0.1 8000
# 在控制台中可以执行命令
# help - 查看帮助
# list - 列出所有服务
# info :01000001 - 查看服务信息
创建自定义配置
让我们创建一个简单的自定义配置文件:
# 创建项目目录
mkdir ~/my-skynet-project
cd ~/my-skynet-project
# 创建配置文件
cat > config << 'EOF'
-- 我的第一个 Skynet 项目配置
thread = 4
start = "main"
-- 服务搜索路径
luaservice = "./service/?.lua;./skynet/service/?.lua"
-- Lua 模块路径
lua_path = "./lualib/?.lua;./skynet/lualib/?.lua"
-- C 模块路径
lua_cpath = "./luaclib/?.so;./skynet/luaclib/?.so"
-- 启用控制台
console = "127.0.0.1:8000"
-- 日志级别
harbor = 0
EOF
# 创建目录结构
mkdir -p service lualib luaclib logs
# 复制 Skynet 到项目目录
cp -r ~/skynet ./skynet
编写 Hello World 服务
现在让我们编写第一个 Skynet 服务。
创建主服务
# 创建 main.lua
cat > service/main.lua << 'EOF'
local skynet = require "skynet"
skynet.start(function()
skynet.error("=================================")
skynet.error("Hello, Skynet!")
skynet.error("这是我的第一个 Skynet 服务")
skynet.error("=================================")
-- 创建一个子服务
local hello_service = skynet.newservice("hello")
-- 向子服务发送消息
skynet.send(hello_service, "lua", "say_hello", "World")
-- 调用子服务并等待响应
local response = skynet.call(hello_service, "lua", "get_time")
skynet.error("当前时间:", response)
-- 退出服务
skynet.exit()
end)
EOF
创建子服务
# 创建 hello.lua
cat > service/hello.lua << 'EOF'
local skynet = require "skynet"
-- 消息处理函数
local CMD = {}
function CMD.say_hello(name)
skynet.error("Hello,", name, "!")
end
function CMD.get_time()
return os.date("%Y-%m-%d %H:%M:%S")
end
skynet.start(function()
skynet.error("Hello 服务已启动")
-- 注册消息处理函数
skynet.dispatch("lua", function(session, source, cmd, ...)
local f = assert(CMD[cmd], "未知命令: " .. cmd)
-- 如果有 session,说明是 call,需要返回结果
if session ~= 0 then
skynet.ret(skynet.pack(f(...)))
else
-- session 为 0,说明是 send,不需要返回
f(...)
end
end)
end)
EOF
运行项目
# 进入项目目录
cd ~/my-skynet-project
# 启动 Skynet
./skynet/skynet config
你将看到类似以下输出:
[:00000001] LAUNCH logger
[:00000002] LAUNCH snlua launcher
[:00000003] LAUNCH snlua main
[:00000004] LAUNCH snlua hello
[:01000004] Hello 服务已启动
[:01000003] =================================
[:01000003] Hello, Skynet!
[:01000003] 这是我的第一个 Skynet 服务
[:01000003] =================================
[:01000004] Hello, World!
[:01000003] 当前时间: 2024-01-16 10:30:45
[:01000003] KILL self
[:01000002] KILL self
使用调试控制台
启动 Skynet 后,可以通过调试控制台与服务交互:
# 打开新终端,连接到调试控制台
telnet 127.0.0.1 8000
# 在控制台中执行命令
Welcome to skynet console
# 查看所有服务
> list
:01000001 logger 0
:01000002 launcher 0
:01000003 main 0
:01000004 hello 0
# 查看服务详细信息
> info :01000004
messages: 0
memory: 12345
cpu: 0.001
# 执行 Lua 代码
> call :01000004 lua get_time
2024-01-16 10:30:45
# 退出控制台
> exit
项目目录结构
一个完整的 Skynet 项目通常具有以下目录结构:
my-skynet-project/
├── config # Skynet 配置文件
├── service/ # 服务脚本目录
│ ├── main.lua # 主服务
│ ├── hello.lua # Hello 服务
│ ├── gate.lua # 网关服务
│ └── agent.lua # 代理服务
├── lualib/ # Lua 模块目录
│ ├── utils.lua # 工具函数
│ ├── protocol.lua # 协议定义
│ └── config.lua # 配置管理
├── luaclib/ # C 扩展模块目录
│ └── mylib.so # 自定义 C 模块
├── logs/ # 日志目录
│ └── skynet.log # 运行日志
├── skynet/ # Skynet 框架源码
│ ├── skynet # Skynet 可执行文件
│ ├── service/ # 内置服务
│ ├── lualib/ # 内置 Lua 库
│ └── luaclib/ # 内置 C 模块
└── scripts/ # 脚本目录
├── start.sh # 启动脚本
└── stop.sh # 停止脚本
启动和停止脚本
创建便捷的启动和停止脚本:
# 创建启动脚本
cat > start.sh << 'EOF'
#!/bin/bash
echo "启动 Skynet 服务..."
# 检查是否已经运行
if [ -f skynet.pid ]; then
echo "Skynet 已经在运行 (PID: $(cat skynet.pid))"
exit 1
fi
# 启动 Skynet(后台运行)
nohup ./skynet/skynet config > logs/skynet.log 2>&1 &
# 保存 PID
echo $! > skynet.pid
echo "Skynet 已启动 (PID: $(cat skynet.pid))"
echo "日志文件: logs/skynet.log"
EOF
chmod +x start.sh
# 创建停止脚本
cat > stop.sh << 'EOF'
#!/bin/bash
echo "停止 Skynet 服务..."
if [ ! -f skynet.pid ]; then
echo "Skynet 未运行"
exit 1
fi
PID=$(cat skynet.pid)
# 发送终止信号
kill $PID
# 等待进程结束
for i in {1..10}; do
if ! ps -p $PID > /dev/null; then
echo "Skynet 已停止"
rm skynet.pid
exit 0
fi
sleep 1
done
# 强制终止
echo "强制终止..."
kill -9 $PID
rm skynet.pid
echo "Skynet 已强制停止"
EOF
chmod +x stop.sh
# 创建重启脚本
cat > restart.sh << 'EOF'
#!/bin/bash
./stop.sh
sleep 2
./start.sh
EOF
chmod +x restart.sh
使用脚本
# 启动服务
./start.sh
# 查看日志
tail -f logs/skynet.log
# 停止服务
./stop.sh
# 重启服务
./restart.sh
常见问题排查
问题 1:编译失败
错误信息:make: *** [linux] Error 1
解决方案:
# 清理并重新编译
make clean
make linux
# 如果仍然失败,检查编译器版本
gcc --version
# 更新 GCC(Ubuntu)
sudo apt install gcc-9 g++-9
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90
问题 2:找不到 Lua 模块
错误信息:module 'skynet' not found
解决方案:
-- 检查配置文件中的 lua_path
lua_path = "./lualib/?.lua;./skynet/lualib/?.lua"
-- 确保路径正确,使用相对路径或绝对路径
问题 3:端口被占用
错误信息:bind: Address already in use
解决方案:
# 查找占用端口的进程
lsof -i :8000
# 终止进程
kill -9 <PID>
# 或者修改配置文件中的端口
console = "127.0.0.1:8001"
问题 4:服务启动后立即退出
可能原因:服务中没有保持运行的逻辑
解决方案:
-- 错误示例:服务会立即退出
skynet.start(function()
skynet.error("Hello")
-- 没有消息处理,服务会退出
end)
-- 正确示例:注册消息处理函数
skynet.start(function()
skynet.error("Hello")
skynet.dispatch("lua", function(...)
-- 处理消息
end)
end)
下一步
恭喜你!你已经成功安装和配置了 Skynet,并运行了第一个服务。
在下一节教程中,我们将深入学习 Skynet 的服务模型,了解服务的生命周期、服务类型和服务间通信机制。
参考资料
- Skynet 官方安装指南:https://github.com/cloudwu/skynet/wiki/Build
- Lua 5.4 参考手册:https://www.lua.org/manual/5.4/
- Skynet 配置详解:https://github.com/cloudwu/skynet/wiki/Config
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。