acid--rpc模块

rpc模块

rpc.h

  • rpc调用结果
template<typename T>
struct return_type {
    using type = T;
};

template<>
struct return_type<void> {
    using type = int8_t;
};

/**
 * @brief 调用结果为 void 类型的,将类型转换为 int8_t
 */
template<typename T>
using return_type_t = typename return_type<T>::type;
  • rpc调用状态
/**
 * @brief RPC调用状态
 */
enum RpcState{
    RPC_SUCCESS = 0,    // 成功
    RPC_FAIL,           // 失败
    RPC_NO_MATCH,       // 函数不匹配
    RPC_NO_METHOD,      // 没有找到调用函数
    RPC_CLOSED,         // RPC 连接被关闭
    RPC_TIMEOUT         // RPC 调用超时
};
  • 封装rpc调用结果
/**
 * @brief 包装 RPC调用结果
 */
template<typename T = void>
class Result{
public:
    using row_type = T;
    using type = return_type_t<T>;
    using msg_type = std::string;
    using code_type = uint16_t;

	...............
        
private:
    /// 调用状态
    code_type m_code = 0;
    /// 调用消息
    msg_type m_msg;
    /// 调用结果
    type m_val;
};

protocol. h

对于rpc通信协议报文的封装

报文格式:

/*
 * 私有通信协议
 * +--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
 * |  BYTE  |        |        |        |        |        |        |        |        |        |        |             ........                                                           |
 * +--------------------------------------------+--------+--------------------------+--------+-----------------+--------+--------+--------+--------+--------+--------+-----------------+
 * |  magic | version|  type  |          sequence id              |          content length           |             content byte[]                                                     |
 * +--------+-----------------------------------------------------------------------------------------------------------------------------+--------------------------------------------+
 * 第一个字节是魔法数。
 * 第二个字节代表协议版本号,以便对协议进行扩展,使用不同的协议解析器。
 * 第三个字节是请求类型,如心跳包,rpc请求。
 * 第四个字节开始是一个32位序列号。
 * 第七个字节开始的四字节表示消息长度,即后面要接收的内容长度。
 */

uint8_t m_magic = MAGIC;
uint8_t m_version = DEFAULT_VERSION;
uint8_t m_type = 0;
uint32_t m_sequence_id = 0;
uint32_t m_content_length = 0;
std::string m_content;

// 一大堆getter和setter
.......

// Meta是只encode |magic|version|type| sequence id|content length 
ByteArray::ptr encodeMeta();
// encode |magic|version|type| sequence id|content length|content
ByteArray::ptr encode();

// 同理
void decodeMeta(ByteArray::ptr bt);
void decode(ByteArray::ptr bt);

报文类型:

  • HEARTBEAT_PACKET: RpcClient 《----》RpcServiceRegistry 、RpcServer 《----》RpcServiceRegistry ,用以确保对方在线。
  • RPC_PROVIDER:向服务中心声明为provider。RpcServer ----》RpcServiceRegistry。
  • RPC_CONSUMER:向服务中心声明为consumer。RpcClient ----》RpcServiceRegistry。
  • RPC_REQUEST:通用请求。项目没有使用。
  • RPC_RESPONSE:通用响应。项目没有使用。
  • RPC_METHOD_REQUEST:请求方法调用。RpcClient ----》RpcServer。
  • RPC_METHOD_RESPONSE:响应方法调用。RpcServer ----》RpcClient 。
  • RPC_SERVICE_REGISTER:向中心注册服务。RpcServer ----》RpcServiceRegistry。
  • RPC_SERVICE_REGISTER_RESPONSE:中心响应服务注册。 RpcServiceRegistry ----》RpcServer 。
  • RPC_SUBSCRIBE_REQUEST:订阅服务。RpcClient ----》RpcServiceRegistry、RpcClient ----》RpcServer。
  • RPC_SUBSCRIBE_RESPONSE:响应订阅服务。RpcServiceRegistry ----》RpcClient 、RpcServer ----》RpcClient 。
  • RPC_PUBLISH_REQUEST:发布服务。RpcServiceRegistry ----》RpcClient 、RpcServer ----》RpcClient 。
  • RPC_PUBLISH_RESPONSE:响应发布服务。RpcClient ----》RpcServiceRegistry、RpcClient ----》RpcServer。

serialize

/**
 * @brief RPC 序列化 / 反序列化包装,会自动进行网络序转换
 * @details 序列化有以下规则:
 * 1.默认情况下序列化,8,16位类型以及浮点数不压缩,32,64位有符号/无符号数采用 zigzag 和 varints 编码压缩
 * 2.针对 std::string 会将长度信息压缩序列化作为元数据,然后将原数据直接写入。char数组会先转换成 std::string 后按此规则序列化
 * 3.调用 writeFint 将不会压缩数字,调用 writeRowData 不会加入长度信息
 *
 * 支持标准库容器:
 * 顺序容器:string, list, vector
 * 关联容器:set, multiset, map, multimap
 * 无序容器:unordered_set, unordered_multiset, unordered_map, unordered_multimap
 * 异构容器:tuple
 */

Serializer只有一个ByteArray。

write

