Linux系统级IO②:RIO-带缓冲区IO实现
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实现相关推荐
- linux cpu 内存爆满 mysql停止_如何用脚本统计linux系统CPU、内存、磁盘IO等信息?...
概述 今天主要分享一个shell脚本,用来获取linux系统CPU.内存.磁盘IO等信息. 脚本 #!/bin/bash# 获取要监控的本地服务器IP地址IP=`ifconfig | grep ine ...
- 通过Xshell7连接云服务Linux系统级上传文件
通过Xshell7连接云服务Linux系统级上传文件 前提准备条件: 1.有一台云服务实例 2.云服务安装了CentOS 7.8 64位系统(根据自己系统环境) 3.记住云服务实例的用户名和密码(忘记 ...
- Linux系统运行时参数命令--网络IO性能监控
目录 5 网络IO性能监控 5.1 性能指标 5.2 网络信息 5.2.1 套接字信息 5.2.2 协议栈统计信息-netstat命令 5.2.3 网络吞吐-sar命令 5.2.4 连通性和延时 5. ...
- linux 系统监控、诊断工具之 IO wait
1.问题: 最近在做日志的实时同步,上线之前是做过单份线上日志压力测试的,消息队列和客户端.本机都没问题,但是没想到上了第二份日志之后,问题来了: 集群中的某台机器 top 看到负载巨高,集群中的机器 ...
- 【Linux系统编程学习】C库IO函数与系统IO函数的关系
此为黑马Linux课程笔记. 1. C标准IO函数工作流程 如图,以C库函数的fopen为例,其返回类型是FILE类型的指针,FILE类型包含很多内容,主要包含三个内容:文件描述符.文件读写指针的位置 ...
- Linux系统编程(十)--高级IO-异步IO
文章目录 1 同步IO与异步IO 2 POSIX异步IO(aiocb) 3 异步操作状态 3.1 aio_error 3.2 aio_return 4 等待异步IO操作 5 异步IO取消操作 6 批量 ...
- linux系统查看CPU使用含义、IO、内存、硬盘使用、负载
一.Linux系统查看CPU使用率命令 在linux的系统维护中,可能需要经常查看cpu使用率,分析系统整体的运行情况.而监控CPU的性能一般包括以下3点:运行队列.CPU使用率和上下文切换. 对于每 ...
- linux标准IO实验,Linux系统编程(第三篇) 标准IO.pdf
第三章:标准I/O 目标: 本章旨在向学员介绍Linux系统 时间:3 学时 I/O相关函数的使用: 1)掌握I/O相关函数的特点及使 教学方法:讲授PPT 用方法 2 )了解I/O与系统调用相关的函 ...
- linux 系统级性能分析工具 perf 的介绍与使用
目录 1. 背景知识 1.1 tracepoints 1.2 硬件特性之cache 2. 主要关注点 3. perf的使用 3.0 perf引入的overhead 3.1 perf list 3.2 ...
最新文章
- python装饰器由浅入深_由浅入深,走进Python装饰器-----第五篇:进阶--类装饰类
- MySQL笔记12:C语言访问MYSQL数据库的完整的代码例子
- 服务器虚拟交换机到网卡不通,S7700堆叠,服务器之间相互ping不通,关闭备交换机ping正常...
- 微信小程序自带地图_微信小程序之map地图
- XproerIM-V1,2,12,65475发布。
- 什么行业适合年轻人自主创业
- 如何切换DNN编辑器
- Hive之表类型解析
- Ubuntu系统下载工具的推荐
- 怎么把音频转换文字?三个步骤解决它
- hdmi接口和计算机连接,hdmi接口,教您hdmi接口怎么连接电视
- 你可能不知道的Gmail分身小技巧
- NetBIOS编程获取本机MAC地址及一个小坑
- OI模板 卢卡斯定理
- python学习小组分组程序_【Python】每日一练:学生学习小组分组程序
- RuntimeError: NEOS requires a valid email address. Please set the ‘NEOS_EMAIL‘ environment variable.
- python sum函数的用法
- Windows如何使文件显示扩展名
- Sobel算子的数学基础
- 欧陆风云3实用修改代码