Muduo Buffer和Google protobuf

Muduo Buffer 实现思路

  • 首先用作者给出的图说明:可以看到有两个下标rederIndex 和 writerIndex 来控制buffer的读取和写入。

        +-------------------+------------------+------------------+
        | prependable bytes |  readable bytes  |  writable bytes  |
        |                   |     (CONTENT)    |                  |
        +-------------------+------------------+------------------+
        |                   |                  |                  |
        0      <=      readerIndex   <=   writerIndex    <=     size
    
  • 整个buffer内部数据是用 vector存储的, 并且根据网络消息的常用格式,在前面预留了8个字节的空间,方便插入消息长度字段,整个空间初始化为8 + 1024。

  • 当从套接字中读取数据量较大,writerIndex到达size大小时,需要考虑两种情况,readerIndex前面有足够多的空间可以写入,这时只需要把已有数据前移,为后面腾出空间即可;如果当前buffer不够,那么就需要调用vector的resize了。

使用protobuf对消息进行序列化

1. protobuf的简介

protobuf 全称是 google protocal buffer, 是一种将结构化数据序列化和反序列化的方法,是google的一个开源库,目前提供了C++, Java, 和Python三种语言的API。

protobuf的简单用法如下:

  • 编写proto文件,给定消息格式,如muduo.query.proto;
  • 使用protoc --cpp_out 编译生成对应C++版本的头文件和.cc文件;
  • 在程序中使用消息,这里注意链接时要加上-lprotobuf.

需要重点介绍的是protobuf实现了反射机制,即它可以在程序运行的时候根据获得的消息类名信息,动态生成消息对象,该机制使用原型模式实现。

2. 程序的整体架构设计

就目前来讲, 渐进的学习了三种设计策略, 用来方便客户端和服务器的通信。现在予以总结。

2.1 使用buffer

这是最基本的策略,即在服务器和TCP连接之间加一个缓冲区Buffer, 如下所示, 当连接中有数据可读时,先读到Buffer中,Server(Client)不直接操纵TCP Connection, 而是直接从对应的Buffer中读取数据;另一方面,当Server(Client)要写数据到对端时,先写到Buffer中,Buffer负责将数据发送出去。

使用Buffer是实现非阻塞IO的必须选择,因为Posix的API如read, write等都是阻塞的,如果Server直接操纵它们,那么整个非阻塞IO的目的将无法实现。所以,增加了缓冲区机制,可以保证Server(Client)在读取或写入时直接对缓冲区操作,而不用去管当前socket是否可读或者可写。

    TCP_Connection <=========> Buffer  <=========>Server(Client)                                 

2.2 使用buffer + codec

使用Buffer会带来一个问题,对于长连接,每次从缓冲区读出的数据如何分开,就会发生粘包问题。这就需要设计一种打包和分包策略,可以保证我们每次将数据打包发送出去后,对端可以原样分包出来。这里的方法有很多,比如可以自己定义一个消息的边界(\r\n),或者给消息增加一个长度的头部等等。muduo作者(@chenshuo)采用了在包头增加长度信息的打包分包策略。这样在Server要发送消息给Client 时,就会由codec(编解码器)自动给消息加上一个长度信息然后再写到buffer中去,反之,从buffer中读取的消息,会先读出头部长度信息,然后读取内容字段发送给上层。

这时的结构是这样的。由Codec负责对消息进一步处理,之后再发送给Buffer。

TCP_Connection <=========> Buffer  <=========> Codec <=========> Server(Client)

2.3 使用buffer + protobuf codec

需求是程序改进的唯一动力。针对上面的架构,发送非结构化数据,比如说一个字符串,是完全可以胜任的,但是,如果我要发送一个结构化的信息呢,如:

srtuct student{
    string name,
    int No,
    string sex
};

这时消息该如何打包呢。前面已经介绍过了,google 给我们提供了protobuf,它在网络通讯中比较常用,主要用来将结构化消息序列化,只需要将消息的结构定义好,即可使用, 并且可以同时定义不同类型的消息。这样我们就可以使用开源的API来将消息进行序列化,然后再写到Buffer中,这样,我们现在的架构就是这样子的,处理结构化消息的任务由Protobuf_Codec完成,然后再交给Buffer处理。这里的 Protobuf_Dispatcher主要用来分发不同类型的消息,因为不同的消息定制了不同的处理方法。

TCP_Connection <===> Buffer  <===> Protobuf_Codec <===> Protobuf_Dispatcher <===> Server(Client)

你可能感兴趣的:(Muduo Buffer和Google protobuf)