系统级 I/O与缓冲机制

深入解析Android Car WatchDog机制:I/O监控的阈值配置与调试技巧 本文深入解析了Android Car WatchDog机制中的I/O监控服务,详细阐述了其核心架构、阈值配置模型与分级处置策略。通过剖析源码和配置文件,提供了针对I/O过度使用问题的实战调试技巧与优化策略,帮助车载应用开发者确保系统稳定性,避免因资源过度消耗导致应用被禁用。 阅读详情

最近实验室的学弟们貌似对缓冲区很感兴趣,听到很多次在讨论缓冲区。今天也来写篇文章和大家讨论一下。从I/O,到缓冲区都会谈到。首先是所有语言都提供了执行I/O的较高级别的工具,例如ANSI C提供了标准I/O库,C++重载了<<和>>等,这些不依赖于系统内核,所以移植性强,而且这个缓冲区的分配长度和优化等细节都是代你处理好了。在Unix系统中,是通过使用有内核提供的系统级Unix I/O函数来实现这些较高级别的I/O函数的。

高级别I/O函数工作很好,上面也提到了几点优点,为什么还要学习Unix I/O呢?

  1. 了解Unix I/O可以帮你理解其他的系统概念。比如进程、存储器层次结构、链接和加载等。
  2. 有时候除了使用Unix I/O 以外别无选择。有些重要情况下,使用高级I/O函数不能实现想要的功能,比如标准I/O库没有提供读取文件元数据的方式,比如文件大小或文件创建时间等。

I/O 概念:

输入/输出(I/O)是在主存和外部设备(如磁盘驱动器、终端和网络)之间拷贝数据的过程。输入操作是从I/O设备拷贝数据到主存,而输出操作是从主存拷贝数据到I/O设备。

所有的I/O设备都被模型化为外文件,所有的输入输出都被当做对相应文件的读和写来执行。设备映射为文件,使得输入输出能够以一种统一且一致的方式来执行。

一系列的Unix I/O函数

#include <sys/type.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(char *filename, int flags, mode_t mode);   

//将filename转换为一个文件描述符, 成功则返回非负的新的文件描述符,出错返回-1
//flags     指明了进程如何访问这个文件
//mode      指定了新文件的访问权限位
#include <unistd.h>
int close(int fd);  
//关闭此文件描述符对应的文件,成功返回09,出错返回-1
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t n);    
//从文件描述符为fd的当前文件位置,拷贝最多n个字节到存储器位置buf。
//成功返回实际传送的字节数,若EOF则为0,出错返回-1
#include <unistd.h>
ssize_t write(int fd, const char *buf, size_t n);  //成功返回写的字节数,出错则为-1
//从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置。
//成功返回写的字节数,出错则为-1
Q:ssize_t和size_t有些什么区别?

A:size_t 被定义为 unsigned int,而ssize_t(有符号的大小)被定义为 int。read函数返回一个有符号的大小,而不是一个无符号的大小,是因为出错返回-1,这使得read的最大值减小了一半,从4G减小到了2G。

什么是“不足值”?

“不足值”的情况:指的是某些情况下,read和write传送的字节比应用程序要求的要少,这些不足值不表示有错误。
造成这种情况的原因有:

  1. 读时遇到EOF。要求的字节数超过了读缓冲区内未读的字节的数量。
  2. 从终端读取文本行。如果打开文件是与终端想关联的(比如键盘和显示器),那么每个read函数将一次传送一个文本行,返回的不足值等于文本行的大小。
  3. 读和写socket。内部缓冲约束和较长的网络延迟会引起read和write返回不足值。

用RIO包健壮地读写

在像网络程序这样容易出现不足值的应用中,RIO(Robust I/O)包提供了方便、健壮和高效的I/O。

RIO提供了两类不同的函数:
  1. 无缓冲的输入输出函数。直接在存储器和文件之间传送数据,没有应用级缓冲。对将二进制数据读写到网络和从网络中读写二进制数据尤其有用。
  2. 带缓冲的输入函数。允许你高效地从文件中读取文本行和二进制数据,这些内容缓存在应用级缓冲区内。带缓冲的RIO输入函数是线程安全的,允许在同一个文件描述符上被交替地调用。

