为什么需要发送缓冲区和接收缓冲区
网络层在发送数据的过程中,由于TCP窗口太小,会导致数据无法发送出去,而上层可能源源不断地产生新的数据,此时就需要将数据先存储起来,以便等到socket可写时再次发送,这个存储数据的地方就叫做发送缓冲区。
对于接收缓冲区也是一样的道理,在收到数据后,我们可以直接对其进行解包,但是这样做不好,有三个理由
理由一:除去一些通用的协议格式,大多数业务都是采用的自定义协议格式,也就是说对一个数据包里面的数据格式的解读应该是业务层应该做的。不同的业务一般有不同的协议格式,协议格式与具体的业务有关,网络通信层一般不知道也不需要知道上层协议数据的具体格式。为了让网络层更加通用,网络通信层应该与业务层解耦。
理由二:即使知道协议格式,由于TCP是流式协议,某一次收到的数据长度也不一定够一个完整的包大小,此时需要一个地方将这些不完整的数据先缓存起来,以便等到数据够一个包大小时再处理
理由三:即便接收到的数据够一个包,但由于一些特殊的业务逻辑要求,我们仍需将收到的数据暂时缓存起来,等满足一定条件时再取出来处理。
鉴于以上的理由,我们在网络层确实需要一个接收缓冲区,将收取到的数据按需存放在该缓冲区里面,交给专门的业务线程或者业务逻辑从接收缓冲区中取出数据,并解包处理业务。
如何设计发送缓冲区和接收缓冲区
一般情况下,我们都会将缓冲区设计为一个内存连续的存储容器
在通常情况下,发送缓冲区和接收缓冲区根据功能至少需要提供两类接口,即存数据的接口和取数据的接口,对于发送缓冲区,由于上层交给网络层的数据时有序的,所以若某次需要发送的数据未发送完,则其剩余的数据一定排在后续产生的数据前面;对于接收缓冲区,由于其不断从socket上读取数据,所以后面读取到的数据一定在前面读取到的数据的后面。另外,应该将发送缓冲区和接收缓冲区的容量设置为多大呢?预分配的内存太小可能不够用,太大可能造成浪费,所以我们可以借助于stl中的vector或者string来实现我们缓冲区。实现按需分配,容量不够时可以扩展容量。
编码实现
buffer.h
#ifndef BUFFER_H
#defi