C++11 constexpr:验证是否为常量表达式(长篇神文) (biancheng.net)

	/**
     * @brief 写入原始数据
     */
    void writeRowData(const char* in, int len){
        m_byteArray->write(in, len);
    }
    /**
     * @brief 写入无压缩数字
     */
    template<class T>
    void writeFint(T value){
        m_byteArray->writeFint(value);
    }
	
	template<typename T>
    void write(T t) {
        if constexpr(std::is_same_v<T, bool>){
            m_byteArray->writeFint8(t);
        } else if constexpr(std::is_same_v<T, float>){
            m_byteArray->writeFloat(t);
        } else if constexpr(std::is_same_v<T, double>){
        .........
    }

read

	template<typename T>
    void read(T& t) {
        if constexpr(std::is_same_v<T, bool>){
            t = m_byteArray->readFint8();
        } else if constexpr(std::is_same_v<T, float>){
            t = m_byteArray->readFloat();
        } else if constexpr(std::is_same_v<T, double>){
            t = m_byteArray->readDouble();
        } else if constexpr(std::is_same_v<T, int8_t>){
        ............
    }

流操作符重载

serializer >> val (向val写入值)

serializer << val (将val写入serializer)

  • 最基本的重载:单个值
	template<typename T>
    [[maybe_unused]]
    Serializer &operator >> (T& i){
        read(i);
        return *this;
    }

    template<typename T>
    [[maybe_unused]]
    Serializer &operator << (const T& i){
        write(i);
        return *this;
    }

顺序容器

  • list
	template<typename T>
    Serializer &operator >> (std::list<T>& v){
        size_t size; // 先读list的size
        read(size);
        for (size_t i = 0; i < size; ++i) {
            T t;
            read(t);
            v.template emplace_back(t);
        }
        return *this;
    }

    template<typename T>
    Serializer &operator << (const std::list<T>& v){
        write(v.size()); // 先写list的size
        for(auto& t : v) {
            (*this) << t;
        }
        return *this;
    }
  • vector
	template<typename T>
    Serializer &operator >> (std::vector<T>& v){
        size_t size;
        read(size);
        for (size_t i = 0; i < size; ++i) {
            T t;
            read(t);
            v.template emplace_back(t);
        }
        return *this;
    }

    template<typename T>
    Serializer &operator << (const std::vector<T>& v){
        write(v.size());
        for(auto& t : v) {
            (*this) << t;
        }
        return *this;
    }

关联容器

  • set与multiset一样,这里只看set
	template<typename T>
    Serializer &operator >> (std::set<T>& v){
        size_t size;
        read(size);
        for (size_t i = 0; i < size; ++i) {
            T t;
            read(t);
            v.template emplace(t);
        }
        return *this;
    }

    template<typename T>
    Serializer &operator << (const std::set<T>& v){
        write(v.size());
        for(auto& t : v) {
            (*this) << t;
        }
        return *this;
    }
  • pair
	template<typename K, typename V>
    Serializer &operator << (const std::pair<K,V>& m){
        (*this) << m.first << m.second;
        return *this;
    }

    template<typename K, typename V>
    Serializer &operator >> (std::pair<K,V>& m){
        (*this) >> m.first >> m.second;
        return *this;
    }
  • map与multimap一样。这里只看map
	template<typename K, typename V>
    Serializer &operator >> (std::map<K,V>& m){
        size_t size;
        read(size);
        for (size_t i = 0; i < size; ++i) {
            std::pair<K,V> p;
            (*this) >> p;
            m.template emplace(p);
        }
        return *this;
    }

    template<typename K, typename V>
    Serializer &operator << (const std::map<K,V>& m){
        write(m.size());
        for(auto& t : m) {
            (*this) << t;
        }
        return *this;
    }

无序容器

  • unordered_set/unordered_multiset与set/multiset一样。
  • unordered_map/unordered_multimap与map/multimap一样。

异构容器tuple

tuple是一个固定大小的不同类型值的集合,是泛化的std::pair。我们也可以把他当做一个通用的结构体来用,不需要创建结构体又获取结构体的特征,在某些情况下可以取代结构体使程序更简洁,直观。std::tuple理论上可以有无数个任意类型的成员变量,而std::pair只能是2个成员,因此在需要保存3个及以上的数据时就需要使用tuple元组了。

template<typename... Args>
Serializer &operator >> (std::tuple<Args...>& t){
    /**
    * @brief 实际的反序列化函数,利用折叠表达式展开参数包
    */
    /* 
    [this] 按值传递捕获this指针
    <typename Tuple, std::size_t... Index> 是模板参数
    
    */
    const auto& deserializer = [this]<typename Tuple, std::size_t... Index>(Tuple& t, std::index_sequence<Index...>) {
        (void)((*this) >> ... >> std::get<Index>(t));
    };
    deserializer(t, std::index_sequence_for<Args...>{});
    return *this;
}

template<typename... Args>
Serializer &operator << (const std::tuple<Args...>& t){
    /**
    * @brief 实际的序列化函数,利用折叠表达式展开参数包
    */
    const auto& package = [this]<typename Tuple, std::size_t... Index>
        (const Tuple& t, std::index_sequence<Index...>) {
        (void)((*this) << ... << std::get<Index>(t));
    };
    package(t, std::index_sequence_for<Args...>{});
    return *this;
}

rpc_session

  • rpc session 继承自 SocketStream , 封装了协议的收发
  • rpc_session 是面向于
// 从sock stream 读取内容, 然后构造 Protocol
Protocol::ptr RpcSession::recvProtocol();

// 发送报文
ssize_t RpcSession::sendProtocol(Protocol::ptr proto);

rpc_service_register

RpcServiceRegistry继承自TcpServer。其主要流程就是tcp server监听端口,然后accept,建立连接,监听socket,其回调函数为handleClient。handleClient会根据rpc的报文类型来调用不同的handler。

  • 作用:
/**
 * @brief RPC服务注册中心
 * @details 接收客户端服务发现请求。接收服务端服务注册请求,断开连接后移除服务。
 * 以上统称为服务注册中心的用户
 */
  • data member
/**
* 维护服务名和服务地址列表的多重映射
* serviceName -> serviceAddress1
*             -> serviceAddress2
*             ...
*/
std::multimap<std::string, std::string> m_services; 

// 维护服务地址到(m_services)迭代器的映射(方便后续服务下线删除)。
// 因为key是servicename,val是addresss vector,当服务下线时,要删除对应的服务地址。只能保存其迭代器。
// 因为serviceName与serviceAddress是一对多的关系,所以second是vector
std::map<std::string, std::vector<std::multimap<std::string, std::string>::iterator>> m_iters;


MutexType m_mutex;
// 允许心跳超时的时间 默认 40s
uint64_t m_AliveTime;

// 订阅的客户端
// first:RPC_SERVICE_SUBSCRIBE + serviceName
// second:RpcSession
std::unordered_multimap<std::string, std::weak_ptr<RpcSession>> m_subscribes;

// 保护 m_subscribes
MutexType m_sub_mtx;
// 停止清理订阅协程
bool m_stop_clean = false;
// 等待清理协程停止
Channel<bool> m_clean_chan{1};
  • 构造函数:绑定两个IOManager。一个用于监听,一个用于处理连接。开启协程定时清理订阅列表。
RpcServiceRegistry::RpcServiceRegistry(IOManager *worker, IOManager *accept_worker)
        : TcpServer(worker, accept_worker)
        , m_AliveTime(s_heartbeat_timeout){
    setName("RpcServiceRegistry");

    // 开启协程定时清理订阅列表
    Go {
        while (!m_stop_clean) {
            sleep(5); // 每隔5s检查一次
            MutexType::Lock lock(m_sub_mtx);
            for (auto it = m_subscribes.cbegin(); it != m_subscribes.cend();) {
                auto conn = it->second.lock(); // weak_ptr lock 提升为 shared_ptr 
                if (conn == nullptr || !conn->isConnected()) { // 检查session是否失效,失效就移除
                    it = m_subscribes.erase(it);
                } else {
                    ++it;
                }
            }
        }
        m_clean_chan << true; // 返回协程清理完毕
    };
}
  • 发布消息publish:只有当服务上线和服务下线时才会才会调用publish函数。

传入的key是RPC_SERVICE_SUBSCRIBE + serviceName。data是

std::tuple<bool, std::string> data { true, serviceAddress}; // 服务上线消息
std::tuple<bool, std::string> data { false, address->toString()}; // 服务下线消息
/**
* @brief 发布消息
* @param[in] key 发布的key
* @param[in] data 支持 Serializer 的都可以发布
*/
template <typename T>
void publish(const std::string& key, T data) {
    {
        MutexType::Lock lock(m_sub_mtx);
        if (m_subscribes.empty()) {
            return;
        }
    }
    // 将data序列化
    Serializer s;
    s << key << data;
    s.reset();
    
    // 构造相应报文(服务上线或者下线看的是data中的第一个变量是true还是false)
    Protocol::ptr pub = Protocol::Create(Protocol::MsgType::RPC_PUBLISH_REQUEST, s.toString(), 0);
    MutexType::Lock lock(m_sub_mtx);
    auto range = m_subscribes.equal_range(key); // 根据key查找订阅该service 的 subscriber
    for (auto it = range.first; it != range.second; ++it) {
        auto conn = it->second.lock();
        if (conn == nullptr || !conn->isConnected()) {
            continue;
        }
        // 给subscriber发送服务发布消息
        conn->sendProtocol(pub);
    }
}
  • 更新心跳定时器:RpcServiceRegistry每次收到报文后,就重启定时器(将其超时时间重新设置为m_AliveTime)。一旦距离上一次收到该client的报文的时间超过m_AliveTime,就client->close()。
void RpcServiceRegistry::update(Timer::ptr& heartTimer, Socket::ptr client) {
    ACID_LOG_DEBUG(g_logger) << "update heart";
    if (!heartTimer) {
        heartTimer = m_worker->addTimer(m_AliveTime, [client]{
            ACID_LOG_DEBUG(g_logger) << "client:" << client->toString() << " closed";
            client->close();
        });
        return;
    }
    // 更新定时器
    heartTimer->reset(m_AliveTime, true);
}

重写:handleClient

要明确,对于service register来说,client有两类:

  • 一个是service consumer
  • 一个是service provider

对于每个client的处理逻辑:

  • 开启心跳定时器,每次收到报文后,就重启定时器,在允许心跳超时的时间 (默认 40s)内没有消息获取,就断开该连接(RpcSession)
  • 然后就是接收报文,根据报文类型进行处理,将处理结果封装为报文发送回去
    • handleUnregisterService:如果接收到的报文为空(不合法),且providerAddr不为空(代表这个client是provider),则代表对应的provider下线。给每个订阅了该service的subscriber都发送一个服务下线报文。
    • HEARTBEAT_PACKET & handleHeartbeatPacket:如果service register接收到的是心跳包(HEARTBEAT_PACKET),client发送的是心跳包,则给client返回一个心跳包(无论client是service provider或者service consumer)。
    • RPC_PROVIDER & handleProvider:收到这样一个包,代表client是provider。用providerAddr记录地址。
    • RPC_SERVICE_REGISTER & handleRegisterService:给provider返回一个服务注册响应报文(RPC_SERVICE_REGISTER_RESPONSE),并给所有订阅该服务的subscriber发送一个(RPC_PUBLISH_REQUEST)服务上线消息(其实就是让subscriber将这个新的地址保存起来,以备后用)。
    • RPC_SERVICE_DISCOVER & handleDiscoverService:收到一个服务发现的包,代表client是consumer。将查找符合的地址并返回给client(包类型是RPC_SERVICE_DISCOVER_RESPONSE)。
    • RPC_SUBSCRIBE_REQUEST & handleSubscribe:收到这样一个包,代表client是consumer。将(servicename,RpcSession)加入到m_subscribes,方便后面服务上线通知client。
// 处理每个client的回调函数
void RpcServiceRegistry::handleClient(Socket::ptr client) {
    ACID_LOG_DEBUG(g_logger) << "handleClient: " << client->toString();
    RpcSession::ptr session = std::make_shared<RpcSession>(client);
    Timer::ptr heartTimer;
    // 为当前client开启心跳定时器
    update(heartTimer, client);
	
    Address::ptr providerAddr;
    while (true) {
        Protocol::ptr request = session->recvProtocol();
        if (!request) {
            if (providerAddr) { // provider地址为空,代表服务还未上线或者已经下线
                ACID_LOG_WARN(g_logger) << client->toString() << " was closed; unregister " << providerAddr->toString();
                handleUnregisterService(providerAddr); 
            }
            return;
        }
        // 更新定时器
        update(heartTimer, client);

        Protocol::ptr response;
        Protocol::MsgType type = request->getMsgType();

        switch (type) {
            case Protocol::MsgType::HEARTBEAT_PACKET: // 心跳包
                response = handleHeartbeatPacket(request);
                break;
            case Protocol::MsgType::RPC_PROVIDER: // 向服务中心声明为provider
                ACID_LOG_DEBUG(g_logger) << client->toString();
                providerAddr = handleProvider(request, client);
                continue;
            case Protocol::MsgType::RPC_SERVICE_REGISTER: // 向中心注册服务
                response = handleRegisterService(request, providerAddr);
                break;
            case Protocol::MsgType::RPC_SERVICE_DISCOVER: // 向中心请求服务发现
                response = handleDiscoverService(request);
                break;
            case Protocol::MsgType::RPC_SUBSCRIBE_REQUEST: // 订阅
                response = handleSubscribe(request, session);
                break;
            case Protocol::MsgType::RPC_PUBLISH_RESPONSE:
                continue;
            default:
                ACID_LOG_WARN(g_logger) << "protocol:" << request->toString();
                continue;
        }

        session->sendProtocol(response);
    }
}

对各种rpc包的处理:

心跳包

对于收到一个心跳包的处理就是返回一个心跳包。

Protocol::ptr RpcServiceRegistry::handleHeartbeatPacket(Protocol::ptr p) {
    return Protocol::HeartBeat();
}

向服务中心声明为provider

获取当前session的对端地址,保存到providerAddr。并且从报文中读出server注册的服务端口。

Address::ptr RpcServiceRegistry::handleProvider(Protocol::ptr p, Socket::ptr sock){
    uint32_t port = 0;
    Serializer s(p->getContent());
    s.reset();
    s >> port;
    IPv4Address::ptr address(new IPv4Address(*std::dynamic_pointer_cast<IPv4Address>(sock->getRemoteAddress())));
    address->setPort(port);
    return address;
}

向中心注册服务

RpcServer 向 RpcServiceRegistry 注册服务的报文内容就是 serviceName。

m_services保存 servicename 到 service address的映射。

向 RpcServer 返回一个 RPC_SERVICE_REGISTER_RESPONSE 报文。

对订阅该服务的RpcClient发布服务上线消息。

/**
* 为服务端提供服务注册
* 将服务地址注册到对应服务名下
* 断开连接后地址自动清除
* @param serviceName 服务名称
* @param serviceAddress 服务地址
*/
Protocol::ptr RpcServiceRegistry::handleRegisterService(Protocol::ptr p, Address::ptr address) {
    std::string serviceAddress = address->toString();
    std::string serviceName = p->getContent();

    MutexType::Lock lock(m_mutex);
    // 服务注册添加表项(服务名-》服务地址)
    auto it = m_services.emplace(serviceName, serviceAddress);
    // 添加迭代器记录
    m_iters[serviceAddress].push_back(it);
    lock.unlock();

    Result<std::string> res = Result<std::string>::Success();
    res.setVal(serviceName);

    Serializer s;
    s << res;
    s.reset();
	// 服务注册成功相应报文
    Protocol::ptr proto =
            Protocol::Create(Protocol::MsgType::RPC_SERVICE_REGISTER_RESPONSE, s.toString());

    // 发布服务上线消息
    std::tuple<bool, std::string> data { true, serviceAddress};
    publish(RPC_SERVICE_SUBSCRIBE + serviceName, data);

    return proto;
}

移除注册服务

当RpcServiceRegistry收到RpcServer一个不合法或者是空的报文时,代表对应的服务下线。

m_services 移除 该服务的记录。

对 RpcClient 发布服务下线消息。

void RpcServiceRegistry::handleUnregisterService(Address::ptr address) {
    MutexType::Lock lock(m_mutex);
    // m_iters维护服务地址到迭代器的映射
    auto it = m_iters.find(address->toString());
    if (it == m_iters.end()) {
        return;
    }
    auto its = it->second; // its类型是std::vector<std::multimap<std::string, std::string>::iterator>
    for (auto& i: its) {
        // i是m_services的迭代器
        // i->first 对应 serviceName
        // i->second 对应 serviceAddress
        m_services.erase(i); // 从已注册的服务列表删除该服务
        
        // 发布服务下线消息
        std::tuple<bool, std::string> data { false, address->toString()};
        publish(RPC_SERVICE_SUBSCRIBE + i->first, data);
    }
    // m_iters也删除对应的记录
    m_iters.erase(address->toString());
}

服务发现

当RpcClient向RpcServiceRegistry发送服务发现的报文,其报文内容是serviceName。

如果服务还没上线,就返回 RPC_NO_METHOD 。

如果服务已上线,就将所有符合的address封装返回,RPC_SUCCESS。

Protocol::ptr RpcServiceRegistry::handleDiscoverService(Protocol::ptr p) {
    // RPC_SERVICE_DISCOVER类型的报文的主题内容是serviceName
    std::string serviceName = p->getContent();
    std::vector<Result<std::string>> result;
    ByteArray byteArray;

    MutexType::Lock lock(m_mutex);
    m_services.equal_range(serviceName);
    auto range = m_services.equal_range(serviceName);
    uint32_t cnt = 0;
    
    // 未注册服务:RPC_NO_METHOD
    if (range.first == range.second) {
        cnt++;
        Result<std::string> res;
        res.setCode(RPC_NO_METHOD);
        res.setMsg("discover service:" + serviceName);
        result.push_back(res);
    } else {
        for (auto i = range.first; i != range.second; ++i) {
            Result<std::string> res; // 将服务地址封装为Result<std::string>,并加入到result
            std::string addr;
            res.setCode(RPC_SUCCESS); // RPC_SUCCESS
            res.setVal(i->second);
            result.push_back(res);
        }
        cnt = result.size();
    }

    Serializer s;
    s << serviceName << cnt;
    for (uint32_t i = 0; i < cnt; ++i) {
        s << result[i];
    }
    s.reset();
    // 将一些列服务地址封装为RPC_SERVICE_DISCOVER_RESPONSE报文并返回
    Protocol::ptr proto =
            Protocol::Create(Protocol::MsgType::RPC_SERVICE_DISCOVER_RESPONSE, s.toString());
    return proto;
}

订阅

RpcClient向RpcServiceRegistry订阅服务的报文内容是RPC_SERVICE_SUBSCRIBE + name。

将其加入到subscriber列表(注意是weak_ptr,这样不影响该连接销毁)。

向RpcClient返回一个RPC_SUBSCRIBE_RESPONSE报文。

Protocol::ptr RpcServiceRegistry::handleSubscribe(Protocol::ptr proto, RpcSession::ptr client) {
    MutexType::Lock lock(m_sub_mtx);
    std::string key;
    // 读取rpc报文内容写到key
    Serializer s(proto->getContent());
    s >> key;
    // 加入到subscriber列表
    m_subscribes.emplace(key, std::weak_ptr<RpcSession>(client));
    Result<> res = Result<>::Success();
    s.reset();
    s << res;
    // 返回订阅成功报文
    return Protocol::Create(Protocol::MsgType::RPC_SUBSCRIBE_RESPONSE, s.toString(), 0);
}

rpc_client

/**
 * @brief RPC客户端
 * @details
 * 开启一个 send 协程,通过 Channel 接收调用请求,并转发 request 请求给服务器。
 * 开启一个 recv 协程,负责接收服务器发送的 response 响应并通过序列号获取对应调用者的 Channel,
 * 将 response 放入 Channel 唤醒调用者。
 * 所有调用者的 call 请求将通过 Channel 发送给 send 协程, 然后开启一个 Channel 用于接收 response 响应,
 * 并将请求序列号与自己的 Channel 关联起来。
 */

成员变量

private:
    // 是否自动开启心跳包
    bool m_auto_heartbeat = true;
    bool m_isClose = true; // 短链接?
    bool m_isHeartClose = true; // 心跳是否停止
    // 超时时间
    uint64_t m_timeout = -1;
    // 服务器的连接
    RpcSession::ptr m_session;
    // 序列号
    uint32_t m_sequenceId = 0;
    // 序列号到对应调用者协程的 Channel 映射 (当收到RpcServer的处理结果后,通过将结果发送给channel,channel唤醒调用方)
    std::map<uint32_t, Channel<Protocol::ptr>> m_responseHandle;
    // m_responseHandle 的 mutex
    MutexType m_mutex;
    // 消息发送通道
    Channel<Protocol::ptr> m_chan;
    // service provider心跳定时器
    Timer::ptr m_heartTimer;
    // 处理订阅的消息回调函数
    std::map<std::string, std::function<void(Serializer)>> m_subHandle;
    // 保护m_subHandle
    MutexType m_sub_mtx;

connect

连接一个RPC服务器

  1. 创建tcp socket,并连接到rpc server;
  2. 将这个连接初始化为RpcSession,记录到m_session;
  3. 开启两个协程:recv 协程、send 协程。recv:接收来自RpcServer发来的(响应)报文,根据报文类型作出相应的处理。send:通过 Channel 收集调用请求,如果没有消息时 Channel 内部会挂起该协程等待消息到达,然后将请求发送到RpcServer;
  4. 创建心跳定时器。如果m_auto_heartbeat开启了自动心跳,则定时向 send 协程的 Channel 发送心跳包(即向RpcServer发送心跳包)。
bool RpcClient::connect(Address::ptr address){
    Socket::ptr sock = Socket::CreateTCP(address);

    if (!sock) {
        return false;
    }
    if (!sock->connect(address, m_timeout)) {
        m_session = nullptr;
        return false;
    }
    m_isHeartClose = false;
    m_isClose = false;
    m_session = std::make_shared<RpcSession>(sock);
    m_chan = Channel<Protocol::ptr>(s_channel_capacity);
    go [this] {
        // 开启 recv 协程
        handleRecv();
    };
    go [this] {
        // 开启 send 协程
        handleSend();
    };

    if (m_auto_heartbeat) { // 如果开启了心跳,
        m_heartTimer = IOManager::GetThis()->addTimer(30'000, [this]{
            ACID_LOG_DEBUG(g_logger) << "heart beat";
            if (m_isHeartClose) {
                ACID_LOG_DEBUG(g_logger) << "Server closed";
                close();
            }
            // 向 send 协程的 Channel 发送消息
            Protocol::ptr proto = Protocol::Create(Protocol::MsgType::HEARTBEAT_PACKET, "");
            m_chan << proto;
            // send协程收到心跳包后m_isHeartClose会置false,
            // 如果没有收到,则 m_isHeartClose = true 会影响上面的if判断
            m_isHeartClose = true; 
        }, true);
    }

    return true;
}

析构函数 & close

析构函数调用close函数

  1. close send协程的channel;
  2. 取消心跳定时器;
  3. 关闭每个调用者的channel;
  4. 关闭连接到RpcServer的session。

handleSend发送报文

通过 Channel 收集调用请求,如果没有消息时 Channel 内部会挂起该协程等待消息到达(其实不一定是请求,也可能是响应服务发布上线或者下线)。

void RpcClient::handleSend() {
    Protocol::ptr request;
    // 通过 Channel 收集调用请求,如果没有消息时 Channel 内部会挂起该协程等待消息到达
    // Channel 被关闭时会退出循环
    while (m_chan >> request) {
        if (!request) {
            ACID_LOG_WARN(g_logger) << "RpcClient::handleSend() fail";
            continue;
        }
        // 向RpcServer发送请求报文
        m_session->sendProtocol(request);
    }
}

handleRecv接收报文

接收来自RpcServer发来的(响应)报文,根据报文类型作出相应的处理:

  • HEARTBEAT_PACKET:收到心跳包,代表与RpcServer的session还有效。m_isHeartClose = false(心跳未停止)。
  • RPC_METHOD_RESPONSE:收到处理结果,通过序列号获取对应调用者的 Channel,将 response 放入 Channel 唤醒调用者。
  • RPC_PUBLISH_REQUEST:找到并调用处理订阅的消息回调函数。
  • RPC_SUBSCRIBE_RESPONSE:响应服务上线下线。
void RpcClient::handleRecv() {
    if (!m_session->isConnected()) {
        return;
    }
    while (true) {
        // 接收响应
        Protocol::ptr response = m_session->recvProtocol();
        
        if (!response) { // 如果收到的报文不合法,close 掉连接到RpcServer的session
            ACID_LOG_WARN(g_logger) << "RpcClient::handleRecv() fail";
            close();
            break;
        }
        m_isHeartClose = false;
        Protocol::MsgType type = response->getMsgType();
        // 判断响应类型进行对应的处理
        switch (type) {
            case Protocol::MsgType::HEARTBEAT_PACKET:
                m_isHeartClose = false;
                break;
            case Protocol::MsgType::RPC_METHOD_RESPONSE:
                // 处理调用结果
                handleMethodResponse(response);
                break;
            case Protocol::MsgType::RPC_PUBLISH_REQUEST:
                // 服务发布(上线或者下线)
                handlePublish(response);
                // 响应 服务发布(上线或者下线)
                m_chan << Protocol::Create(Protocol::MsgType::RPC_PUBLISH_RESPONSE,"");
                break;
            case Protocol::MsgType::RPC_SUBSCRIBE_RESPONSE:
                // 订阅响应
                break;
            default:
                ACID_LOG_DEBUG(g_logger) << "protocol:" << response->toString();
                break;
        }
    }
}

收到服务发布的回调函数:??

void RpcClient::handlePublish(Protocol::ptr proto) {
    Serializer s(proto->getContent());
    std::string key;
    s >> key;
    MutexType::Lock lock(m_sub_mtx);
    auto it = m_subHandle.find(key);
    if (it == m_subHandle.end()) return;
    it->second(s);
}

收到调用结果的回调函数:获取该调用结果的序列号,序列号对应一个channel,对该 Channel 发送调用结果唤醒调用者,调用方可以通过这个channel来获取调用结果。

void RpcClient::handleMethodResponse(Protocol::ptr response) {
    // 获取该调用结果的序列号
    uint32_t id = response->getSequenceId();
    std::map<uint32_t, Channel<Protocol::ptr>>::iterator it;

    MutexType::Lock lock(m_mutex);
    // 查找该序列号的 Channel 是否还存在,如果不存在直接返回
    it = m_responseHandle.find(id);
    if (it == m_responseHandle.end()) {
        return;
    }
    // 通过序列号获取等待该结果的 Channel
    Channel<Protocol::ptr> chan = it->second;
    // 对该 Channel 发送调用结果唤醒调用者
    chan << response;
}

call 调用请求

	/**
     * @brief 实际调用
     * @param[in] s 序列化完的请求
     * @return 返回调用结果
     */
    template<typename R>
    Result<R> call(Serializer s) {
        Result<R> val;
        // 检查session是否存在,不存在直接返回空的结果。RPC_CLOSED
		Result<R> val;
        if (!m_session || !m_session->isConnected()) {
            val.setCode(RPC_CLOSED);
            val.setMsg("socket closed");
            return val;
        }
        
        // 开启一个 Channel 接收调用结果
        Channel<Protocol::ptr> recvChan(1);
        
        // 将请求序列号与接收 Channel 关联,并放入m_responseHandle
        uint32_t id = 0;
        std::map<uint32_t, Channel<Protocol::ptr>>::iterator it;
        {
            MutexType::Lock lock(m_mutex);
            id = m_sequenceId;
            it = m_responseHandle.emplace(m_sequenceId, recvChan).first;
            ++m_sequenceId;
        }

        // 创建调用请求报文,附带上请求 id
        Protocol::ptr request =
                Protocol::Create(Protocol::MsgType::RPC_METHOD_REQUEST,s.toString(), id);

        // 向 send 协程的 Channel 发送消息
        m_chan << request;
		
        // 下面的步骤就是等待返回结果..........
     
        acid::Timer::ptr timer;
        bool timeout = false;
        if( m_timeout != (uint64_t)-1 ){ // 设置了调用超时
            // 如果调用超时则关闭接收 Channel
        }
		
        // 等待 response,Channel内部会挂起协程,如果有消息到达或者被关闭则会被唤醒
        Protocol::ptr response;
        recvChan >> response;
		
        // response在超时期限内容返回,关闭定时器
        if(timer){
            timer->cancel();
        }
		
        // 结果都收到了,这个channel已经没用了。删除序列号与 Channel 的映射
        {
            MutexType::Lock lock(m_mutex);
            if (!m_isClose) {    
                m_responseHandle.erase(it);
            }
        }
		
        if (timeout) {
        	// 超时,返回空的结果    
        }
		
        // response报文为空,返回RPC_CLOSED
		
        // response报文的主体内容为空,返回RPC_NO_METHOD
		
        // 将返回结果反序列化并返回
    }
  • 对外暴露的call
    /**
     * @brief 有参数的调用
     * @param[in] name 函数名
     * @param[in] ps 可变参
     * @return 返回调用结果
     */
    template<typename R, typename... Params>
    Result<R> call(const std::string& name, Params... ps) {
        using args_type = std::tuple<typename std::decay<Params>::type...>;
        args_type args = std::make_tuple(ps...);
        Serializer s;
        s << name << args;
        s.reset();
        return call<R>(s);
    }
    /**
     * @brief 无参数的调用
     * @param[in] name 函数名
     * @return 返回调用结果
     */
    template<typename R>
    Result<R> call(const std::string& name) {
        Serializer s;
        s << name;
        s.reset();
        return call<R>(s);
    }
    /**
     * @brief 异步调用,返回一个 Channel
     */
    template<typename R,typename... Params>
    Channel<Result<R>> async_call(const std::string& name, Params&& ... ps) {
        Channel<Result<R>> chan(1);
        RpcClient::ptr self = shared_from_this();
        // 开启一个协程
        go [self, chan, name, ps..., this] () mutable {
            chan << call<R>(name, ps...);
            self = nullptr; // 释放
        };
        return chan;
    }
  • callback????
 	/**
     * @brief 异步回调模式
     * @param[in] callback 回调函数
     * @param[in] name 函数名
     * @param[in] ps 可变参
     */
    template<typename... Params>
    void callback(const std::string& name, Params&&... ps) {
        auto tp = std::make_tuple(ps...); // 将可变模板参数变为一个tuple,方便序列化
        constexpr auto size = std::tuple_size<typename std::decay<decltype(tp)>::type>::value; // 获取参数个数
        auto cb = std::get<size-1>(tp);
        using res = typename function_traits<decltype(cb)>::args<0>::type;
        using rt = typename res::row_type;
        
        RpcClient::ptr self = shared_from_this();
        go [cb = std::move(cb), name = std::move(name), tp = std::move(tp), size, self, this] {
            auto proxy = [&cb, &name, &tp, &size, &self, this]<std::size_t... Index>(std::index_sequence<Index...>){
                cb(call<rt>(name, std::get<Index>(tp)...));
            };
            proxy(std::make_index_sequence<size - 1>{});
        };
    }

subscribe

/**
* @brief 订阅消息
* @param[in] key 订阅的key
* @param[in] func 回调函数
*/
// Func类型是std::function<void(Serializer)
template<typename Func>
void subscribe(const std::string& key, Func func) {
    {
        MutexType::Lock lock(m_sub_mtx);
        auto it = m_subHandle.find(key);
        if (it != m_subHandle.end()) { // 已有回调函数,直接return
            ACID_ASSERT2(false, "duplicated subscribe");
            return;
        }
		// 添加回调函数
        m_subHandle.emplace(key, std::move(func));
    }
    // 向RpcServer发送订阅请求(subscribe request)
    Serializer s;
    s << key;
    s.reset();
    Protocol::ptr request = Protocol::Create(Protocol::MsgType::RPC_SUBSCRIBE_REQUEST, s.toString(), 0);
    m_chan << request;
}

rpc_connection_pool

RPC客户端连接池

成员变量

private:
    bool m_isClose = true; // 连接池是否已经关闭
    bool m_isHeartClose = true; // 心跳是否停止
    uint64_t m_timeout;	// 请求超时时间
    // 保护 m_conns
    MutexType m_connMutex;
    // 服务名到全部缓存的服务地址列表映射
    std::map<std::string, std::vector<std::string>> m_serviceCache;
    // 服务名和服务地址的连接池
    std::map<std::string, RpcClient::ptr> m_conns;
    // 服务注册中心连接
    RpcSession::ptr m_registry;
    // 服务注册中心心跳定时器
    Timer::ptr m_heartTimer;
    // 向服务注册中心消息发送通道
    Channel<Protocol::ptr> m_chan;
    // 服务名到对应调用者协程的 Channel 映射 
    std::map<std::string, Channel<Protocol::ptr>> m_discover_handle;
    // m_discover_handle 的 mutex
    MutexType m_discover_mutex;
    // 处理订阅的消息回调函数
    std::map<std::string, std::function<void(Serializer)>> m_subHandle;
    // 保护m_subHandle
    MutexType m_sub_mtx;

connect

这里connect到service registry。

bool RpcConnectionPool::connect(Address::ptr address){
    // 连接到 registry
    Socket::ptr sock = Socket::CreateTCP(address);
    if (!sock) {
        return false;
    }
    if (!sock->connect(address, m_timeout)) {
        ACID_LOG_ERROR(g_logger) << "connect to register fail";
        m_registry = nullptr;
        return false;
    }
    m_registry = std::make_shared<RpcSession>(sock);


    go [this] {
        // 开启 recv 协程
        handleRecv();
    };

    go [this] {
        // 开启 send 协程
        handleSend();
    };

    // 服务中心心跳定时器 30s
    m_heartTimer = acid::IOManager::GetThis()->addTimer(30'000, [this]{
        ACID_LOG_DEBUG(g_logger) << "heart beat";
        if (m_isHeartClose) {
            ACID_LOG_DEBUG(g_logger) << "registry closed";
            //放弃服务中心
            m_heartTimer->cancel();
            m_heartTimer = nullptr;
        }
        // 创建心跳包
        Protocol::ptr proto = Protocol::Create(Protocol::MsgType::HEARTBEAT_PACKET, "");
        // 向 send 协程的 Channel 发送消息
        m_chan << proto;
        m_isHeartClose = true; // send协程置为true
    }, true);

    return true;
}

