English | 中文版
[TOC]
采用特定的指令形式
在CPU与I/O设备之间存在I/O通道(I/O Channel),其主要目的是为了建立独立的I/O操作,不仅使数据的传送能独立于CPU,而且也希望有关对I/O操作的组织,管理及其结束处理尽量独立,以保证CPU有更多的时间去进行数据处理。
只要字节多路通道扫描每个子通道的速率足够快,而连接到子通道上的设备的速率又不是太高(不适用于高速设备),便不致丢失信息。
TODO
TODO
| 操作 | fcntl | ioctl | 路由套接字 | POSIX |
|---|---|---|---|---|
设置套接字为非阻塞式I/O型 |
F_SETFL, O_NONBLOCK | FIONBIO | fcntl | |
设置套接字为信号驱动式I/O型 |
F_SETFL, O_ASYNC | FIOASYNC | fcntl | |
| 设置套接字属主 | F_SETOWN | SIOCSPGRP或FIOSETOWN | fcntl | |
| 获取套接字属主 | F_GETOWN | SIOCGPGRP或FIOGETOWN | fcntl | |
| 获取套接字接收缓冲区中的字节数 | FIONREAD | |||
| 测试套接字是否处于带外标志 | SIOCATMARK | sockatmark | ||
| 获取接口列表 | SIOCGIFCONF | sysctl | ||
| 接口操作 | SIOC[GS]IFxxx |
|||
| ARP告诉缓存操作 | SIOCxARP | RTM_xxx | ||
| 路由表操作 | SIOCxxxRT | RTM_xxx |
fcntl函数提供了与网络编程相关的如下特性:
- 非阻塞式
I/O:通过使用F_SETFL命令设置O_NONBLOCK文件状态标志,我们可以把一个套接字设置为非阻塞型 - 信号驱动式
I/O:通过使用F_SETFL命令设置O_ASYNC文件状态标志,我们可以把一个套接字设置成一旦其状态发生变化,内核就产生了一个SIGIO信号。 - F_SETOWN:命令允许我们指定用于接收SIGIO和SIGURG信号的套接字属主。其中SIGIO信号是套接字被设置为信号驱动式I/O型后产生的,SIGURG信号是在新的带外数据到达套接字时产生的。F_GETOWN命令返回套接字的当前属主。
大多数文件系统为改善性能都采用某种预读(read ahead)技术,当检测到正进行顺序读取时,系统就试图读入比应用所要求的更多数据,并假想应用很快就会读这些数据。
delayed write,传统的UNIX系统实现在内核中设有缓冲区高速缓存或页高速缓存,大多数磁盘I/O都通过缓冲区进行。当我们向文件写入数据时,内核通常先将数据复制到缓冲区中,然后排入队列,晚些时候再写入磁盘
time-of-check-to-time-of-use,如果有两个基于文件的函数调用,其中第二个调用依赖于第一个调用的结果,那么程序是脆弱的;因为两个调用并不是原子操作,在两个函数调用之间文件可能改变了,这样也就造成了第一个调用的结果就不在有效,使得程序最终的结果是错误的。
#include <unistd.h>
int access(const char *pathname, int mode);
int faccessat(int fd, const char *pathname, int mode, int flag);-
fd文件描述符 -
pathname绝对/相对路径 -
mode模式mode 说明 R_OK 测试读权限 W_OK 测试写权限 X_OK 测试执行权限 -
flags标志 -
返回值- 成功:0
- 失败:-1
进行访问权限测试。
#include<fcntl.h>
int fcntl(int fd, int cmd, ...);fd文件描述符cmd命令F_DUPFD复制文件描述符,新文件描述符作为函数值返回。F_DUPFD_CLOEXEC复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符标志的值,返回新文件描述符。F_GETFD对应于fd的文件描述符标志作为函数值返回。F_SETFD对于fd设置文件描述符标志。F_GETFL对应于fd的文件状态标志作为函数值返回。F_SETFL将文件状态标志设置为第3个参数的值(取为整型值),此参数可以为:O_APPEND,O_NONBLOCK,O_SYNC,O_DSYNC,O_RSYNC,O_FSYNC,O_ASYNC。F_GETOWN获取当前接受SIGIO和SIGURG信号的进程ID或进程组ID。F_SETOWN设置接收SIGIO和SIGURG信号的进程ID或进程组ID。
- 返回值
- 成功:取决于cmd的值
- 失败:-1
fcntl有5种功能:
- 复制一个已有的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)
- 获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD)
- 获取/设置文件状态标志(cmd=F_DETFL或F_SETFL)
- 获取/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)
- 获取/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)
对于fcntl的文件状态标志:
| 文件状态标志 | 说明 |
|---|---|
| O_RDONLY | 只读打开 |
| O_WRONLY | 只写打开 |
| O_RDWR | 读,写打开 |
| O_EXEC | 只执行打开 |
| O_SEARCH | 只搜索打开目录 |
| O_APPEND | 追加写 |
| O_NONBLOCK | 非阻塞模式 |
| O_SYNC | 等待写完成(数据和属性) |
| O_DSYNC | 等待写完成(仅数据) |
| O_RSYNC | 同步读和写 |
| O_FSYNC | 等待写完成(仅FreeBSD和Mac OS X) |
| O_ASYNC | 异步I/O(仅FreeBSD和Mac OS X) |
#include <fcntl>
int open(const char* path, int oflag, ...);
int openat(int fd, const char* path, int oflag, ...);-
fd文件描述符- 如果path是绝对路径名,fd被忽略,open=openat
- 如果path是相对路径名,fd参数指出了相对路径在文件系统中的开始地址
- 如果path是相对路径名且fd参数具有特殊值AT_FDCWD,路径名在当前工作目录中获取
-
path要打开或创建文件的名字 -
oflag选项必选一个的操作选项:
O_RDONLY只读打开O_WRONLY只写打开O_RDWR读写打开O_EXEC只执行打开O_SEARCH只搜索打开(应用于目录,在目录打开时验证它的搜索权限)
可选的操作选项:
O_APPEND每次写时都追加到文件的尾端O_CLOEXEC把FD_CLOEXEC常量设置为文件描述符标志O_CREAT若此文件不存在则创建它O_DIRECTORY如果path引用的不是目录,则出错O_EXCL如果同时指定了O_CREAT,而文件已存在,则出错O_NOCTTY如果path引用的是终端设备,则不将该设备分配作为此进程的控制终端O_NOFOLLOW如果path引用的是一个符号链接,则出错O_NONBLOCK如果path引用的是一个FIFO,一个块特殊文件或一个字符特殊文件,则此选项为文件的本次打开操作和后续I/O操作设置非阻塞方式O_SYNC使每次write等待物理I/O操作完成,包括由该write操作引起的文件属性更新所需的I/O
-
返回值
- 成功:文件描述符
- 失败:-1
打开文件/目录。
#include <fcntl.h>
int create(const char* path, mode_t mode);path路径mode创建模式- 返回值
- 成功:只写文件描述符
- 失败:-1
创建一个新文件,等效于:open(path, O_RDWR|O_CREAT|O_TRUNC, mode);
#include <unistd.h>
int close(int fd);fd文件描述符- 返回值
- 成功:0
- 失败:-1
关闭文件
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);fd文件描述符offset偏移量whence位置SEEK_SET将文件的偏移量设置为距文件开始处offset个字节SEEK_CUR将文件偏移量设置为其当前值加offset,offset可正可负SEEK_END将文件的偏移量设置为文件长度加offset,offset可正可负
- 返回值
- 成功:新的文件偏移量
- 失败:-1
为一个打开的文件设置偏移量
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);fd文件描述符buf缓冲区nbytes要求读的长度- 返回值
- 成功:读到的字节数
- 已到文件尾:0
- 失败:-1
从文件中读数据
以下这些情况会导致实际读到的字节数少于要求读的字节数:
- 读普通文件时,在读到要求字节数之前已到达了文件尾
- 从终端设备读时,网络中的缓冲机制可能造成返回值小于所要求读的字节数
- 从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数
- 当从某些面向记录的设备(如磁带)读时,一次最多返回一个记录
- 当一信号造成中断,而已经读了部分数据量时
#include <unistd.h>
ssize_t write(int fd, const void* buf, size_t nbytes);fd文件描述符buf缓冲区nbytes要写入的字节数- 返回值
- 成功:已写的字节数(==要写入的字节数)
- 失败:-1或已写的字节数(<要写入的字节数)
写数据到文件
#include <unistd.h>
int dup(int fd);
int dup2(int fd, int fd2);fd待复制的文件描述符fd2用来指定返回的文件描述符的值- 如果
fd2已经打开,先关闭它 - 如果
fd等于fd2,则dup2返回fd2而不关闭它 - 其它情况,
fd2的FD_CLOEXEC文件描述符标志被清除,fd2在进程调用exec时是打开状态
- 如果
- 返回值
- 成功:新的文件描述符
- 失败:-1
复制一个现有的文件描述符
例,返回的新描述符与参数fd共性同一个文件表项时的结构:
#include <unistd.h>
void sync(void);sync只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等实际写磁盘操作结束。
#include <unistd.h>
int fsync(int fd);fd文件描述符- 返回值
- 成功:0
- 失败:-1
fsync只对由文件描述符fd指定的一个文件起作用,并且等待写磁盘操作结束才返回。
#include <unistd.h>
int fdatasync(int fd);fd文件描述符- 返回值
- 成功:0
- 失败:-1
fdatasync类似于fsync,但它只影响文件的数据部分。而除数据外,fsync还会同步更新文件的属性。
#include <unistd.h>
#include <sys/ioctl.h>
int ioctl(int fd, int request, ...);fd文件描述符request- 返回值
- 成功:其它值
- 失败:-1
UNIX系统实现用它进行很多杂项设备操作,有些实现甚至将它扩展到用于普通文件。
FreeBSD中通用的ioctl操作:
| 类别 | 常量名 | 头文件 | ioctl数 |
|---|---|---|---|
| 盘标号 | DIOxxx | <sys/disklable.h> |
4 |
| 文件I/O | FIOxxx | <sys/filio.h> |
14 |
| 磁带I/O | MTIOxxx | <sys/mtio.h> |
11 |
| 套接字I/O | SIOxxx | <sys/sockio.h> |
73 |
| 终端I/O | TIOxxx | <sys/ttycom.h> |
43 |
[1] UNIX环境高级编程.第3版.第三章 文件I/O





