30 行代码,从零构建你的第一个 ionet 服务器

前言

判断一个框架是否值得投入,最好的方式就是跑通一个完整 demo。不是看 PPT,不是听别人吹,而是亲手写代码、看它启动、发请求、拿到响应。

这篇文章将带你从零开始,用最少的代码搭建一个完整的 ionet 游戏服务器。你将完成以下事情:

  1. 定义一个业务数据协议
  2. 编写一个 Action(业务动作)
  3. 启动服务器
  4. 用模拟客户端发送请求
  5. 把服务器打成 jar 包独立运行

整个过程大约 10 分钟。让我们开始。


Step 1:创建项目并配置依赖

创建一个标准的 Maven 项目,在 pom.xml 中添加 ionet 依赖:

<properties>
    <java.version>25</java.version>
    <!-- 查看最新版本: https://central.sonatype.com/artifact/com.iohao.net/run-one -->
    <ionet.version>xx.xx</ionet.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.iohao.net</groupId>
        <artifactId>run-one</artifactId>
        <version>${ionet.version}</version>
    </dependency>
</dependencies>

就这一个依赖。没有 Spring、没有 Netty 的手动配置、没有中间件的 starter——一个 run-one 搞定一切。


Step 2:定义业务数据协议

在 ionet 中,前端和后端之间通过协议对象传递业务数据。定义一个非常简单的消息:

@ProtobufClass
public class HelloMessage {
    public String name;

    @Override
    public String toString() {
        return "HelloMessage{name='" + name + "'}";
    }
}

@ProtobufClass 注解让这个普通 Java Bean 自动获得高效的二进制序列化能力。不需要手写 .proto 文件——虽然 ionet 也支持标准 Protobuf,但对于快速开发,用注解更直接。


Step 3:编写 Action

这一步是最关键的,也是 ionet 最"反直觉"的地方——因为它太简单了。

@ActionController(1)
public class DemoAction {

    @ActionMethod(0)
    private HelloMessage here(HelloMessage helloMessage) {
        HelloMessage newHelloMessage = new HelloMessage();
        newHelloMessage.name = helloMessage.name + ", I'm here";
        return newHelloMessage;
    }

    @ActionMethod(1)
    private HelloMessage jackson(HelloMessage helloMessage) {
        // 断言:name 必须是 "Jackson",否则抛出错误码
        ErrorCode.nameChecked.assertTrue("Jackson".equals(helloMessage.name));

        helloMessage.name = "Hello, " + helloMessage.name;
        return helloMessage;
    }

    @ActionMethod(2)
    private List<HelloMessage> list() {
        return IntStream.range(1, 5).mapToObj(id -> {
            HelloMessage helloMessage = new HelloMessage();
            helloMessage.name = "data:" + id;
            return helloMessage;
        }).toList();
    }
}

让我们拆解一下:

  • @ActionController(1) 定义了这个类的主路由1
  • @ActionMethod(0) 定义了方法的子路由0,完整路由就是 1-0
  • 方法参数 HelloMessage helloMessage = 客户端发来的请求数据
  • return 的值 = 自动发送给客户端的响应数据

这就是全部了。 没有 Channel、没有 ByteBuf、没有序列化框架的手动调用。和写一个 Spring Controller 的体验几乎一样。

关于异常处理

注意第二个方法 jackson 中的这行代码:

ErrorCode.nameChecked.assertTrue("Jackson".equals(helloMessage.name));

这是 ionet 的断言 + 异常机制。如果断言失败,框架会自动将错误码返回给客户端,你不需要写 try-catch,不需要封装 Result 对象。业务代码保持极致的清晰

对应的错误码定义:

public enum ErrorCode implements ErrorInformation {
    nameChecked(100, "The name must be Jackson");

    final int code;
    final String message;

    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    @Override
    public String getMessage() { return this.message; }

    @Override
    public int getCode() { return this.code; }
}

Step 4:启动服务器