handleSend发送报文

和RpcClient的handleSend一样。只不过这里的发送的报文是发给registry。

/**
     * @brief rpc 连接对象的发送协程,通过 Channel 收集调用请求,并转发请求给注册中心。
     */
void RpcConnectionPool::handleSend() {
    Protocol::ptr request;
    // 通过 Channel 收集调用请求,如果没有消息时 Channel 内部会挂起该协程等待消息到达
    // Channel 被关闭时会退出循环
    while (m_chan >> request) {
        if (!request) {
            ACID_LOG_WARN(g_logger) << "RpcConnectionPool::handleSend() fail";
            continue;
        }
        // 发送请求
        m_registry->sendProtocol(request);
    }
}

handleRecv接收报文

和RpcClient的handleRecv一样。只不过这里的接收的报文是来自registry。

/**
     * @brief rpc 连接对象的接收协程,负责接收注册中心发送的 response 响应并根据响应类型进行处理
     */
void RpcConnectionPool::handleRecv() {
    if (!m_registry->isConnected()) {
        return;
    }
    while (true) {
        // 接收响应
        Protocol::ptr response = m_registry->recvProtocol();
        if (!response) {
            ACID_LOG_WARN(g_logger) << "RpcConnectionPool::handleRecv() fail";
            close();
            break;
        }
        m_isHeartClose = false;
        Protocol::MsgType type = response->getMsgType();
        // 判断响应类型进行对应的处理
        switch (type) {
            case Protocol::MsgType::HEARTBEAT_PACKET: // 心跳包
                m_isHeartClose = false;
                break;
            case Protocol::MsgType::RPC_SERVICE_DISCOVER_RESPONSE: // 服务发现响应包
                handleServiceDiscover(response);
                break;
            case Protocol::MsgType::RPC_PUBLISH_REQUEST: // 发布服务上下线
                handlePublish(response);
                m_chan << Protocol::Create(Protocol::MsgType::RPC_PUBLISH_RESPONSE,""); // 响应
                break;
            case Protocol::MsgType::RPC_SUBSCRIBE_RESPONSE:
                break;
            default:
                ACID_LOG_DEBUG(g_logger) << "protocol:" << response->toString();
                break;
        }
    }
}

