Skip to content

Bus 插件

查看 Markdown

Bus 为进程分配逻辑地址,读取应用类型、进程端点和连接关系。bus_module 提供配置查询,msg_module 根据应用类型、Bus ID 或 Session 发送消息;实际连接由 Net 插件管理。

地址与职责

Bus 地址使用 channel.zone.app.instance 四段形式,例如 1.1.31.1。四段各占 8 位,组合为 bus_id_t;它是进程标识,不是 IP 地址或监听端口。

段 含义 示例
channel 应用划分的渠道 1
zone 应用划分的区域 1
app app_type 的数值 31 对应 ark_app_game
instance 同类进程实例编号 1
接口 职责
bus_module 本进程信息、应用名称映射、目标关系和其他进程配置
msg_module 消息序列化、选择已有连接、填写消息头并请求发送
net_service_manager_module 监听服务、客户端连接、Bus 与 Session 的映射
net_client_service / net_server_service 收包回调、连接事件和连接状态处理

配置进程与连接关系

bus_module::init() 读取 bus.plugin.conf 的四个部分:

配置节点 内容
applications 应用名称与 app_type 数值的映射
relations 有方向的连接目标:source 应连接到哪些 target 类型
processes 每个 Bus ID 的监听端点、连接上限和线程配置
center 注册中心参数,供 get_reg_center() 查询

下面说明 Game 与 World 两类进程的配置关系。内外端点使用不同端口,避免同时监听时冲突。

<xml>
    <applications>
        <application name="world" type="30" />
        <application name="game" type="31" />
    </applications>
    <relations>
        <relation source="game" target="world" />
    </relations>
    <processes>
        <proc busid="1.1.30.1" endpoint_server="tcp://127.0.0.1:9101"
            endpoint_intranet="tcp://127.0.0.1:9111" max_connection="100" thread_num="1" />
        <proc busid="1.1.31.1" endpoint_server="tcp://127.0.0.1:9102"
            endpoint_intranet="tcp://127.0.0.1:9112" max_connection="100" thread_num="1" />
    </processes>
    <center ip="127.0.0.1" port="8500" service_name="ark-service"
        check_interval="10s" check_timeout="3s" />
</xml>

这是 Bus 配置示例,不是完整的双进程启动配置。应用还需加载 Bus、Net 及其依赖插件,设置各自的 Bus ID,启动监听并发起连接。relations 只提供目标类型列表;读取关系本身不会自动建立连接。

center 有配置项不等于已启用动态注册或发现。当前网络服务管理模块中的 Consul 注册 / 健康检查发现路径仍为注释,不能依靠这份配置自动获得目标进程。

查询本进程与目标进程

在模块完成初始化后,通过插件管理器取得 Bus 接口。以下函数收集当前应用类型对应的、静态配置中的目标进程。

#include <vector>

#include "ark/bus/bus_module.hpp"
#include "ark/plugin_manager.hpp"

std::vector<ark::proc_config> configured_targets(ark::plugin_manager& manager) {
    auto* bus = manager.find_module<ark::bus_module>();
    if (bus == nullptr)
    {
        return {};
    }

    std::vector<ark::app_type> types;
    if (!bus->get_target_bus_relations(types))
    {
        return {};
    }

    std::vector<ark::proc_config> result;
    for (auto type : types)
    {
        std::vector<const ark::proc_config*> processes;
        bus->get_other_proc(type, processes);
        for (const auto* process : processes)
        {
            result.push_back(*process);
        }
    }
    return result;
}

get_other_proc(type, list) 向输出列表追加配置指针,返回追加后列表的总长度。上例每次使用空列表,并复制配置,避免把模块内部指针保存在外部。该查询按类型筛选,不额外限定渠道或区域;应用需要时应自行筛选。

