首页 > 编程语言 >CSAPP 系统级I/O和网络编程

CSAPP 系统级I/O和网络编程

时间:2024-11-20 16:20:06浏览次数:1  
标签:文件 CSAPP read void 编程 网络 rio 缓冲区 size

image

from pixiv

系统级I/O

文件

所有的 I/O 设备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式,允许 Linux 内核引出一个简单、低级的应用接口,称为 Unix I/O

Linux 文件有主要有三种类型:

  • 普通文件
  • 目录
  • 网络socket(套接字)

当然还有命名通道(named pipe)、 符号链接(symbolic link),以及字符和块设备(character and block device)等类型先不予讨论。

改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置 k,初始为 0。这个文件位置是从文件开头起始的字节偏移量。应用程序能够通过执行 seek 操作,显式地设置文件的当前位置为 k。

对于这种行为,对于普通文件是有效的,对于如socket、目录等类型文件无效。

当我们调用open函数两次打开同一个普通文件foo.txt,那么这两次打开均会从文件起始位置开始,然后记录file_offset, read和write的读写操作均会改变file_offset。

且两次open返回的是不同的文件描述符。有点像CSAPP书上下图:
image

关于文件描述符,文件表,v-node表在fork后,重定向后如何均有提及。

RIO

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t n);
// 返回:若成功则为读的字节数,若 EOF 则为0,若出错为 -1。

ssize_t write(int fd, const void *buf, size_t n);
// 返回:若成功则为写的字节数,若出错则为 -1。

在 x86-64 系统中,size_t 被定义为 unsigned long,而 ssize_t(有符号的大小)被定义为 long。
read 函数返回一个有符号的大小,而不是一个无符号大小,这是因为出错时它必须返回 -1。

RIO(Robust I/O,健壮的 I/O)包,其实现的思路和目的为:

  • 处理不足值:在某些情况下,read 和 write 传送的字节比应用程序要求的要少。这些不足值(short count)不表示有错误。出现这样情况的原因有:

    • 读时遇到 EOF。这个时候说明确实没有内容可以读了,直接返回。
    • 从终端读文本行。这个时候每个 read 函数将一次传送一个文本行。
    • 读和写网络套接字(socket)。那么内部缓冲约束和较长的网络延迟会引起 read 和 write 返回不足值。这个时候必须通过反复调用 read 和 write 处理不足值,直到所有需要的字节都传送完毕。
  • 实现无缓冲的输入输出函数:rio_readnrio_writen。这些函数直接在内存和文件之间传送数据,没有应用级缓冲。它们对将二进制数据读写到网络和从网络读写二进制数据尤其有用。

ssize_t rio_readn(int fd, void *usrbuf, size_t n);
ssize_t rio_writen(int fd, void *usrbuf, size_t n);
// 返回:若成功则为传送的字节数,若 EOF 则为 0(只对 rio_readn 而言),若出错则为 -1。
  • 实现带缓冲的输入函数。这些函数允许你高效地从文件中读取文本行和二进制数据。
#define RIO_BUFSIZE 8192
typedef struct {
    int rio_fd;                /* Descriptor for this internal buf */
    int rio_cnt;               /* Unread bytes in internal buf */
    char *rio_bufptr;          /* Next unread byte in internal buf */
    char rio_buf[RIO_BUFSIZE]; /* Internal buffer */
} rio_t;
//初始化rp指针
void rio_readinitb(rio_t *rp, int fd);
// 返回:无。

//对于文本数据,rio_readlineb,它从一个内部读缓冲区复制一个文本行,当缓冲区变空时,会自动地调用 read 重新填满缓冲区。
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
//对于既包含文本行也包含二进制数据的文件,提供了一个 rio_readn 带缓冲区的版本,叫做 rio_readnb,它从和 rio_readlineb 一样的读缓冲区中传送原始字节。
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
// 返回:若成功则为读的字节数,若 EOF 则为 0,若出错则为 -1。

手动实现一下

标准I/O

C 语言定义了一组高级输入输出函数,称为标准 I/O 库,为程序员提供了 Unix I/O 的较高级别的替代。

标准 I/O 库将一个打开的文件模型化为一个流。对于程序员而言,一个流就是一个指向 FILE 类型的结构的指针。

类型为 FILE 的流是对文件描述符和流缓冲区的抽象。流缓冲区的目的和 RIO 读缓冲区的一样:就是使开销较高的 Linux I/O 系统调用的数量尽可能得小。