处理服务发现的响应报文:

报文内容是servicename和一些对应的地址。

通过服务名获取等待该结果的 Channel,对该 Channel 发送调用结果唤醒调用者。

/**
     * @brief 处理注册中心服务发现响应
     */
void RpcConnectionPool::handleServiceDiscover(Protocol::ptr response) {
    Serializer s(response->getContent());
    std::string service;
    s >> service;
    std::map<std::string, Channel<Protocol::ptr>>::iterator it;

    MutexType::Lock lock(m_discover_mutex);
    // 查找该序列号的 Channel 是否还存在,如果不存在直接返回
    it = m_discover_handle.find(service);
    if (it == m_discover_handle.end()) {
        return;
    }
    // 通过服务名获取等待该结果的 Channel
    Channel<Protocol::ptr> chan = it->second;
    // 对该 Channel 发送调用结果唤醒调用者
    chan << response;
}

处理发布服务上下线报文:

根据服务名找到对应的回调函数m_subHandle,并调用。

/**
     * @brief 处理发布消息
     */
void RpcConnectionPool::handlePublish(Protocol::ptr proto) {
    Serializer s(proto->getContent());
    std::string key;
    s >> key;
    MutexType::Lock lock(m_sub_mtx);
    auto it = m_subHandle.find(key);
    if (it == m_subHandle.end()) return;
    it->second(s);
}