带缓冲I/O和不带缓冲I/O有什么区别?

所谓不带缓冲,并不是内核不提供缓冲,系统内核对磁盘的读写都会提供一个块缓冲(也有人称为内核高速缓存),当调用一次read或write函数,直接进行系统调用,将数据写入到块缓冲进行排队。因此所谓的不带缓冲的I/O是指进程不提供缓冲功能,内核还是提供缓冲的。

而带缓冲的I/O是指进程对输入输出流进行了改进,比如调用标准I/O库函数往磁盘写数据时,标准IO库提供了一个流缓冲,先把数据写入流缓冲区中,当达到一定条件,比如流缓冲区满了或者手动刷新了流缓冲,这时候才会把数据一次送往内核提供的缓冲,再经块缓冲写入磁盘。

因此,带缓冲I/O一般会比不带缓冲I/O调用系统调用的次数要少。


ssize_t write(int filedes, const void *buff, size_t nbytes)
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp)

拿这两个函数来说,首先要清楚,所谓的带缓冲并不是指上面两个函数的buff参数。

现在假设内核设的缓存是100字节,如果你使用write,且buff的size是10字节,当你要把10个同样的buff写到文件时,需要调用10次write,也就是10次系统调用,此时因为延迟写的技术,并没有写到硬盘,如果想立即写入硬盘,需调用fsync。(涉及写操作机制几个概念,同步写机制、延迟写机制、异步写机制,此处不说了,可以查一下)

标准I/O,也就是带缓存的IO,也称为用户态的缓存,区别于内核所设的缓存。假设缓存长度为50字节,把100字节的数据写到文件,只需2次系统调用,因为先把数据写到流缓存,当其满或者手动刷新之后才填入内核缓存,所以2次就够了。

至于究竟写到了文件中还是内核缓冲区中,对于进程来说是没有差别的,如果进程A和进程B打开同一文件,进程A写到内核缓冲区中的数据从进程B也能读到,因为内核空间是进程共享的。
C标准库这类缓冲区不具有这一特性,因为进程的用户空间是独立的。


下面具体来看RIO 是怎么实现的。

RIO的无缓冲输入输出函数
/*
 * 无缓冲输入函数 
 * 成功返回收入的字节数 
 * 若EOF返回0 ,出错返回-1
 */
ssize_t rio_readn(int fd, void *usrbuf, size_t n)
{
   size_t nleft = n;
   ssize_t nread = 0;
   char *pbuf = usrbuf;

   while(nleft > 0){
       //在某些系统中,当处理程序捕捉到一个信号时,被中断的系统调用(read write accept)
       //在信号处理程序返回时不再继续,而是立即返回给客户一个错误条件,并将errno设置成为EINTR
       if((nread = read(fd, pbuf,nleft)) == -1){
           if(errno == EINTR){  
               nread = 0;   //中断造成的,再次调用read
           } else{
               return -1;   //出错
           }
       }
       else if(nread == 0)  //到了文件末尾
           break;
       nleft -=nread;
       pbuf += nread;
   }
   return n-nleft;
}

/*
 * 无缓冲输出函数
 * 成功返回输出的字节数,出错返回-1
*/ 
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)
                nwritten = 0;
            else
                return -1;
        }
        nleft -=nwritten;
        bufp += nwritten;
    }

    return n;   // write 不会返回不足值
}
RIO的带缓冲输入函数

每次调用 read 都会陷入内核态,频繁的调用效率不是很高。更好的方法就是调用一个包装函数,它从一个内部读缓冲区拷贝数据,当缓冲区变空时,会自动地调用 read 重新填满缓冲区。

#define RIO_BUFSIZE 8192

typedef struct {
    int rio_fd;                 //内部读缓冲区描述符
    int rio_cnt;                //内部缓冲区中未读字节数
    char *rio_bufptr;           //内部缓冲区中下一个未读的字节
    char rio_buf[RIO_BUFSIZE];  //内部读缓冲区
}rio_t;     //一个类型为rio_t的读缓冲区


