网络库缓冲区实践思路
@(网络编程实现)
下面给出的是借鉴于muduo::Buffer
的非阻塞I/O,TCP套接字的缓冲区设置。
- 关键字:
非阻塞网络、TCP、多连接、简单
为什么需要缓冲区
- 为什么需要输出缓冲区
受限于TCP协议,应用程序要发送的数据可能无法一次发送完成。在这种情况下,应用程序不可能阻塞在发送端口上。这就需要缓冲区暂时保存还未发送的数据,待套接字可写时再又网络库发送。
- 为什么需要输入缓冲区
应用程序只关心消息到达,而不关心数据到达;TCP协议是无消息边界的字节流协议。当有数据到达时,可能到达是不完整的消息,这个时候就需要缓冲区暂时保存数据,待数据完整后再递送数据。
缓冲区的大小设置思路:藉由readv
实现
如前面的需求所言,缓冲区的空间要足够大,减少反复read
的系统调用开销。但也不能太大,不然在多线程情况下会导致巨大的、不必要的(因为实际上缓冲区的使用率会很低)内存开销。muduo中给出了借用栈上空间来实现一次读入足够的数据,而众多连接不至于占用过大内存的解决措施:
在栈上准备一块空间extraBuf
,之后使用readv
来读取数据:iovec
有两块,第一块指向Buffer自身的writeable
,第二块指向extraBuf
。如果数据过大,在填满了writeable
之后,会填到extraBuf
中,之后再将extraBuf
中的数据加到扩大了的缓冲区中。
内部数据结构实现思路:vector<char>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U7ip9Hcw-1632918381331)(./无标题.png)]
- 读取:
当从Buffer中读取数据时,
readIndex
后移。当readIndex
和writeIndex
相等时,则二者置为 h e a d L e n g t h headLength headLength。
- 写入:
当向Buffer中写入数据时,
writeIndex
后移,如果剩余空间不够,则利用vector
自身的空间扩大机制重新申请更大的空间。所以writeIndex
和readIndex
得是下标而非指针。
- 头部预留:
头部最好预留一定的空间( h e a d L e n g t h headLength headLength),用于存储一些比如消息长度之类的信息。