Skynet 安装与环境搭建

详细介绍 Skynet 的安装步骤、环境配置、编译选项和第一个 Hello World 服务的编写

本教程将详细介绍如何在不同操作系统上安装和配置 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 的服务模型,了解服务的生命周期、服务类型和服务间通信机制。

参考资料

  1. Skynet 官方安装指南:https://github.com/cloudwu/skynet/wiki/Build
  2. Lua 5.4 参考手册:https://www.lua.org/manual/5.4/
  3. Skynet 配置详解:https://github.com/cloudwu/skynet/wiki/Config

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页