// 初始化rio_t结构,创建一个空的读缓冲区
// 将fd和地址rp处的这个读缓冲区联系起来
void rio_readinitb(rio_t *rp, int fd)
{
    rp -> rio_fd = fd;
    rp -> rio_cnt = 0;
    rp -> rio_bufptr = rp -> rio_buf;
}


//是 RIO 读程序的核心,是Unix read函数的带缓冲的版本,供内部调用
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;
        } 
        else if(rp -> rio_cnt == 0)  //EOF
            return 0;
        else
            rp -> rio_bufptr = rp -> rio_buf;   //重置指针位置
    }

    //从内部缓冲区拷贝到用户缓冲区中
    cnt = (rp -> rio_cnt < n) ? rp -> rio_cnt : n;

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

    rp -> rio_bufptr += cnt;
    rp -> rio_cnt -= cnt;

    return cnt;
}

//带缓冲输入函数,每次输入一行
//从文件rp读出一个文本行(包括结尾的换行符),将它拷贝到usrbuf,并且用空字符来结束这个文本行
//最多读maxlen-1个字节,余下的一个留给结尾的空字符
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
    int rc,n;
    char c,*bufp = usrbuf;
    for(n = 1; n<maxlen; n++){
        if((rc = rio_read(rp, &c, 1)) == 1){     //每次读取一个字符
            *bufp++ = c;
            if(c == '\n')
                break;
        } else if(rc == 0){
            if(n == 1)      //空文件
                return 0;
            else
                break;      //读到部分数据
        } else
            return -1;      //出错
    }

    *bufp = '\0';              //添加字符串结尾符
    return n-1;
}


//带缓冲输入函数
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;       //出错 
        } else if( nread == 0 )
            break;      //EOF

        nleft -= nread;
        bufp += nread;
    }

    return (n - nleft);
}

实现过程参考 CSAPP 第十章内容。

为什么rio_writen()不需要缓冲呢?

假设将一个HTTP请求写到对应socket的文件描述符的缓冲区,假设缓冲区大小为8K,该请求报文大小为1K,那么如果缓冲区被设置为只有填满才会真正被写入文件,那就是说如果没有提供一个刷新缓冲区的函数手动刷新,还需要额外发送7K的数据将缓冲区填满,这个报文才能真正被写入到socket中。

所以一般带有缓冲区的函数库都会有一个刷新缓冲区的函数,用于将在缓冲区的数据真正写入文件当中,即使缓冲区没有被填满,这正是C标准库的做法。然而如果程序开发人员不小心忘记在写入操作完成后手动刷新,那么该数据便一直驻留在缓冲区,进程也会被阻塞。

做网络应用程序应该用什么I/O函数?

Unix对网络的抽象是一种称为套接字的文件类型,也是文件描述符。标准I/O流,程序能够在同一个流上执行输入和输出,因此从某种意义上来说是全双工的。然后,对流的限制和对套接字的限制,有时候会互相冲突。比如下面两个限制:

  1. 如果中间没有插入对fflush、fseek、fsetpos或者rewind的调用,一个输入函数不能跟随在一个输出函数之后。fflush是清空流缓冲区,后三个函数使用 Unix I/O lseek 函数重置当前的文件位置。
  2. 如果中间没有插入对fseek、fsetpos或者rewind的调用,一个输出函数不能跟随在一个输入函数之后,除非输入函数入到EOF。

在开发网络应用中,对套接字使用 lseek 是非法的。因此对上面限制1 来说还可以采用刷新缓冲区来满足;然而对第二个限制的唯一办法是,对同一个打开的套接字描述符打开两个流,一个用来读,一个用来写。
但是它要求应用程序在两个流上都要调用 fclose,这样才能释放相关存储器资源,多个操作试图关闭同一个描述符,第二个close就会失败,在线程化程序中关闭一个已经关闭了的描述符是会导致灾难的。

引用书上原文:

因此,我们建议你在网络套接字上不要使用标准I/O函数来进行输入和输出。而要使用健壮的RIO函数。如果需要使用格式化的输出,使用 sprintf 函数在存储器中格式化一个字符串,然后用 rio_writen 把它发送到套接口。如果需要格式化输入,使用 rio_readlineb 来读一个完整的文本行,然后用 sscanf 从文本行提取不同的字段。

