Unix/Linux上的五种IO模型(UNP6.2)

IO多路复用一般不能和blocking IO用在一起,因为blocking IO中read() write() accept() connect()都有可能阻塞当前线程,这样线程就没办法处理其他socket上的IO事件了

non-blocking IO的核心思想是避免阻塞在read()或write()或其他IO系统调用上,让一个线程能服务于多个socket连接,IO线程只能阻塞在IO多路复用函数上,如select、poll、epoll_wait,这样一来,应用层的缓冲是必须的.

1.TcpConnection必须要有output buffer:write系统调用可能一次不能发送完程序需要发送的数据,此时剩余的数据保存在output buffer中。要让程序在write操作上不阻塞,网络库必须要给每个TCP connection配置output buffer.

2.TcpConnection必须要有input buffer:收到的数据可能不构成一条完整的消息或者一次收到两条消息的数据,收到的数据先放到input buffer里,等构成一条完整的消息再通知程序的业务逻辑(TCP分包)

综上,muduo中的IO都是带缓冲的IO,不会自己去read()或write()某个socket,只会操作TcpConnection的input buffer和output buffer.

Muduo Buffer设计要点:

  • 对外表现为一块连续的内存(char*, len),以方便客户代码的编写。
  • 其 size() 可以自动增长,以适应不同大小的消息。它不是一个 fixed size array (即 char buf[8192]),通过vector自动实现
  • 利用临时栈上空间,如果读入的数据不多,那么全部都读到 Buffer 中去了;如果长度超过 Buffer 的 writable 字节数,就会读到栈上的 stackbuf 里,然后程序再把 stackbuf 里的数据 append 到 Buffer 中。

Buffer的数据结构:

prependable空间,让程序能以很低的代价在数据前面添加几个字节.比方说,程序以固定的4个字节表示消息的长度,我要序列化一个消息,但是不知道它有多长,那么我可以一直 append() 直到序列化完成,然后再在序列化数据的前面添加消息的长度

Buffer的操作:

基本的read-write cycle:

iovec,与readv和wirtev操作相关的结构体,readv和writev函数用于在一次函数调用中读、写多个非连续缓冲区.

struct iovec{
void *iov_base; /* Pointer to data. */
size_t iov_len; /* Length of data. */
};
//写数据到缓冲区,writeIndex后移,从缓冲区中读数据,readIndex后移
ssize_t Buffer::readFd(int fd, int* savedErrno)
{
// saved an ioctl()/FIONREAD call to tell how much to read
char extrabuf[];
struct iovec vec[];
const size_t writable = writableBytes();
vec[].iov_base = begin()+writerIndex_;
vec[].iov_len = writable;
vec[].iov_base = extrabuf;
vec[].iov_len = sizeof extrabuf;
// when there is enough space in this buffer, don't read into extrabuf.
// when extrabuf is used, we read 128k-1 bytes at most.
const int iovcnt = (writable < sizeof extrabuf) ? : ;
const ssize_t n = sockets::readv(fd, vec, iovcnt);
if (n < )
{
*savedErrno = errno;
}
else if (implicit_cast<size_t>(n) <= writable)
{
writerIndex_ += n;
}
else
{
writerIndex_ = buffer_.size();
//将栈中的数据添加到buffer,如果buffer空间不够,需要扩容
append(extrabuf, n - writable);
}
// if (n == writable + sizeof extrabuf)
// {
// goto line_30;
// }
return n;
}

readv()将文件中连续的数据块读入内存分散的缓冲区中。writev()收集内存中分散的若干缓冲区中的数据写至文件的连续区域中。
#include <sys/uio.h>
ssize_t readv(int fildes, const struct iovec *iov, int iovcnt);
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt);

参数iovcnt指出数组iov的元素个数,元素个数至多不超过IOV_MAX,Linux中定义IOV_MAX的值为1024。

