在上篇Unix系统级I/O中,我们介绍了有关在Unix环境下读取和写入文件的函数readwrite,也提到了标准I/O在进行网络I/O时的局限性。但是在某些地方,直接使用readwrite往往会出现不足值,比如在复杂的网络环境中读取socket。如果想让我们的程序更加的可靠,就需要反复的调用readwrite去处理,知道传送完所需要的字节。在csapp一书中,给我们提供了一个健壮可靠的I/O包来自动处理这种不足值的情况,称为RIO(Robust I/O)。本文主要整理RIO提供的函数备忘。

详细代码及用法示例可以在这里找到。

无缓冲区的rio

rio_readnrio_writenreadwrite用法基本一致,只是rio_readn会不断尝试读出,直到读取出n个字节或遇到EOF或出错;rio_writen函数绝不会返回一个不足值,它会不断尝试写入直到写入全部字节或者出错。由于没有缓冲区的存在,rio_readnrio_writen可以任意交替使用。

#include "rio.h"ssize_t  rio_readn(int fd, void *buf, size_t n);
/* 返回:若成功则为传送的字节数,若为EOF则为0,若出错则为-1 */ssize_t  rio_writen(int fd, void *buf, size_t n);
/* 返回:若成功则为传送的字节数,若出错则为-1 */

函数定义如下:

ssize_t rio_readn(int fd, void *usrbuf, size_t n)
{size_t nleft = n;ssize_t nread;char *bufp = usrbuf;while (nleft > 0) {if ((nread = read(fd, bufp, nleft)) < 0) {if(errno == EINTR)      /* Interrupted by big handler return */nread = 0;          /* and call read() again */elsereturn -1;          /* errno set by read() */}else if (nread == 0)break;                  /* EOF */nleft -= nread;bufp += nread;}return (n - nleft);             /* return >= 0 */
}ssize_t rio_writen(int fd, void *usrbuf, size_t n)
{size_t nleft = n;ssize_t nwritten;char *bufp = usrbuf;while (nleft > 0) {if ((nwritten = write(fd, bufp, nleft)) <= 0) {if(errno == EINTR)      /* Interrupted by big handler return */nwritten = 0;       /* and call write() again */elsereturn -1;          /* errno set by write() */}nleft -= nwritten;bufp += nwritten;}return n;
}

带缓冲区的rio

带缓冲区的rio所包含的函数如下:

#include "rio.h"void rio_readinitb(rio_t *rp, int fd);
/* 返回:无 */ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
/* 返回:若成功则为读的字节数,若为EOF则为0,若出错则为-1 */

带缓冲区的rio由一个rio_t的结构体管理,其形式如下:

#define RIO_BUFSIZE 8192typedef struct {int     rio_fd;                 /* 描述符 */int     rio_cnt;                /* 缓冲区中还未读的字节数 */char    *rio_bufptr;            /* 缓冲区中下一个未读的字节 */char    rio_buf[RIO_BUFSIZE];   /* 缓冲区 */
} rio_t;

在使用带缓冲区的rio时,每打开一个描述符,都需要使用rio_readinitb来对rio_t进行初始化:

void rio_readinitb(rio_t *rp, int fd) {rp->rio_fd = fd;rp->rio_cnt = 0;rp->rio_bufptr = rp->rio_buf;
}

对缓冲区的控制主要由rio_read来完成:

static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n) {int cnt;while (rp->rio_cnt <= 0) {  /* Refill if buf is empty */rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));if (rp->rio_cnt < 0) {if (errno != EINTR) /* Interrupted by sig handler return */return -1;} else if (rp->rio_cnt == 0)  /* EOF */return 0;elserp->rio_bufptr = rp->rio_buf; /* Reset buffer ptr */}/* Copy min(n, rp->rio_cnt) bytes from internal buf to user 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函数由static关键字修饰成静态函数,这对与一个函数来说,说明这个函数只对声明它的文件可见,且不同的文件可以声明相同名的静态函数。

rio_readlinebrio_readnb的具体实现如下:

ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n) {size_t nleft = n;ssize_t nread;char *bufp = usrbuf;while (nleft > 0) {if ((nread = rio_read(rp, bufp, nleft)) < 0)return -1;          /* errno set by read() */else if (nread == 0)break;              /* EOF */nleft -= nread;bufp += nread;}return (n - nleft);         /* return >= 0 */
}ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) {int n, rc;char c, *bufp = usrbuf;for (n = 1; n < maxlen; n++) {if ((rc = rio_read(rp, &c, 1)) == 1) {*bufp++ = c;if (c == '\n') {n++;break;}} else if (rc == 0) {if (n == 1)return 0;   /* EOF, no data read */elsebreak;      /* EOF, some data was read */} elsereturn -1;      /* Error */}*bufp = 0;return n - 1;
}

