赞
踩
首先用作者给出的图说明:可以看到有两个下标rederIndex 和 writerIndex 来控制buffer的读取和写入。
- +-------------------+------------------+------------------+
- | prependable bytes | readable bytes | writable bytes |
- | | (CONTENT) | |
- +-------------------+------------------+------------------+
- | | | |
- 0 <= readerIndex <= writerIndex <= size
整个buffer内部数据是用 vector存储的, 并且根据网络消息的常用格式,在前面预留了8个字节的空间,方便插入消息长度字段,整个空间初始化为8 + 1024。
protobuf 全称是 google protocal buffer, 是一种将结构化数据序列化和反序列化的方法,是google的一个开源库,目前提供了C++, Java, 和Python三种语言的API。
protobuf的简单用法如下:
需要重点介绍的是protobuf实现了反射机制,即它可以在程序运行的时候根据获得的消息类名信息,动态生成消息对象,该机制使用原型模式实现。
就目前来讲, 渐进的学习了三种设计策略, 用来方便客户端和服务器的通信。现在予以总结。
这是最基本的策略,即在服务器和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)
使用Buffer会带来一个问题,对于长连接,每次从缓冲区读出的数据如何分开,就会发生粘包问题。这就需要设计一种打包和分包策略,可以保证我们每次将数据打包发送出去后,对端可以原样分包出来。这里的方法有很多,比如可以自己定义一个消息的边界(\r\n),或者给消息增加一个长度的头部等等。muduo作者(@chenshuo)采用了在包头增加长度信息的打包分包策略。这样在Server要发送消息给Client 时,就会由codec(编解码器)自动给消息加上一个长度信息然后再写到buffer中去,反之,从buffer中读取的消息,会先读出头部长度信息,然后读取内容字段发送给上层。
这时的结构是这样的。由Codec负责对消息进一步处理,之后再发送给Buffer。
TCP_Connection <=========> Buffer <=========> Codec <=========> Server(Client)
需求是程序改进的唯一动力。针对上面的架构,发送非结构化数据,比如说一个字符串,是完全可以胜任的,但是,如果我要发送一个结构化的信息呢,如:
- 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)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。