muduo buffer类的设计与使用的更多相关文章

  1. Buffer类的详解(转)

    Buffer 类是 java.nio 的构造基础.一个 Buffer 对象是固定数量的数据的容器,其作用是一个存储器,或者分段运输区,在这里,数据可被存储并在之后用于检索.缓冲区可以被写满或释放.对于 ...

  2. Unity3D 游戏开发构架篇 ——角色类的设计与持久化

    在游戏开发中,游戏角色占了很大的篇幅,可以说游戏中所有的内容都是由主角所带动.这里就介绍一下角色类的设计和持久化. 一.角色类应用场景和设计思想 游戏中的角色类型不一而足,有不同的技能,有不同的属性等 ...

  3. Node.js权威指南 (5) - 使用Buffer类处理二进制数据

    5.1 创建Buffer对象 / 705.2 字符串的长度与缓存区的长度 / 725.3 Buffer对象与字符串对象之间的相互转换 / 74 5.3.1 Buffer对象的toString方法 / ...

  4. Node.js系列:Buffer类的使用

    客户端JavaScript中没有对二进制数据提供很好的支持.但是在处理TCP流或文件流时,必须要处理二进制数据.Node.js定义了一个Buffer类,用来创建一个专门存放二进制数据的缓存区. Buf ...

  5. Node.js之使用Buffer类处理二进制数据

    Node.js之使用Buffer类处理二进制数据 Buffer类可以在处理TCP流或文件流时处理二进制数据,该类用来创建一个专门存放二进制数据的缓存区. 1. 创建Buffer对象 1.1 直接创建: ...

  6. “乐”动人心--2017年10款最佳音乐类APP设计盘点

    在上下班的路上,听几首自己喜欢的音乐来打发无聊的等公交车和地铁的时间是现代年轻人的常态.音乐作为最能鼓动人心的"语言",也成为了人们在互联网生活里占比例最高的消费活动之一,一款好看 ...

  7. 浅析nodejs的buffer类(转)

    最近翻阅了node v0.10.4的buffer类的源代码,收获不少,也很久没有在cnode上发表文章了,想把一些收获分享给大家,有什么错误的地方希望大牛们指正啊. 前阵子有位rrestjs框架的使用 ...

  8. 关于FIFO memory buffer模块的设计

    关于FIFO memory buffer模块的设计 FIFO memory `timescale 1ns / 1ps ///////////////////////////////////////// ...

  9. node.js—Buffer类(二进制数据处理模块)

    Buffer类概述 一个用于更好的操作二进制数据的类 我们在操作文件或者网络数据的时候,其实操作的就是二进制数据流 Node为我们提供了一个更加方便的去操作这种数据流的类 Buffer,他是一个全局的 ...

随机推荐

  1. createuser - 定义一个新的 PostgreSQL 用户帐户

    SYNOPSIS createuser [ option...] [ username] DESCRIPTION 描述 createuser 创建一个新的 PostgreSQL 用户.只有超级用户(在 ...

  2. ascii - 在八进制,十进制,十六进制中的 ASCII 字符集编码

    描述 ASCII 是美国对于信息交换的标准代码,它是7位码,许多8位码(比如 ISO 8859-1, Linux 的默认字符集)容纳 ASCII 作为它们的下半部分.对应的国际 ASSII 是 ISO ...

  3. bat copy

    @echo off regedit /s %~dp0regedit.reg                                          //注册注册表xcopy "D: ...

  4. 对比props

    1.在组件中data返回数组对象 2.在父级作用域中写入 (1)prop传值 <btn-grp :buttons="buttons"></btn-grp> ...

  5. 流行-Manifold【0】-维基百科中文版本解释

  6. seq2seq(1)- EncoderDecoder架构

    零 seq2seq是从序列到序列的学习过程,最重要的是输入序列和输出序列是可变长的,这种方式就非常灵活了,典型的机器翻译就是这样一个过程. 一 最基本的seq2seq网络架构如下所示: 可以看到,en ...

  7. ORACLE in与exists语句的区别(一)

    select * from Awhere id in(select id from B) 以上查询使用了in语句,in()只执行一次,它查出B表中的所有id字段并缓存起来.之后,检查A表的id是否与B ...

  8. P1759 通天之潜水(不详细,勿看)(动态规划递推,组合背包,洛谷)

    题目链接:点击进入 题目分析: 简单的组合背包模板题,但是递推的同时要刷新这种情况使用了哪些物品 ac代码: #include<bits/stdc++.h> using namespace ...

  9. 虚拟机Linux与本地虚拟网卡配置---NAT链接方式

    虚拟机Linux与本地虚拟网卡配置---NAT链接方式 **********这是我亲自尝试多次实践出来的结果,不是复制粘贴************************* 首先进行初始化,这样避免有 ...

  10. Django, one-to-many, many-to-many

    1.定义关系 定义三个表,Publisher,Book,Author 一个作者有姓,有名及email地址. 出版商有名称,地址,所在城市.省,国家,网站. 书籍有书名和出版日期. 它有一个或多个作者( ...