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服务器
- 创建tcp socket,并连接到rpc server;
- 将这个连接初始化为RpcSession,记录到m_session;
- 开启两个协程:recv 协程、send 协程。recv:接收来自RpcServer发来的(响应)报文,根据报文类型作出相应的处理。send:通过 Channel 收集调用请求,如果没有消息时 Channel 内部会挂起该协程等待消息到达,然后将请求发送到RpcServer;
- 创建心跳定时器。如果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函数
- close send协程的channel;
- 取消心跳定时器;
- 关闭每个调用者的channel;
- 关闭连接到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;
}

浙公网安备 33010602011771号