RIO(Robust I/O)(tar.gz) 健壮的I/O包(Robust I/O),用于处理套接字编程中使用read和write出现不足值的情况。 立即下载

相关推荐

RIO(Robust I/O)(zip)

健壮的I/O包(Robust I/O),用于处理套接字编程中使用read和write出现不足值的情况。

IOCP模型总结

<br />IOCP模型总结<br /> IOCP(I/O Completion Port,I/O完成端口)是性能最好的一种I/O模型。它是应用程序使用<br /><br /> 线程池处理异步I/O请求的一种机制。在处理多个并发的异步I/O请求时,以往的模型都是在<br /><br /> 接收请求是创建一个线程来应答请求。这样就有很多的线程并行地运行在系统中。而这些线<br /><br /> 程都是可运行的,Windows内核花费大量的时间在进行线程的上下文切换,并没有多少时间花<br /><br

shigaopb的专栏 1678

浅谈带缓冲I/O 和不带缓冲I/O的区别与联系

这里搜集从网上看到的一些言论,自认为还是比较靠谱的,有些不靠谱的根据自己的理解进行了修正。 首先要明白不带缓冲的概念:所谓不带缓冲,并不是指内核不提供缓冲,而是只单纯的系统调用,不是函数库的调用。系统内核对磁盘的读写都会提供一个块缓冲(在有些地方也被称为内核高速缓存),当用write函数对其写数据时,直接调用系统调用,将数据写入到块缓冲进行排队,当块缓冲达到一定的量时,才会把数据写入磁盘。因此所谓的不带缓冲的I/O是指进程不提供缓冲功能(但内核还是提供缓冲的)。每调用一次write或read函数,直接系统调用。 而带缓冲的I/O是指进程对输入输出流进行了改进,提供了一个流缓冲,当用fwrit

C++ windows网络编程系列1—各种通信模型对比

介绍windows网络编程的通信模型及对比,包括介绍同步、异步、阻塞、非阻塞I/O,着重介绍select模型和iocp模型的优缺点和应用场景。

saber的博客 4098

《点云处理算法》——GROR配准

GROR点云配准

阁楼 1315

DataGrip 2023.3 Windows版激活保姆级教程:从下载脚本到输入激活码,一次搞定

本文提供DataGrip 2023.3 Windows版的完整安装与授权指南,从环境准备到数据库连接管理,再到高效开发技巧与高级功能扩展,帮助开发者快速掌握这一专业数据库管理工具。内容涵盖安装步骤、初始配置、常见问题解决及性能调优技巧,适合数据库开发新手和专业人士。

weixin_30275415的博客 634

C++ IO框架

问题描述:在客户端阻塞于标准输入上的fgets调用时,如果服务器进程突然终止,服务器TCP虽然正确地给客户端发送了一个FIN,但是客户端正阻塞于从标准输入读入的过程,因此无法立即看到这个EOF(文件结束符)。直到从标准输入读到数据后,客户端才能看到EOF,但此时可能已经错过了及时处理服务器关闭的时机。解决方案需求:这样的进程就需要一种预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪(如TCP连接关闭、标准输入有数据可读等),就通知进程。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 1586

Calibre LVS效率翻倍秘籍:用Hierarchical Flow处理亿级晶体管设计的5个关键阶段

本文详细解析了如何利用Hierarchical Flow技术提升Calibre LVS在亿级晶体管SoC设计中的验证效率。通过五个关键阶段的分层验证流程,包括顶层抽象验证、模块级独立验证等,可显著降低内存占用40-60%,缩短迭代周期50-70%,特别适用于SMIC等先进工艺节点。文章还分享了算力资源优化、并行化处理等实战技巧,帮助工程师应对大规模芯片验证挑战。

sam99的博客 768

Linux IO操作——RIO包

1.linux基本I/O接口介绍 ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, void *buf, size_t count); 以上两个是linux下的两个系统调用。用于对文件行主要的I/O操作。fd是非负文件描写叙述符,事实上相当于标识一个文件的唯一编号。默认标号0是标准输...

weixin_34122604的博客 616

别再乱拖了!Godot 4.x 场景编辑器的7个隐藏操作技巧(附快捷键清单)

