UNXI系统级的IO函数,在某些情况下,传送的字节数比用户要求的少,会出现不足值(short count)主要原因为:

  • ①读取时遇到EOF:文件的大小不足以填充read需要读取的字节数,那么返回不足值0表示提前遇到EOF
  • ②从终端读取文本行:read函数每次传送一个文本行,返回的不足值表示文本行的大小
  • ③读写网络SOCKET:由于网络延迟等原因,对Linux套接字执行read可能返回不足值(数据还没有接受完)

一种策略是反复调用read函数,直到将所需要的字节全部读取完毕。另一种思路采取缓冲区方式:

带缓冲区输入函数:允许应用程序高效的从文件中读取文本和二进制数据,避免频繁读取和以及解决不足问题。

RIO robust IO健壮IO读取包,其通过实现一个用户级的缓冲区来处理不足值,以及减少频繁的系统级IO的调用。

【rio_t】

一个用户级的内存缓冲区与一个打开的文件描述符关联:

#define RIO_BUFFERSIZE 8192
typedef struct {int rio_fd;   //关联的描述符fdint rio_cnt;  //剩余可读字节数char* rio_bufptr; //当前读开始位置char rio_buf[RIO_BUFFERSIZE];
}rio_t;//初始化缓冲区  关联一个文件描述符fd
void rio_readinitb(rio_t* rp,int fd)  //初始化一个rio_t结构的读缓冲区
{rp->rio_bufptr=rp->rio_buf;//初始化读指针为 buf起点rp->rio_cnt=0;  //未读字节数rp->rio_fd=fd;
}

【rio_readn rio_writen】

实现无缓冲区的读写,主要应用于写入文件:

ssize_t rio_readn(int fd,void* usrbuf,size_t n)
{size_t nleft=n;ssize_t nread;char* bufp=(char*)usrbuf;while(nleft>0){if((nread=read(fd,bufp,nleft))<0){if(errno==EINTR)nread=0;elsereturn -1;}else if(nread==0)break;nleft-=nread;  //将fd的数据直接传送到用户区bufp+=nread;}
}
ssize_t rio_writen(int fd,void* usrbuf,size_t n)
{size_t nleft=n;ssize_t nwritten;char* bufp=(char*)usrbuf;while(nleft>0){if((nwritten=write(fd,bufp,nleft))<=0){if(errno==EINTR)nwritten=0;elsereturn -1;}nleft-=nwritten;bufp+=nwritten;  //指针右移}}

核心函数rio_read

ssize_t rio_read(rio_t* rp,char* usrbuf,size_t n)
  • rp:需要读取的缓冲区(与一个打开文件描述符关联)
  • usrbuf:读取到的用户内存位置
  • n:读取的字节数

其基本实现思路为:

static ssize_t rio_read(rio_t* rp,char* usrbuf,size_t n)
{int cnt;while(rp->rio_cnt<=0){//当缓冲区可读数量为0时,调用read读取到缓冲区rp->rio_cnt=read(rp->rio_fd,rp->rio_buf,sizeof(rp->rio_buf));if(rp->rio_cnt<0){if(errno!=EINTR)return -1;  //读取发生错误}else if(rp->rio_cnt==0)return 0;elserp->rio_bufptr=rp->rio_buf;//缓冲区填充成功 重置起始指针}cnt =n;if(rp->rio_cnt<n){cnt=rp->rio_cnt;//可读的字节数 取较小值}memcpy(usrbuf,rp->rio_bufptr,cnt);rp->rio_bufptr+=cnt;rp->rio_cnt-=cnt;//可读字节数减少return cnt;//返回读取成功的字节数
}

由此可见RIO_READ和Linux系统级的Read函数具有类似的含义。出错时,返回-1.在遇到EOF时,返回不足值0 。

基于rio_read的带缓冲区实现,可以进一步实现:

ssize_t rio_readlineb(rio_t *rp,void* usrbuf,sszie_t maxlen)

该函数读取一行的数据,它会调研rio_read函数从rio缓冲区一个个读取字符,可能发生两种情况:

  • 提前遇到\n 换行符,那么返回已经读取字节数的串
  • 读取到maxlen-1字节的字符,末尾添加NULL 返回这一行
//带缓冲区版本的readline实现
ssize_t rio_readlineb(rio_t* rp,void* usrbuf,size_t maxlen)
{int n;int rc;char c;char *bufp=(char*)usrbuf;for(n=1;n<maxlen;n++)  //填充maxlen-1个字符{if((rc=rio_read(rp,&c,1))==1) //每次从缓冲区中读取一个字符{*bufp++=c;if(c=='\n'){//遇到换行符 提前结束n++;break;}}else if(rc==0){if(n==1)return 0;elsebreak;} elsereturn -1;}*bufp=0; //最后一个填充NULLreturn n-1;}

而借助rio_read实现的rio_readnb实现缓冲区的读取n个字符:

ssize_t rio_readnb(rio_t* rp,void* usrbuf,size_t n)
{ssize_t nleft=n;ssize_t nread;char* bufp=(char*) usrbuf;while(nleft>0){if((nread=rio_read(rp,bufp,nleft))<0){return -1;}else if(nread==0)break;nleft-=nread;bufp+=nread;}return (n-nleft);}

【实验与演示】

int main()
{int n;rio_t rio;char buf[1024];int file_fd=open("rio_test.txt",O_RDWR|O_CREAT,S_IWOTH);rio_readinitb(&rio,STDIN_FILENO);//初始化rio缓冲区 与  STDIN关联while((n=rio_readlineb(&rio,buf,1024))!=0)rio_writen(file_fd,buf,n);//无缓冲区 写入到STDOUT
}

通过关联标准的输入到用户级缓冲区RIO

不断的读取行,并通过直接复制的方式IO输出到 fd打开的文件中:

g++ rio_readlineb.cpp -o rio_readlineb

打开相应的文本文件(权限设定):

chmod 777 rio_test.txt

rio_test.txt 的内容:

RIO是带有用户缓冲区的封装实现,相较于直接调用read函数的优势有以下几点:

①:当缓冲区有可读字节时,直接返回相应大小的字节,无需执行系统调用Read ,避免陷入内核

②:当缓冲区没有可读字节时,执行一次Read,并且Read一次申请读取缓冲区大小的字节,提高了存取效率。

Linux系统级IO②:RIO-带缓冲区IO实现相关推荐

  1. linux cpu 内存爆满 mysql停止_如何用脚本统计linux系统CPU、内存、磁盘IO等信息?...

    概述 今天主要分享一个shell脚本,用来获取linux系统CPU.内存.磁盘IO等信息. 脚本 #!/bin/bash# 获取要监控的本地服务器IP地址IP=`ifconfig | grep ine ...

  2. 通过Xshell7连接云服务Linux系统级上传文件

    通过Xshell7连接云服务Linux系统级上传文件 前提准备条件: 1.有一台云服务实例 2.云服务安装了CentOS 7.8 64位系统(根据自己系统环境) 3.记住云服务实例的用户名和密码(忘记 ...

  3. Linux系统运行时参数命令--网络IO性能监控

    目录 5 网络IO性能监控 5.1 性能指标 5.2 网络信息 5.2.1 套接字信息 5.2.2 协议栈统计信息-netstat命令 5.2.3 网络吞吐-sar命令 5.2.4 连通性和延时 5. ...

  4. linux 系统监控、诊断工具之 IO wait

    1.问题: 最近在做日志的实时同步,上线之前是做过单份线上日志压力测试的,消息队列和客户端.本机都没问题,但是没想到上了第二份日志之后,问题来了: 集群中的某台机器 top 看到负载巨高,集群中的机器 ...

  5. 【Linux系统编程学习】C库IO函数与系统IO函数的关系

    此为黑马Linux课程笔记. 1. C标准IO函数工作流程 如图,以C库函数的fopen为例,其返回类型是FILE类型的指针,FILE类型包含很多内容,主要包含三个内容:文件描述符.文件读写指针的位置 ...

  6. Linux系统编程(十)--高级IO-异步IO

    文章目录 1 同步IO与异步IO 2 POSIX异步IO(aiocb) 3 异步操作状态 3.1 aio_error 3.2 aio_return 4 等待异步IO操作 5 异步IO取消操作 6 批量 ...

  7. linux系统查看CPU使用含义、IO、内存、硬盘使用、负载

    一.Linux系统查看CPU使用率命令 在linux的系统维护中,可能需要经常查看cpu使用率,分析系统整体的运行情况.而监控CPU的性能一般包括以下3点:运行队列.CPU使用率和上下文切换. 对于每 ...

  8. linux标准IO实验,Linux系统编程(第三篇) 标准IO.pdf

    第三章:标准I/O 目标: 本章旨在向学员介绍Linux系统 时间:3 学时 I/O相关函数的使用: 1)掌握I/O相关函数的特点及使 教学方法:讲授PPT 用方法 2 )了解I/O与系统调用相关的函 ...

  9. linux 系统级性能分析工具 perf 的介绍与使用

    目录 1. 背景知识 1.1 tracepoints 1.2 硬件特性之cache 2. 主要关注点 3. perf的使用 3.0 perf引入的overhead 3.1 perf list 3.2 ...

最新文章

  1. python装饰器由浅入深_由浅入深,走进Python装饰器-----第五篇:进阶--类装饰类
  2. MySQL笔记12:C语言访问MYSQL数据库的完整的代码例子
  3. 服务器虚拟交换机到网卡不通,S7700堆叠,服务器之间相互ping不通,关闭备交换机ping正常...
  4. 微信小程序自带地图_微信小程序之map地图
  5. XproerIM-V1,2,12,65475发布。
  6. 什么行业适合年轻人自主创业
  7. 如何切换DNN编辑器
  8. Hive之表类型解析
  9. Ubuntu系统下载工具的推荐
  10. 怎么把音频转换文字?三个步骤解决它
  11. hdmi接口和计算机连接,hdmi接口,教您hdmi接口怎么连接电视
  12. 你可能不知道的Gmail分身小技巧
  13. NetBIOS编程获取本机MAC地址及一个小坑
  14. OI模板 卢卡斯定理
  15. python学习小组分组程序_【Python】每日一练:学生学习小组分组程序
  16. RuntimeError: NEOS requires a valid email address. Please set the ‘NEOS_EMAIL‘ environment variable.
  17. python sum函数的用法
  18. Windows如何使文件显示扩展名
  19. Sobel算子的数学基础
  20. 欧陆风云3实用修改代码

热门文章

  1. 东风破 -词:方文山 曲:周杰伦
  2. 模型稳定度指标PSI与IV
  3. 索尼sony xperia xc刷安卓7、8,解锁root教程
  4. 7-3 sdut-C语言实验- 对称矩阵的判定
  5. rpc服务器不可用桌面图标消失,rpc服务器不可用,教您rpc服务器不可用怎么办
  6. 光场相机预处理 TFTOOLBOX
  7. 啊哈C——学习3.2一起来找茬
  8. mysql 赋权限_MySQL赋予用户权限命令总结
  9. 华为2288H v5服务器配置JBOD(硬盘直通)
  10. 大数据对于旅游业意味着更大的挑战