subscribe订阅服务

和RpcClinet的subscribe一样。

	/**
     * @brief 订阅消息
     * @param[in] key 订阅的key
     * @param[in] func 回调函数
     */
    template<typename Func>
    void subscribe(const std::string& key, Func func) {
        {
            MutexType::Lock lock(m_sub_mtx);
            auto it = m_subHandle.find(key);
            if (it != m_subHandle.end()) {
                ACID_ASSERT2(false, "duplicated subscribe");
                return;
            }

            m_subHandle.emplace(key, std::move(func));
        }
        Serializer s;
        s << key;
        s.reset();
        Protocol::ptr request = Protocol::Create(Protocol::MsgType::RPC_SUBSCRIBE_REQUEST, s.toString(), 0);
        m_chan << request;
    }

discover 服务发现

/**
     * @brief 服务发现
     * @param name 服务名称
     * @return 服务地址列表
     */
std::vector<std::string> RpcConnectionPool::discover(const std::string& name) {
    if (!m_registry || !m_registry->isConnected()) {
        return {};
    }
    // 开启一个 Channel 接收调用结果
    Channel<Protocol::ptr> recvChan(1);

    std::map<std::string, Channel<Protocol::ptr>>::iterator it;
    {
        MutexType::Lock lock(m_discover_mutex);
        // 将请求序列号与接收 Channel 关联
        it = m_discover_handle.emplace(name, recvChan).first;
    }

    // 创建请求协议,附带上请求 id
    Protocol::ptr request = Protocol::Create(Protocol::MsgType::RPC_SERVICE_DISCOVER, name);

    // 向 send 协程的 Channel 发送消息
    m_chan << request;

    Protocol::ptr response = nullptr;
    // 等待 response,Channel内部会挂起协程,如果有消息到达或者被关闭则会被唤醒
    recvChan >> response;

    {
        MutexType::Lock lock(m_discover_mutex);
        m_discover_handle.erase(it);
    }

    if (!response) {
        return {};
    }

    std::vector<Result<std::string>> res;
    std::vector<std::string> rt; // 地址列表,用来return
    std::vector<Address::ptr> addrs;

    Serializer s(response->getContent());
    uint32_t cnt;	// 地址个数
    std::string str; // 服务名
    s >> str >> cnt;

    for (uint32_t i = 0; i < cnt; ++i) {
        Result<std::string> r;
        s >> r;
        res.push_back(r);
    }

    if (res.front().getCode() == RPC_NO_METHOD) { // RPC_NO_METHOD
        return {};
    }

    for (size_t i = 0; i < res.size(); ++i) { // 取出地址列表
        rt.push_back(res[i].getVal());
    }

    if (!m_subHandle.contains(RPC_SERVICE_SUBSCRIBE + name)) {
        // 向注册中心订阅服务变化的消息
        // 添加回调函数
        subscribe(RPC_SERVICE_SUBSCRIBE + name, [name, this](Serializer s){
            // false 为服务下线,true 为新服务节点上线
            bool isNewServer = false;
            std::string addr;
            s >> isNewServer >> addr;
            MutexType::Lock lock(m_connMutex);
            if (isNewServer) {
                // 一个新的服务提供者节点加入,将服务地址加入服务列表缓存
                LOG_DEBUG << "service [ " << name << " : " << addr << " ] join";
                m_serviceCache[name].push_back(addr);
            } else {
                // 已有服务提供者节点下线
                LOG_DEBUG << "service [ " << name << " : " << addr << " ] quit";
                // 清理缓存中断开的连接地址
                auto its = m_serviceCache.find(name);
                if (its != m_serviceCache.end()) {
                    std::erase(its->second, addr);
                }
            }
        });
    }

    return rt;
}

