You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7sDream 4a0bfcde4d
finish usage doc
10 months ago
chong finish usage doc 10 months ago
example finish usage doc 10 months ago
.gitignore finish usage doc 10 months ago
LICENSE add README and LICENSE 10 months ago
Pipfile init 11 months ago
Pipfile.lock init 11 months ago
README.md finish usage doc 10 months ago
run_example.py init 11 months ago
setup.py add README and LICENSE 10 months ago

README.md

Chong

chong.py 是一个实验(玩具)性质的 RPC Framework,想法是通过一个最简单的 RPC 框架的实现来说明 RPC 技术的一些基础原理。

依赖

除了 pipenv 本身之外,其他依赖包可通过 pipenv install 安装。

使用文档

使用 chong 开发 RPC 服务很简单,下面介绍通用的步骤。

安装

由于只是玩具项目,没有发布到 pypi,所以需要先竟然 pipenv 环境,执行安装:

git clone https://git.7sdre.am/7sDream/chong.py.git
cd chong
pipenv install
pipenv shell
python setup.py develop

然后执行 chong -h,如果有帮助文本出现,即说明安装完成。

定义接口

和其他 RPC 框架一样,第一步是定义接口。

chong 使用 yaml 文件格式定义接口,整个文件的根对象为 chong,其中含有二个子项:

  • struct: 数据结构定义
  • apis:接口定义

每个 struct 的定义由一系列字段定义组成,每个字段只需要设置字段名和类型即可。

每个 API 接口以接口名为名称,由参数类型,返回值类型两个子项组成。

之所以不允许多参数,是因为多个参数也可以用结构体来实现,而且这样更为统一,也更容易实现,同时也并没有损失任何能力。

下面是一个简单的 adder 的接口定义文件,供参考:

# example/protocol/adder.yml

chong:
  structs:
    Info:
      status: int
      message: str
    Argument:
      a: [int]
      b: [int]
    Result:
      info: Info
      sum: [int]
  apis:
    add:
      argument: Argument
      return: Result

(目前类型只支持 intstrlist,而且对 list,并不提供成员类型检查功能,所以嵌套的 list 可能会有问题,没什么时间改,先凑合着用一下)

这个定义文件中声明了三个类型,一个接口,含义用 C++ 的代码写出来大概是这样:

struct Info {
    int status;
    message std::string;
};

struct Argument {
    std::vector<int> a;
    std::vector<int> b;
};

struct Result {
    Info info;
    std::vector<int> sum;
};

class Adder {
    Result add(Argument args) {
        // ...
    }
}

yaml 语法简单,应该不需要进一步的说明吧。

代码生成

使用 chong CLI 工具可以生成客户端和服务端的样板代码:

cd example/protocol
chong adder.yml

此时会生成三个文件:

  • adder_strut.py:所有的数据结构定义
  • adder_client.py:客户端 Client 实现,客户端直接使用即可
  • adder_server.py:服务端 Server 的基类,服务端需要继承此类,实现接口

这三个文件都不需要打开看,这部分只讲使用,不讲原理。

服务端实现

# example/server.py

from example.protocol.adder_structs import Argument, Result
from .protocol.adder_server import AdderServer


class AdderImpl(AdderServer):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

    async def add(self, arg: Argument) -> Result:
        print(f"{arg.a} {arg.b}")
        return Result({
            "info": {
                "status": 0,
                "message": "OK"
            },
            "sum": [a + b for a, b in zip(arg.a, arg.b)]
        })


async def start() -> None:
    server = AdderImpl(7777)
    await server.start()

这里 AdderImpl 继承了 adder_server 里的 AdderServer 类,(除了构造函数之外)实现了我们在接口定义文件里定义的 add 接口。

模版代码中的服务端基类接受两个参数,第一个是端口(也即 start 函数中的 7777),第二个是 IP,IP 不填默认为所有。

这个 start 函数只是为了方便使用而已,不是必须。

客户端使用

CLI 产生的 AdderClient 类可以直接使用,不需要额外再写什么代码:

# example/client.py

import random
import asyncio

from .protocol.adder_structs import Argument
from .protocol.adder_client import AdderClient


async def start() -> None:
    adder = AdderClient("127.0.0.1", 7777)

    while True:
        a = [random.randint(0, 100) for _ in range(10)]
        b = [random.randint(0, 100) for _ in range(10)]
        arg = Argument({
            "a": a,
            "b": b,
        })

        result = await adder.add(arg)

        print(f"status: {result.info.status}, {result.info.message}")
        print(f"{arg.a} + {arg.b} = {result.sum}")

        await asyncio.sleep(1)

AdderClient 类也接受端口和 IP 两个参数 ,所以这里填写的端口需要和服务端一致。

运行结果

然后分别跑起来服务端和客户端即可,我这里写了一个 run_example.py 来辅助启动:

# run_example.py

import sys
import asyncio

import example.server
import example.client

if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "server":
        asyncio.get_event_loop().run_until_complete(example.server.start())
        asyncio.get_event_loop().run_forever()
    else:
        asyncio.get_event_loop().run_until_complete(example.client.start())

python run_example.py server 启动服务端,python run_example.py 启动客户端,以下是结果:

example-result

LICENSE

MIT