前言:

内核态(内核模式)和用户态(用户模式)是linux的一种机制,用于限制应用可以执行的指令和可访问的地址空间,这通过设置某个控制寄存器的位来实现。

进程处于用户模式下,它不允许发起I/O操作,所以它必须通过系统调用进入内核模式才能对文件进行读取。

从用户模式切换到内核模式,主要的开销是处理器要将返回地址(当前指令的下一条指令地址)和额外的处理器状态(寄存器)压入到栈中,这些数据到会被压到内核栈而不是用户栈。

另外,一个进程使用系统调用还隐含了一点——调用系统调用的进程可能会被抢占

当内核代表用户执行系统调用时,

若该系统调用被阻塞,该进程就会进入休眠,然后由内核选择一个就绪状态,当前优先级最高的进程运行。

另外,即使系统调用没有被阻塞,当系统调用结束,从内核态返回时,若在系统调用期间出现了一个优先级更高的进程,则该进程会抢占使用了系统调用的进程。

内核态返回会返回到优先级高的进程,而不是原本的进程。

一、Linux下基本的I/O介绍:

ssize_t read(int fd, void *buf, size_tcount);

ssize_t write(int fd, void *buf, size_tcount);

在Linux中,read 和write 是基本的系统级I/O函数。当用户进程使用read 和 write 读写linux的文件时,进程会从用户态进入内核态,通过I/O操作读取文件中的数据。这样每次读写都通过系统调用会增大系统的负担的。

二、介绍一款在《深入理解计算机系统》中看到的RIO包:

RIO,全称Robust I/O,即健壮的IO包。它提供了与系统I/O类似的函数接口,在读取操作时,RIO包加入了读缓冲区,一定程度上增加了程序的读取效率。

首先有rio_t这个结构体,是一个读缓冲区的格式:

#define RIO_BUFSIZE     4096

typedefstruct

{

int rio_fd;      //与缓冲区绑定的文件描述符的编号

int rio_cnt;        //缓冲区中还未读取的字节数

char *rio_bufptr;   //当前下一个未读取字符的地址

char rio_buf[RIO_BUFSIZE];

}rio_t;

这个是rio的数据结构,通过rio_readinitb(rio_t *, int)可以将文件描述符与rio数据结构绑定起来。注意到这里的rio_buf的大小是4096,为linux中文件的块大小。

初始化读缓冲区

void rio_readinitb(rio_t *rp, int fd)

{

rp->rio_fd = fd;

rp->rio_cnt = 0;

rp->rio_bufptr = rp->rio_buf;

return;

}

带缓冲区的读函数

static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)

{

int cnt;

while(rp->rio_cnt <= 0)

{

rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));

if(rp->rio_cnt < 0)

{

if(errno != EINTR)  //遇到中断类型错误的话应该进行读取,否则就返回错误

return -1;

}

elseif(rp->rio_cnt == 0)   //读取到了EOF

return0;

else

rp->rio_bufptr = rp->rio_buf;      //重置bufptr指针,令其指向第一个未读取字节,然后便退出循环

}

cnt = n;

if((size_t)rp->rio_cnt < n)

cnt = rp->rio_cnt;

memcpy(usrbuf, rp->rio_bufptr, n);

rp->rio_bufptr += cnt;      //读取后需要更新指针

rp->rio_cnt -= cnt;         //未读取字节也会减少

return cnt;

}

ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)

{

size_t leftcnt = n;

ssize_t nread;

char *buf = (char *)usrbuf;

while(leftcnt > 0)

{

if((nread = rio_read(rp, buf, n)) < 0)

{

if(errno == EINTR)      //其实这里可以不用判断EINTR,rio_read()中已经对其处理了

nread = 0;

else

return -1;

}

leftcnt -= nread;

buf += nread;

}

return n-leftcnt;

}

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

{

size_t n;

int rd;

char c, *bufp = (char *)usrbuf;

for(n=1; n<maxlen; n++)    //n代表已接收字符的数量

{

if((rd=rio_read(rp, &c, 1)) == 1)

{

*bufp++ = c;

if(c == '\n')

break;

}

elseif(rd == 0)        //没有接收到数据

{

if(n == 1)          //如果第一次循环就没接收到数据,则代表无数据可接收

return0;

else

break;

}

else

return -1;

}

*bufp = 0;

return n;

}

以上三个的读函数都是带缓冲区的,但是下面这个rio_writen不需要写缓冲。

因为,比如说,我们在写一个http的请求报文,然后将这个报文写入了对应socket的文件描述符的缓冲区,假设缓冲区大小为8K,该请求报文大小为1K。那么,如果缓冲区被设置为被填满才会自动将其真正写入文件(而且一般也是这样做的),那就是说如果没有提供一个刷新缓冲区的函数手动刷新,我还需要额外发送7K的数据将缓冲区填满,这个请求报文才能真正被写入到socket当中。所以,一般带有缓冲区的函数库都会一个刷新缓冲区的函数,用于将在缓冲区的数据真正写入文件当中,即使缓冲区没有被填满,而这也是C标准库的做法。然而,如果一个程序员一不小心忘记在写入操作完成后手动刷新,那么该数据(请求报文)便一直驻留在缓冲区,而你的进程还在傻傻地等待响应。

