预计阅读时间: 6分钟
问题:
假如 device 和base是继承关系
base * ptr1 =new device();
device* ptr2 = new base(*ptr1)
请问ptr1 和ptr2是同样2个对象吗? 肯定不是呀
办法:
原型在哪里呀?
代码:这里是使用谷歌序列化框架为例子
tCP是一种流协议(stream protocol)。【补充一个概念
】
这就意味着数据是以字节流的形式传递给接收者的,没有固有的”报文”或”报文边界”的概念。
https://www.toutiao.com/i6932340828622963208/
tcp为什么需要分包:消息(多个)--字节流--消息(完整)
代码语言:javascript复制//字节流拆分边界
void ProtobufCodec::onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
while (buf->readableBytes() >= kMinMessageLen kHeaderLen)
{
const int32_t len = buf->peekInt32();
if (len > kMaxMessageLen || len < kMinMessageLen)
{
errorCallback_(conn, buf, receiveTime, kInvalidLength);
break;
} //不是完整数据
else if (buf->readableBytes() >= implicit_cast<size_t>(len kHeaderLen))
{
ErrorCode errorCode = kNoError;
//pb不负责数据的边界处理。
MessagePtr message = parse(buf->peek() kHeaderLen, len, &errorCode);
if (errorCode == kNoError && message)
{
messageCallback_(conn, message, receiveTime);
buf->retrieve(kHeaderLen len);
}
else
{
errorCallback_(conn, buf, receiveTime, errorCode);
break;
}
}
else
{
break;
}
}
}
//通过工厂映射创建一个类
google::protobuf::Message* ProtobufCodec::createMessage(const std::string& typeName)
{
google::protobuf::Message* message = NULL;
const google::protobuf::Descriptor* descriptor =
google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(typeName);
if (descriptor)
{
const google::protobuf::Message* prototype =
google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
if (prototype)
{
message = prototype->New();
}
}
return message;
}
//把字节流变成一个类
MessagePtr ProtobufCodec::parse(const char* buf, int len, ErrorCode* error)
{
MessagePtr message;
// check sum
int32_t expectedCheckSum = asInt32(buf len - kHeaderLen);
int32_t checkSum = static_cast<int32_t>(
::adler32(1,
reinterpret_cast<const Bytef*>(buf),
static_cast<int>(len - kHeaderLen)));
if (checkSum == expectedCheckSum)
{
// get message type name
int32_t nameLen = asInt32(buf);
if (nameLen >= 2 && nameLen <= len - 2*kHeaderLen)
{
std::string typeName(buf kHeaderLen, buf kHeaderLen nameLen - 1);
// create message object
message.reset(createMessage(typeName));
if (message)
{
// parse from buffer
const char* data = buf kHeaderLen nameLen;
int32_t dataLen = len - nameLen - 2*kHeaderLen;
if (message->ParseFromArray(data, dataLen))
{
*error = kNoError;
}
else
{
*error = kParseError;
}
}
else
{
*error = kUnknownMessageType;
}
}
else
{
*error = kInvalidNameLen;
}
}
else
{
*error = kCheckSumError;
}
return message;
}
补充概念:
- pb 不负责 tcp 读取和写入 包括 切分数据这个动作。
- pb 客户端和服务共享pro文件。通过名字映射具体的类。
这个是谷歌pb代码:
//static
GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
static auto instance =
internal::OnShutdownDelete(new GeneratedMessageFactory);
return instance;
}
class GeneratedMessageFactory final : public MessageFactory {
public:
static GeneratedMessageFactory* singleton();
void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
void RegisterType(const Descriptor* descriptor, const Message* prototype);
// implements MessageFactory ---------------------------------------
const Message* GetPrototype(const Descriptor* type) override;
private:
// Initialized lazily, so requires locking.
std::unordered_map<const Descriptor*, const Message*> type_map_;
//问题:谁注册的,在哪里注册。
//这样避免if else 判断,新增类型就注册
};
void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
const Message* prototype) {
// This should only be called as a result of calling a file registration
// function during GetPrototype(), in which case we already have locked
// the mutex.
mutex_.AssertHeld();
if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
}
}
void MessageFactory::InternalRegisterGeneratedMessage(
const Descriptor* descriptor, const Message* prototype) {
GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
}哈哈哈
找到了
// For internal use only: Registers a message type. Called only by the
// functions which are registered with InternalRegisterGeneratedFile(),
// above.
static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
从静态方法到静态类,这说明了什么,在编译期间就可以执行。
不需要依赖具体对象。
// For internal use only: Registers a .proto file at static initialization
// time, to be placed in generated_factory. The first time GetPrototype()
// is called with a descriptor from this file, |register_messages| will be
// called, with the file name as the parameter. It must call
// InternalRegisterGeneratedMessage() (below) to register each message type
// in the file. This strange mechanism is necessary because descriptors are
// built lazily, so we can't register types by their descriptor until we
// know that the descriptor exists. |filename| must be a permanent string.
static void InternalRegisterGeneratedFile(
const google::protobuf::internal::DescriptorTable* table);
最重要一个注释:在静态对象初始化的时候,注册类型(编译期间,不需要手工注册)
代码语言:javascript复制 // For internal use only: Registers a .proto file at static initialization
// time, to be placed in generated_factor