>上下文
我正在用C++编写一个事件驱动的应用程序服务器。我想使用谷歌协议缓冲区来移动我的数据。由于服务器是事件驱动的,因此连接处理程序 API 基本上是一个回调函数,让我知道另一个 N 字节的缓冲区何时从客户端到达。
问题
作为 protobuf 的完全初学者,我的问题是:是否有可能以某种方式哄骗 protobuf 接受组成一条完整消息所需的许多缓冲区,以促进"流解析器",而不是等待整个数据首先到达临时缓冲区?
换句话说,我想要这个:
//Event API. May be called multiple times for each protobuf message
bool data_arrived_from_client(void *buf,size_t len){
my_protobuf.parse_part(buf,len); // THIS IS THE GROSSLY SIMPLIFIED SEMANTIC OF WHAT I WANT
message_size+=len;
if(message_size>COMPLETE_BUFFER_SIZE){
use_complete_protobuf();
return true;
}
return false;
}
..取而代之的是:
//Event API. May be called multiple times for each protobuf message
bool data_arrived_from_client(void *buf,size_t len){
my_temp_buffer.append_data(buf,len);
message_size+=len;
if(message_size>COMPLETE_BUFFER_SIZE){
my_protobuf.ParseFromArray(my_temp_buffer.data_ptr(),my_temp_buffer.size());
use_complete_protobuf();
return true;
}
return false;
}
答
特别感谢完整代码的答案!
不,这是不可能的。
Protobuf 解析器是一个递归下降解析器,这意味着它的相当一部分状态存储在堆栈上。 这使得它很快,但这意味着除了暂停整个线程之外,没有办法在中间暂停解析器。 如果您的应用程序是非阻塞的,则只需缓冲字节,直到要解析整个消息。
也就是说,这并不像听起来那么糟糕。 请记住,消息的最终解析表示形式(即内存中的消息对象)比线路表示形式大得多。 因此,与以后要处理它的内容相比,您几乎不会在缓冲上浪费内存。 事实上,在实际拥有所有数据之前推迟解析实际上可能会节省内存,因为您不会保留一个大的半解析对象,它只是坐在那里等待数据到达。
是的,这是可能的,我已经在Javascript中完成了,但是设计可以移植到C++。
https://github.com/chrisdew/protostream