因此,下面那个函数的fd就是int型的。

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;

else

return -1;

}

bufp += nwritten;

nleft -= nwritten;

}

return n;

}

RIO——健壮的IO包相关推荐

  1. java.io包对象读写_java.io 包中的____________和____________类主要用于对对象(Object)的读写_学小易找答案...

    [多选题]连铸钢水成分控制的要求有( ). [单选题]起动机用直流电动机将电能转化为 [单选题]下列关于我国少数民族传统禁忌的说法中,错误的是( ). [多选题]下列选项中 , 属于表单控件的是 ( ...

  2. 装饰器模式与java.io包

    为什么80%的码农都做不了架构师?>>>    Decorator设计模式是典型的结构型模式(在GOF的那本模式的Bible中将模式分为:1.创建型模式:2.结构型模式:3.行为模式 ...

  3. Java.io包中常用的类

    Java.io包 Java.io.BufferedInputStream类实例 Java.io.BufferedOutputStream类使用例子 Java.io.BufferedReader类 Ja ...

  4. Java源码解析——Java IO包

    一.基础知识: 1. Java IO一般包含两个部分:1)java.io包中阻塞型IO:2)java.nio包中的非阻塞型IO,通常称为New IO.这里只考虑到java.io包中堵塞型IO: 2. ...

  5. 【JDK源码】java.io包常用类详解

    看完java.io的JDK源码,在网上发现一篇关于java.io中的类使用的文章总结的很全面,看完之后在原文的基础上加了一些自己的总结如下构成了本篇文章.原文地址 一.Java Io流 1. Java ...

  6. spring源码分析-core.io包里面的类

    前些日子看<深入理解javaweb开发>时,看到第一章java的io流,发觉自己对io流真的不是很熟悉.然后看了下JDK1.7中io包的一点点代码,又看了org.springframewo ...

  7. Java学习笔记之 IO包 字节流

    IO包最重要的五个类和一个接口 File/OutputStream/InputStream(字节流)/Writer/Reader(字符流) 一个接口:Serializable File类: 字节流: ...

  8. 封装成jar包_通用源码阅读指导mybatis源码详解:io包

    io包 io包即输入/输出包,负责完成 MyBatis中与输入/输出相关的操作. 说到输入/输出,首先想到的就是对磁盘文件的读写.在 MyBatis的工作中,与磁盘文件的交互主要是对 xml配置文件的 ...

  9. golang 中io包用法(一)

    本文转自Golove博客:http://www.cnblogs.com/golove/p/3276678.html   ,并在此基础上进行修改. io 包为I/O原语提供了基础的接口.它主要包装了这些 ...

最新文章

  1. 恢复SQLSERVER被误删除的数据
  2. 百度网盘7.3.1.10版本增加工作空间功能,可实现百度网盘与电脑文件夹同步
  3. list 根据某个数字所在位置_【Python学习笔记】09、使用list和tuple
  4. delphi if多个条件_Python从入门到精通——一文读懂if语句用法
  5. 让你每天精神都好好的方法ZT 1
  6. Linux du 命令
  7. Windows API串口编程
  8. lamp+cacti+ntop+thold+nagios+syslog
  9. centos7.6 挂载硬盘
  10. mantis使用介绍
  11. 关于自然语言理解的一些理解
  12. Ubuntu v18.04安装网易云音乐
  13. 读书笔记-在工作中保持充沛的体力
  14. 自考本科英语(二)学习笔记和考试经验
  15. word排版案例报告_导师:论文排版都搞不好,你拿什么去投稿?!
  16. RoboWare Studio的安装
  17. 大数据行业就业指南:三大方向 十大职位
  18. unity 2D游戏开发 制作帧动画的两种方法
  19. 一些有影响的博客推荐
  20. 云桌面与云盘如何集成?用什么方案集成?

热门文章

  1. leek()函数使用
  2. python数据分析项目实战—————链家北京租房数据统计分析
  3. getsockopt套接口选项
  4. 站内搜寻引擎 php mysql_迅搜(xunsearch) - 开源免费中文全文搜索引擎|PHP全文检索|mysql全文检索|站内搜索...
  5. 什么是物联网安全,为什么它很重要?
  6. 跨时钟域(CDC)优秀文章汇总-持续收集
  7. 【编写if时尽量不要带else】
  8. 计算机二级考试不及格看不到分数吗,计算机二级查不到成绩是不是没过,不及格有分数吗...
  9. 电力系统短路计算MATLAB
  10. 自己努力要学习啦(android的很多demo 总有你需要的)