call调用

这个是其他call都调用的函数,下面主要看这个:

  • 从连接池取出服务名对应的RpcClient,如果还没失效,则调用RpcClient的call,并直接返回结果。
  • 如果对应的RpcClient已经失效
    • 如果服务地址缓存为空,则重新进行服务发现discover,否则直接进行下一步
    • 根据负载均衡路由规则挑选一个地址,建立连接(RpcClient),则调用RpcClient的call,并返回结果。
	/**
     * @brief 远程过程调用
     * @param[in] name 函数名
     * @param[in] ps 可变参
     * @return 返回调用结果
     */
    template<typename R, typename... Params>
    Result<R> call(const std::string& name, Params... ps) {
        MutexType::Lock lock(m_connMutex);
        // 从连接池里取出服务连接
        auto conn = m_conns.find(name);
        Result<R> result;
        if (conn != m_conns.end()) {
            lock.unlock();
            // 调用RpcClinet的call
            result = conn->second->template call<R>(name, ps...);
            if (result.getCode() != RPC_CLOSED) {
                return result;
            }
            lock.lock();
            // 移除失效连接
            std::vector<std::string>& addrs = m_serviceCache[name];
            std::erase(addrs, conn->second->getSocket()->getRemoteAddress()->toString());

            m_conns.erase(name);
        }

        std::vector<std::string>& addrs = m_serviceCache[name];
        // 如果服务地址缓存为空则重新向服务中心
        if (addrs.empty()) {
            if (!m_registry || !m_registry->isConnected()) {
                Result<R> res;
                res.setCode(RPC_CLOSED);
                res.setMsg("registry closed");
                return res;
            }
            // 请求服务发现
            addrs = discover(name);
            // 如果没有发现服务返回错误
            if (addrs.empty()) {
                Result<R> res;
                res.setCode(RPC_NO_METHOD);
                res.setMsg("no method:" + name);
                return res;
            }
        }

        // 选择客户端负载均衡策略,根据路由策略选择服务地址
        RouteStrategy<std::string>::ptr strategy =
                RouteEngine<std::string>::queryStrategy(Strategy::Random);

        if (addrs.size()) {
            const std::string ip = strategy->select(addrs);
            Address::ptr address = Address::LookupAny(ip);
            // 选择的服务地址有效
            if (address) {
                RpcClient::ptr client = std::make_shared<RpcClient>();
                // 成功连接上服务器
                if (client->connect(address)) {
                    m_conns.template emplace(name, client);
                    lock.unlock();
                    return client->template call<R>(name, ps...);
                }
            }
        }
        result.setCode(RPC_FAIL);
        result.setMsg("call fail");
        return result;
    }
	/**
     * @brief 异步远程过程调用回调模式
     * @param[in] callback 回调函数
     * @param[in] name 函数名
     * @param[in] ps 可变参
     */
    template<typename... Params>
    void callback(const std::string& name, Params&&... ps) {
        static_assert(sizeof...(ps), "without a callback function");
        auto tp = std::make_tuple(ps...);
        constexpr auto size = std::tuple_size<typename std::decay<decltype(tp)>::type>::value;
        auto cb = std::get<size-1>(tp);
        static_assert(function_traits<decltype(cb)>{}.arity == 1, "callback type not support");
        using res = typename function_traits<decltype(cb)>::args<0>::type;
        using rt = typename res::row_type;
        static_assert(std::is_invocable_v<decltype(cb), Result<rt>>, "callback type not support");
        RpcConnectionPool::ptr self = shared_from_this();
        go [cb = std::move(cb), name = std::move(name), tp = std::move(tp), size, self, this] {
            auto proxy = [&cb, &name, &tp, &size, &self, this]<std::size_t... Index>(std::index_sequence<Index...>){
                cb(call<rt>(name, std::get<Index>(tp)...));
            };
            proxy(std::make_index_sequence<size - 1>{});
        };
    }
    /**
     * @brief 异步远程过程调用
     * @param[in] name 函数名
     * @param[in] ps 可变参
     * @return 返回 Channel
     */
    template<typename R,typename... Params>
    Channel<Result<R>> async_call(const std::string& name, Params&& ... ps) {
        Channel<Result<R>> chan(1);
        RpcConnectionPool::ptr self = shared_from_this();
        go [chan, name, ps..., self, this] () mutable {
            chan << call<R>(name, ps...);
            self = nullptr;
        };
        return chan;
    }
	/**
     * @brief 异步远程过程调用
     * @param[in] name 函数名
     * @param[in] ps 可变参
     * @return 返回 Channel
     */
    template<typename R,typename... Params>
    Channel<Result<R>> async_call(const std::string& name, Params&& ... ps) {
        Channel<Result<R>> chan(1);
        RpcConnectionPool::ptr self = shared_from_this();
        go [chan, name, ps..., self, this] () mutable {
            chan << call<R>(name, ps...);
            self = nullptr;
        };
        return chan;
    }