#include <stdio.h>
extern FILE *stdin;    /* Standard input (descriptor 0) */
extern FILE *stdout;   /* Standard output (descriptor 1) */
extern FILE *stderr;   /* Standard error (descriptor 2) */

image

from csapp
  • G1:只要有可能就使用标准 I/O。

  • G2:不要使用 scanf 或 rio_readlineb 来读二进制文件。
    因为scanf和rio_readlineb中均有通过换行符或终止符来判断是否需要'截断'的操作,二进制文件可能散布着很多 Oxa 字节,而这些字节又与终止文本行无关。

  • G3:对网络套接字的 I/O 使用 RIO 函数,而不要使用标准I/O。
    具体理由和标准I/O内部实现有关,比如标准I/O需要使用 Unix I/O lseek 函数来重置当前的文件位置,但是socket没有文件位置这个概念。

标签:文件,CSAPP,read,void,编程,网络,rio,缓冲区,size
From: https://www.cnblogs.com/cilinmengye/p/18558616

相关文章

  • 【网络安全】1+X应急响应(初级)最详细,最全,看完包你通过
    +X应急响应(重点)应急响应准备⼯作:应急响应概念:⽹络安全应急响应概念:应急响应体系:应急响应过程:应急准备阶段主要⼯作:⻛险评估与改进:应急响应预案制定流程:应急响应流程:应急响应保障措施:Windows系统排查:Linux系统排查:系统备份:备份概述:备份种类:系统加固:数据库加固......
  • 神经网络(系统性学习二):单层神经网络(感知机)
    此前篇章:神经网络中常用的激活函数神经网络(系统性学习一):入门篇单层神经网络(又叫感知机)单层网络是最简单的全连接神经网络,它仅有输入层和输出层,没有隐藏层。即,网络的所有输入直接影响到输出。结构:输入层→输出层特点:只适用于线性可分问题。即,单层网络只能学习并解决......
  • 分别用else if语句和switch语名完成下列编程题输入一个整数月份(1到12),输出对应的季度(第
    用elseif语句:#include<stdio.h>intmain(){ intm; scanf("%d",&m); if(m>=1&&m<=12){ if(m>=1&&m<3){  printf("第一季度\n"); }elseif(m>=4&&m<=6){  prin......
  • JavaScript函数式编程之组合函数
    1.Reduce过程是一个函数pipeline,参数组合+函数pipelineJavaScript函数式编程实践指南-修言-掘金小册constarr=[1,2,3]constinitialValue=0constadd=(previousValue,currentValue)=>previousValue+currentValue;//执行顺序0+1+2+3constsumAr......
  • 蓝队基础之网络七层杀伤链(完整版)
    目录企业网络架构高层管理CIO(首席信息官)CTO(首席技术官)IT管理中央系统自带设备(BYOD)影子IT中央技术团队客户服务团队基础设施团队数据库管理团队技术团队安全部门CISO(首席信息安全官)信息安全管理成熟度模型(ISM3)安全职能型企业网络分区DMZ(非军事区)蜜罐代理V......
  • 第二次网络渗透测试课程实验--使用Ping指令测试网络连通性
    首先,我们需要知道目的计算机的ip,才能执行ping指令。那么如何得到设备的ip呢?在本机,可以调出控制台面板,然后输入ipconfig指令,即可获得本机的ip地址、默认网关、子网掩码等信息。在虚拟机中,打开控制台面板,然后输入ifconfig指令即可得到虚拟机的ip、MAC地址等信息。得到目的设备......
  • 2024年入职/转行网络安全,该如何规划?_网络安全职业规划
     前言前段时间,知名机构麦可思研究院发布了 《2022年中国本科生就业报告》,其中详细列出近五年的本科绿牌专业,其中,信息安全位列第一。网络安全前景对于网络安全的发展与就业前景,想必无需我多言,作为当下应届生收入较高的专业之一,网络安全同样也在转行领域中占据热门位置,主要......
  • 2024最新网络安全自学路线,内容涵盖3-5年技能提升
     01什么是网络安全网络安全可以基于攻击和防御视角来分类,我们经常听到的“红队”、“渗透测试”等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面性,例如Web安全技术,既有Web渗透,也......
  • 入门网络安全工程师要学习哪些内容(详细教程)
    ......
  • TCP/UDP套接字基础编程及拓展
    一、环境1.1客户端:windows宿主机1.2服务器端:Linux虚拟机1.3注意事项测试套接字编程通信时,先确保C/S能互相ping通,且双方主机防火墙允许目的端口号为“创建的端口号”的数据包通过。二、代码2.1UDP套接字编程2.1.1UDPClient.pyfromsocketimport*#导入套接字......