健壮的I/O(RIO)相关推荐

  1. Android Surface system analyze

    CSDN新首页上线啦,邀请你来立即体验! 立即体验 博客     学院     下载     GitChat     更多 prike 深入理解 Android 卷I - 第8章 深入理解Surfac ...

  2. 用RIO包健壮地读写

    用RIO包健壮地读写 RIO 包全名为 Robust IO 函数包.包中函数是对 Linux 基本 I/O 函数的封装,使其更加健壮.高效,更适用于网络编程.具体来说,它会自动处理读写中的不足值情况. ...

  3. RIO——健壮的IO包

    前言: 内核态(内核模式)和用户态(用户模式)是linux的一种机制,用于限制应用可以执行的指令和可访问的地址空间,这通过设置某个控制寄存器的位来实现. 进程处于用户模式下,它不允许发起I/O操作,所 ...

  4. 健壮I/O读写函数——RIO包

    RIO(Robust I/O,健壮的I/O) 头文件说明 #include <unistd.h> //unistd.h 中所定义的接口通常都是大量针对系统调用的封装,如 fork.pipe ...

  5. 健壮的网络编程IO函数-RIO包

    RIO包 简介 Rio包即为Robust io函数包.包中函数是对Linux基本I/O函数的封装,使其更加健壮.高效,更适用于网络编程. 分析 Rio包由rio_t结构体和系列函数组成. 首先是两个不 ...

  6. Linux IO操作——RIO包

    1.linux基本I/O接口介绍 ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, void *buf, siz ...

  7. 网络编程使用标准I/O的危险以及正确使用RIO包

    一.各IO包的关系 Unix I/O模型是在操作系统内核中实现的,应用程序可以通过诸如open.close.lseek.read.write和stat这样的函数来访问Unix I/O.较高级别的RIO ...

  8. 代码质量第4层——健壮的代码!

    健壮性(Robustness) 是指程序在遇到规范以外的输入,错误和异常时,仍能正常运行.简单来说,健壮代码的适应性很强,不会因为一些异常,就导致程序崩溃. 不健壮的前端代码体现为: 接口返回异常或报 ...

  9. appium获取元素节点的方法_Appium学废系列(四) 如何写出优雅又健壮的脚本

    ‍‍正文共:3716字  预计阅读时间:10分钟 1 合理使用appium自动化等待方法 在自动化测试脚本的运行过程中,webdriver操作浏览器的时候,对于元素的定位是有一定的超时时间,大致应该在 ...

最新文章

  1. Java 线程 — ThreadPoolExecutor
  2. 新手入门深度学习 | 2-3:文本数据建模流程示例
  3. SAP UI5 Require Busy dialog
  4. 如何才能学好单片机?​
  5. 如何不让FCKEditor自动添加P标签
  6. Android 9 带着 AI 来了,为什么我们还停留在 6?
  7. eclipse建java项目不见_秒建一个后台管理系统?用这5个开源免费的Java项目就够了...
  8. jQuery:获取浏览器中的分辨率
  9. javascript把特定XML响应解析成一个对象
  10. 同济大学计算机专业考研的教材,同济大学电子信息(计算机与智能技术)专业考研参考书目-指定教材-辅导资料...
  11. 层次分析法(AHP),超详解,进来秒懂!!
  12. R语言学习(五)——聚类分析
  13. Linux系统装intel网卡,在Centos下安装intel网卡的方法
  14. 【web攻防】CVE-2020-10487 tomcat 文件包含漏洞 docker 复现学习
  15. go模拟android浏览器,模拟浏览器登录操作
  16. oracle脏读如何解决,关于脏读分析
  17. 目前住院病人主要由护士护理这样做不仅需要大量护士而且由子不能随时观察危重病人的病情变化还可能会延误抢救时机.某医院打算开发-个以计算机为中心的患者监护系统试写出问题定义并且分析开发这个系统的可行性.
  18. [Swift]LeetCode41. 缺失的第一个正数 | First Missing Positive
  19. Zemax光学设计(六)——MTF(调制传递函数)曲线
  20. 最新计算机专业技术年度考核,信息技术教师个人年度考核工作总结

热门文章

  1. LeekCode3_无重复字符的最长子串(中等)
  2. centos java 乱码,linux(centos7)下程序中文输出乱码问题的解决
  3. 精仿小鸟云官网高大上模板,可做对接IDC站
  4. (googlechrome)未知错误导致安装失败,如果googlechrome....
  5. 使用ArchR分析单细胞ATAC-seq数据(第四章)
  6. 通过 汇编了解C语言 指针 悬垂指针概念
  7. 身家过亿的帝都富豪来参加1024节专属盛典,小码农献上单链表一篇来庆祝盛典
  8. 约数的和及约数的个数
  9. Python1.语言基本要素上(郭炜老师python大学mooc)
  10. 债转股问题研究(lunwen+开题报告+外文翻译)