rpc_server

RpcServer继承自TcpServer。

成员变量

private:
    // 保存注册的函数
    std::map<std::string, std::function<void(Serializer, const std::string&)>> m_handlers;
    // 服务中心连接
    RpcSession::ptr m_registry;
    // 服务中心心跳定时器
    Timer::ptr m_heartTimer;
    // 开放服务端口
    uint32_t m_port;
    // 和客户端的心跳时间 默认 40s
    uint64_t m_AliveTime;
    // 订阅的客户端
    std::unordered_multimap<std::string, std::weak_ptr<RpcSession>> m_subscribes;
    // 保护 m_subscribes
    MutexType m_sub_mtx;
    // 停止清理订阅协程
    bool m_stop_clean = false;
    // 等待清理协程停止
    Channel<bool> m_clean_chan{1};

bindRegistry

建立到registry的连接,记录到m_registry,向服务中心声明为provider,注册服务端口。

bool RpcServer::bindRegistry(Address::ptr address) {
    Socket::ptr sock = Socket::CreateTCP(address);

    if (!sock) {
        return false;
    }
    if (!sock->connect(address)) {
        ACID_LOG_WARN(g_logger) << "can't connect to registry";
        m_registry = nullptr;
        return false;
    }
    m_registry = std::make_shared<RpcSession>(sock);

    Serializer s;
    s << m_port;
    s.reset();

    // 向服务中心声明为provider,注册服务端口
    Protocol::ptr proto = Protocol::Create(Protocol::MsgType::RPC_PROVIDER, s.toString());
    m_registry->sendProtocol(proto);
    return true;
}

start

向服务中心注册服务。

开启与registry的心跳定时器。

开启协程定时清理订阅列表。

TcpServer::start()。

bool RpcServer::start() {
    if (m_registry) {
        for(auto& item: m_handlers) { // 向服务中心注册服务
            registerService(item.first);
        }
        auto server = std::dynamic_pointer_cast<RpcServer>(shared_from_this());
        // 服务中心心跳定时器 30s
        m_registry->getSocket()->setRecvTimeout(30'000);
        m_heartTimer = m_worker->addTimer(30'000, [server]{
            ACID_LOG_DEBUG(g_logger) << "heart beat";
            Protocol::ptr proto = Protocol::Create(Protocol::MsgType::HEARTBEAT_PACKET, "");
            server->m_registry->sendProtocol(proto);
            Protocol::ptr response = server->m_registry->recvProtocol();
	
            if (!response) {
                ACID_LOG_WARN(g_logger) << "Registry close";
                
                //放弃服务中心,独自提供服务
                server->m_heartTimer->cancel();
            }
        }, true);
    }

    // 开启协程定时清理订阅列表
	.........

    return TcpServer::start();
}