查询 结果与限制
get_self_bus_id() / get_self_bus_name() 当前进程的整数 ID / 四段地址
get_self_proc() 本进程的 proc_config;它是静态配置,不代表监听已启动
get_app_type(name) 未找到时返回 ark_app_default
get_app_name(type) 未找到时返回空字符串
get_other_proc(id, proc) 找到时复制配置并返回 true;未找到返回 false
combine_bus_id(type, instance) 沿用本进程的渠道和区域,组合指定类型与实例的 ID

建立 TCP 连接

目标进程应先通过 net_service_manager_module::create_server() 启动监听。下面从静态配置取目标的内网端点,并将 TCP 连接请求交给网络服务管理模块。

#include "ark/bus/bus_module.hpp"
#include "ark/net/net_service_manager_module.hpp"
#include "ark/plugin_manager.hpp"

bool queue_tcp_connection(ark::plugin_manager& manager, ark::bus_id_t target_id) {
    auto* bus = manager.find_module<ark::bus_module>();
    auto* network = manager.find_module<ark::net_service_manager_module>();
    if (bus == nullptr || network == nullptr)
    {
        return false;
    }

    ark::proc_config target;
    if (!bus->get_other_proc(target_id, target))
    {
        return false;
    }

    const auto& endpoint = target.intranet_ep;
    if (endpoint.proto() != ark::proto_type::tcp || endpoint.get_ip().empty() || endpoint.get_port() == 0)
    {
        return false;
    }

    return network->create_client_service(
        ark::bus_addr(target_id), ark::proto_type::tcp, endpoint.get_ip(), endpoint.get_port());
}

返回 true 表示连接请求已加入客户端服务,连接在后续 update() 中处理;它不表示已经连接成功。通过客户端服务的 reg_net_event_callback() 观察连接事件,通过 reg_msg_callback() 注册消息处理。接收端使用对应服务端接口注册回调。

当前客户端服务按状态处理断线重连,重试间隔写在实现中,为 30 秒;它不是此配置文件中的可调退避策略。重连不会替应用重放此前发送失败的业务消息。

发送与接收消息

连接可用后,通过 msg_module 发送应用自己的 Protobuf 消息。下面的函数接收调用方定义的消息 ID 和消息类型,不预设业务协议。

#include "ark/bus/msg_module.hpp"

bool send_to_process(ark::msg_module& messages, ark::bus_id_t target_id, ark::msg_id_t message_id,
    const google::protobuf::Message& body) {
    return messages.send_msg_by_bus_id(target_id, message_id, body);
}
发送接口 连接选择
send_msg_by_bus_id() 使用源进程与目标 Bus ID 对应的已有连接,生成进程间消息头
send_def_ss_msg_by_app_type() 在指定应用类型的客户端服务中,通过一致性哈希选择连接;当前选择键为本进程 Bus ID
send_def_cs_msg_by_app_type() 与上项采用相同的连接选择方式,使用客户端消息头
send_to_client() 通过外部监听服务,发送到指定 Session
send_to_intra() 通过内网监听服务,发送到指定 Session

进程间消息头携带消息 ID、源 / 目标 Bus ID 和 Actor ID。发送失败会返回 false,例如没有服务、连接不可用或序列化失败;返回 true 不表示远端业务已处理成功。需要请求响应、超时和幂等保证时,由应用协议实现。

接收流程是:网络服务拆出 net_msg → 按消息 ID 调用已注册回调 → 使用 msg_module::decode_protobuf() 解析业务消息。解析函数返回 false 表示 Protobuf 解析失败;read_message_body() 可复制原始消息体并取得 Actor ID。回调中的 net_msg* 是借用数据,需要延后处理时应先复制所需内容。

覆盖范围与后续工作

本页示例覆盖配置查询、显式 TCP 连接请求和已有连接上的消息发送。它不构成经过验收的多进程部署示例,也不保证所有协议在服务管理层均已接入。底层传输能力见 Net 插件。

TODO:提供独立的双进程示例与测试,覆盖连接建立、消息往返、进程重启、重连和跨机器路由;动态注册 / 发现另行实现和验证。

API 来源

导航

输入关键词开始搜索…

↑↓ 移动↵ 选择Esc 关闭