本文揭示了Godot 4.x场景编辑器的7个隐藏操作技巧,包括智能对齐、轴心点应用、多节点批量操作等,帮助开发者提升游戏开发效率。特别介绍了坐标系切换和自定义快捷键等实用功能,适用于处理复杂场景和团队协作。

weixin_29534421的博客 361

《软件工程——实践者的研究方法》重难点复习笔记(第八章——理解需求)

8项需求工程任务 inception 开始 8.1.1 identify stakeholders 定义:从软件开发中收益 例如:市场人员、销售经理、顾客、顾问、维护团队等(P139) 8.1.2 这个阶段的问题是context-free的。有三套(P140) 8.1.3 提到NFR(nonfunctional requirement)和QFD(quality

whooiif的博客 1814

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

RIO(Robust I/O,健壮的I/O)头文件说明#include &lt;unistd.h&gt; //unistd.h 中所定义的接口通常都是大量针对系统调用的封装,如 fork、pipe 以及各种 I/O 原语(read、write、close 等) #include &lt;fcntl.h&gt; //fcntl.h定义了很多宏和open、fcntl函数原型 #inc...

小码的嵌入式技术博客 2101

ESP32-S3射频测试与全球认证全栈实践指南

功率谱密度(PSD)和发射功率等级是无线通信设备射频合规的核心基础概念,其物理层原理直接决定自适应测试、阻塞容限及多国认证的通过路径。PSD ≥10 dBm/MHz触发强制性自适应测试,需验证LBT机制与跳频鲁棒性;而16级可编程发射功率等级(-24 dBm至+20 dBm)则为功耗、覆盖与法规平衡提供工程调控维度。该能力广泛应用于低功耗蓝牙IoT终端、智能家居网关及工业无线传感器等场景,尤其在ESP32-S3平台中,需结合eFuse校准、Sigma工具链与QuickTrack认证策略实现从实验室调试到量产

weixin_34945060的博客 285

系统I/O与底层

从I/O底层理解Linux下一切皆文件的原则、剖析用户缓冲区与内核缓冲区的意义、理解重定向的实现原理。

geek! 1021

【异常】Cursor 模型服务地域访问限制报错的完整排查与解决方案This model provider doesn‘t serve your region

其本质是:Cursor客户端依赖的上游大语言模型服务提供商,基于自身服务的合规运营范围,对客户端发起的请求进行了来源地域权限校验;当系统检测到请求的网络来源地域,不在该模型服务商官方授权提供服务的地域范围内时,会触发服务访问拦截策略,拒绝响应本次模型调用请求,最终在客户端抛出该报错。合规声明:本文所提供的所有方案,均仅用于技术问题排查与解决,请您在使用过程中严格遵守当地法律法规,以及对应软件与模型服务提供商的用户协议与合规要求。更多关于AI+教育领域的干货,可以关注我的微信公众号一时间获取哦~

奶爸的编程之路,也就一周冷个三天 1134

ofd转pdf报错:org.ofdrw.reader.ZipUtil.unZipFileByApacheCommonCompress【已解决】

ofd转pdf报错:java.lang.NoClassDefFoundError:org/apache/commons/io/function/IOIterator at org.ofdrw.reader.ZipUtil.unZipFileByApacheCommonCompress,java.lang.NoSuchMethodError:org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.getNextEntry()

黄团团的个人博客 1283

Linux文件操作与I/O全解析:从C接口到系统调用(上)

从C标准库到系统调用,从用户缓冲到内核页缓存,文件操作的不同层级提供了灵活性与性能的取舍平衡。深入理解文件描述符、缓冲机制和重定向原理,是构建高效可靠应用的基石。建议通过。

qwer55588的博客 885

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

系统级I/O

csapp 系统级I/O

刘大帅 1155

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

计算系统安全速成之系统级I/O【11】

计算系统安全速成之系统级I/O

缘友一世的博客 1332

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

《深入理解计算机系统》读书笔记11: 系统级 I/O

作者: andylin02学习章节: 第 10 章 系统级 I/O关键词: Unix I/O;文件描述符;RIO包;带缓冲的输入输出;共享文件;I/O重定向;标准I/O库;stat;目录操作;套接字;Shell Lab。

1183

Linux 文件 I/O 太难懂?一文吃透 Linux 系统级文件操作

相信很多Linux学习者都会有这样的困惑:天天在终端敲各种命令,看似熟练,却摸不透底层逻辑。这些操作我们闭着眼都能敲,但背后的门道你真的懂吗?为什么>能改变输出方向?用open函数打开文件后,返回的那个数字(比如3、4)又是什么?运行这段代码(gcc编译后执行),你会发现fd的值通常是3——这就是我们今天的核心主角,也是贯穿所有I/O和重定向的“钥匙”。搞懂它,你才能真正看透Linux文件操作的底层。文件I/O是Linux系统的核心能力,也是开发者夯实底层基础的关键。

hw5230的博客 872

Linux系统学习【理解“文件“、回顾C文件接口、系统文件I/O、理解“⼀切皆⽂件“、缓冲区】

本文深入探讨Linux系统中"一切皆文件"的设计理念,从狭义文件(文本/代码)扩展到广义文件(设备/管道/网络),分析统一文件接口(open/read/write/close)和文件描述符机制。通过C语言文件操作示例(如实现简易cat命令),过渡到系统调用层面,讲解open/read/write/close等底层接口的使用及与C库函数的区别。重点剖析文件描述符本质(内核数组索引)、默认分配规则(0/1/2对应标准I/O)和重定向原理(dup2系统调用)。全文贯穿Linux的设计,帮助读者构建知识体系。

承于所学,探技术之渊;以代码求政,寻成长之道。 1万+

操作系统I/O结构全解析:从DMA到异步I/O,性能问题一网打尽

在计算机系统中,I/O(输入/输出)是连接CPU与外部设备的关键通道。很多开发者熟悉进程与内存管理,却对设备控制器、中断机制、DMA等概念缺乏系统认知,导致面对磁盘占用率过高、线程池阻塞等线上问题时无从下手。理解I/O结构,本质是理解操作系统如何弥合CPU与慢速设备之间的速度鸿沟。从程序查询、中断驱动到直接存储器访问(DMA),每一次演进都在减少CPU的无效等待;而缓冲、缓存、I/O软件分层则实现了设备无关性与高效数据通路。进一步地,阻塞、非阻塞、I/O多路复用与异步I/O模型,直接决定了高并发系统的设计选

weixin_29698641的博客 277

文件I/O概念

文件I/O(Input/Output),又称系统I/O或系统调用,是操作系统内核提供的一组API接口函数,用于应用程序与底层硬件(如磁盘、设备)之间的数据读写操作。核心特点:无缓冲机制:文件I/O不提供用户空间的缓冲,每次读写都直接与内核交互直接系统调用:通过操作系统内核完成,性能开销相对较大底层操作:提供最基础的读写能力,适合需要精细控制的场景文件描述符(File Descriptor,简称fd)是一个非负整数,是Linux/Unix系统中用于标识已打开文件的抽象概念。

weixin_47160515的博客 205

基础I/O

本文深入讲解Linux系统中"一切皆文件"的核心思想。首先对比了C语言文件接口(fopen/fwrite/fread)与系统文件I/O(open/write/read/close),指出C标准库本质上封装了系统调用。重点解析了文件描述符fd的管理机制:进程通过struct files_struct维护文件描述符表,每个打开的文件对应一个struct file对象,fd即为数组下标。文章详细阐述了重定向原理——通过dup2修改文件描述符表的指向,实现输入输出重定向(>、<、>>),并给出了在myshell中实

2302_81273171的博客 243

《深入理解计算机系统》系统级 I/O

系统级 I/O 是 Unix 编程的基石。文件描述符是 I/O 的核心句柄。短计数是正常现象,必须通过循环处理。内核数据结构(描述符表、打开文件表、V-node)解释了文件共享和重定向的原理。dup2是实现 Shell 重定向和管道的关键。理解带缓冲 I/O与系统调用 I/O的区别及适用场景。掌握这些内容后,你就具备了编写网络服务器和处理复杂文件操作的能力。

989
上一篇: TCP连接的关闭
下一篇: [Web Server](一)Tiny Web Server分析
Tanswer_
博客等级 码龄11年 231粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值