/**
     * @brief 向服务注册中心发起注册
     * @param[in] name 注册的函数名
     */
void RpcServer::registerService(const std::string &name) {
    Protocol::ptr proto = Protocol::Create(Protocol::MsgType::RPC_SERVICE_REGISTER, name);
    m_registry->sendProtocol(proto);

    Protocol::ptr rp = m_registry->recvProtocol();
    if (!rp) {
        ACID_LOG_WARN(g_logger) << "registerService:" << name << " fail, registry socket:" << m_registry->getSocket()->toString();
        return;
    }

    Result<std::string> result;
    Serializer s(rp->getContent());
    s >> result;

    if (result.getCode() != RPC_SUCCESS) {
        ACID_LOG_WARN(g_logger) << result.toString();
    }
    ACID_LOG_INFO(g_logger) << result.toString();
}

update更新定时器

void RpcServer::update(Timer::ptr& heartTimer, Socket::ptr client) {
    // ACID_LOG_DEBUG(g_logger) << "update heart";
    if (!heartTimer) {
        heartTimer = m_worker->addTimer(m_AliveTime, [client]{
            ACID_LOG_DEBUG(g_logger) << "client:" << client->toString() << " closed";
            client->close();
        });
        return;
    }
    // 更新定时器
    heartTimer->reset(m_AliveTime, true);
}

handleClient

void RpcServer::handleClient(Socket::ptr client) {
    ACID_LOG_DEBUG(g_logger) << "handleClient: " << client->toString();
    RpcSession::ptr session = std::make_shared<RpcSession>(client);

    Timer::ptr heartTimer;
    // 开启心跳定时器
    update(heartTimer, client);
    while (true) {
        Protocol::ptr request = session->recvProtocol();
        if (!request) {
            break;
        }
        // 更新定时器
        update(heartTimer, client);

        auto self = shared_from_this();
        // 启动一个任务协程
        go [request, session, self, this]() mutable {
            Protocol::ptr response;
            Protocol::MsgType type = request->getMsgType();
            switch (type) {
                case Protocol::MsgType::HEARTBEAT_PACKET:		// 心跳
                    response = handleHeartbeatPacket(request);
                    break;
                case Protocol::MsgType::RPC_METHOD_REQUEST:		// 调用请求
                    response = handleMethodCall(request);
                    break;
                case Protocol::MsgType::RPC_SUBSCRIBE_REQUEST: 	// 订阅请求
                    response = handleSubscribe(request, session);
                    break;
                case Protocol::MsgType::RPC_PUBLISH_RESPONSE:	// 响应发布
                    return;
                default:
                    ACID_LOG_DEBUG(g_logger) << "protocol:" << request->toString();
                    break;
            }

            if (response) {
                session->sendProtocol(response);
            }
            self = nullptr;
        };
    }

}
  • handleHeartbeatPacket:返回一个心跳包。
Protocol::ptr RpcServer::handleHeartbeatPacket(Protocol::ptr p) {
    return Protocol::HeartBeat();
}
  • handleMethodCall:调用服务端注册的函数,返回一个RPC_METHOD_RESPONSE报文。
Protocol::ptr RpcServer::handleMethodCall(Protocol::ptr p) {
    std::string func_name;
    Serializer request(p->getContent());
    request >> func_name;
    Serializer rt = call(func_name, request.toString());
    Protocol::ptr response = Protocol::Create(
            Protocol::MsgType::RPC_METHOD_RESPONSE, rt.toString(), p->getSequenceId());
    return response;
}

/**
* @brief 调用服务端注册的函数,返回序列化完的结果
* @param[in] name 函数名
* @param[in] arg 函数参数字节流
* @return 函数调用的序列化结果
*/
Serializer RpcServer::call(const std::string &name, const std::string& arg) {
    Serializer serializer;
    if (m_handlers.find(name) == m_handlers.end()) {
        return serializer;
    }
    auto fun = m_handlers[name];
    fun(serializer, arg);
    serializer.reset();
    return serializer;
}
  • handleSubscribe:将其加入到订阅者列表,并返回一个RPC_SUBSCRIBE_RESPONSE报文。
Protocol::ptr RpcServer::handleSubscribe(Protocol::ptr proto, RpcSession::ptr client) {
    MutexType::Lock lock(m_sub_mtx);
    std::string key;
    Serializer s(proto->getContent());
    s >> key;
    m_subscribes.emplace(key, std::weak_ptr<RpcSession>(client));
    Result<> res = Result<>::Success();
    s.reset();
    s << res;
    return Protocol::Create(Protocol::MsgType::RPC_SUBSCRIBE_RESPONSE, s.toString(), 0);
}

publish

对所有订阅了key的订阅者都发送一个RPC_PUBLISH_REQUEST报文。

	/**
     * @brief 发布消息
     * @param[in] key 发布的key
     * @param[in] data 支持 Serializer 的都可以发布
     */
    template <typename T>
    void publish(const std::string& key, T data) {
        {
            MutexType::Lock lock(m_sub_mtx);
            if (m_subscribes.empty()) {
                return;
            }
        }
        Serializer s;
        s << key << data;
        s.reset();
        Protocol::ptr pub = Protocol::Create(Protocol::MsgType::RPC_PUBLISH_REQUEST, s.toString(), 0);
        MutexType::Lock lock(m_sub_mtx);
        auto range = m_subscribes.equal_range(key);
        for (auto it = range.first; it != range.second; ++it) {
            auto conn = it->second.lock();
            if (conn == nullptr || !conn->isConnected()) {
                continue;
            }
            conn->sendProtocol(pub);
        }
    }

registerMethod

	/**
     * @brief 注册函数
     * @param[in] name 注册的函数名
     * @param[in] func 注册的函数
     */
    template<typename Func>
    void registerMethod(const std::string& name, Func func) {
        m_handlers[name] = [func, this](Serializer serializer, const std::string& arg) {
            proxy(func, serializer, arg);
        };
    }

proxy:?????

	/**
     * @brief 调用代理
     * @param[in] fun 函数
     * @param[in] serializer 返回调用结果
     * @param[in] arg 函数参数字节流
     */
    template<typename F>
    void proxy(F fun, Serializer serializer, const std::string& arg) {
        typename function_traits<F>::stl_function_type func(fun);
        using Return = typename function_traits<F>::return_type;
        using Args = typename function_traits<F>::tuple_type;

        acid::rpc::Serializer s(arg);
        // 反序列化字节流,存为参数tuple
        Args args;
        try {
            s >> args;
        } catch (...) {
            Result<Return> val;
            val.setCode(acid::rpc::RPC_NO_MATCH);
            val.setMsg("params not match");
            serializer << val;
            return;
        }

        return_type_t<Return> rt{};

        constexpr auto size = std::tuple_size<typename std::decay<Args>::type>::value;
        auto invoke = [&func, &args]<std::size_t... Index>(std::index_sequence<Index...>){
            return func(std::get<Index>(std::forward<Args>(args))...);
        };

        if constexpr(std::is_same_v<Return, void>) {
            invoke(std::make_index_sequence<size>{});
        } else {
            rt = invoke(std::make_index_sequence<size>{});
        }

        Result<Return> val;
        val.setCode(acid::rpc::RPC_SUCCESS);
        val.setVal(rt);
        serializer << val;
    }
posted @ 2023-11-21 15:05  DavidJIAN  阅读(25)  评论(0)    收藏  举报