public class DemoApplication {
    static void main() {
        // 开启源码文档解析,以显示代码行数
        CoreGlobalConfig.setting.parseDoc = true;
        CoreGlobalConfig.setting.print = true;

        // 创建对外服,端口 10100
        int port = ExternalGlobalConfig.externalPort;
        var externalServer = ExternalMapper.builder(port).build();

        var aeron = new AeronLifecycleManager().getAeron();

        new RunOne()
                .setAeron(aeron)
                .enableCenterServer()
                .setExternalServer(externalServer)
                .setLogicServerList(List.of(new DemoLogicServer()))
                .startup();
    }
}

启动时需要添加 VM options:

--add-opens java.base/jdk.internal.misc=ALL-UNNAMED
--enable-native-access=ALL-UNNAMED

启动后,控制台会输出所有已注册的 Action 信息,包括路由、所在类、方法名、参数类型、返回值,甚至代码行数。点击控制台中的 DemoAction.java:43,IDE 会直接跳转到对应代码——这个特性在大型项目中极其实用。


Step 5:模拟客户端请求

添加模拟客户端依赖:

<dependency>
    <groupId>com.iohao.net</groupId>
    <artifactId>extension-client</artifactId>
    <version>${ionet.version}</version>
</dependency>

编写模拟客户端:

public class DemoClient {
    static void main() {
        new ClientRunOne()
                .setInputCommandRegions(List.of(new DemoRegion()))
                .startup();
    }

    static class DemoRegion extends AbstractInputCommandRegion {
        @Override
        public void initInputCommand() {
            this.setCmd(DemoCmd.cmd, "TestDemo");

            // 模拟请求 1-0
            ofCommand(DemoCmd.here).setTitle("here").setRequestData(() -> {
                HelloMessage msg = new HelloMessage();
                msg.name = "1";
                return msg;
            }).callback(result -> {
                HelloMessage value = result.getValue(HelloMessage.class);
                log.info("{}", value);
            });

            // 模拟请求 1-1(会触发异常)
            ofCommand(DemoCmd.jackson).setTitle("Jackson").setRequestData(() -> {
                HelloMessage msg = new HelloMessage();
                msg.name = "1";  // 不是 "Jackson",会触发错误码
                return msg;
            }).callback(result -> {
                HelloMessage value = result.getValue(HelloMessage.class);
                log.info("{}", value);
            });

            // 模拟请求 1-2
            ofCommand(DemoCmd.list).setTitle("list").callback(result -> {
                List<HelloMessage> list = result.listValue(HelloMessage.class);
                log.info("{}", list);
            });
        }
    }
}

启动客户端后,在控制台输入 . 可以列出所有可用的模拟命令。输入 1-01-11-2 即可触发对应请求。

你会看到:

  • 1-0 返回 HelloMessage{name='1, I'm here'}
  • 1-1 返回错误码 100(因为 name 不是 "Jackson")
  • 1-2 返回一个包含 4 个元素的 List

这个模拟客户端可以反复执行命令,不需要每次重启。它模拟的是真实的网络环境——和你的前端同事联调时,再也不用喊"再点一下、再点一下"了。


Step 6:打包运行

mvn clean package

target/ 目录下会生成一个 jar 文件,大约 15MB。启动它:

java \
  --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \
  --enable-native-access=ALL-UNNAMED \
  -jar target/ionet-quick-demo.jar

通常在 0.x 秒内完成启动。没有预热、没有"Application started in 8.3 seconds"——就是快。


回顾:我们做了什么?

步骤 做了什么 代码量
协议定义 HelloMessage 5 行
业务逻辑 DemoAction 类,3 个 Action 20 行
启动器 DemoApplication 12 行
合计 一个完整的分布式服务器 ~37 行

这 37 行代码写出来的服务器:

  • 支持 TCP、WebSocket、UDP
  • 具备分布式扩展能力
  • 内置异常机制和错误码
  • 有模拟客户端可以即时测试
  • 打成 jar 包后只有 15MB

更多资源

下一篇预告:[一个 Java 方法就是一个 Action —— ionet 的零学习成本之道]

posted @ 2026-02-26 21:38  渔民小镇  阅读(0)  评论(0)    收藏  举报