LINUX 高级IO操作
一 知识点非常重要
二 非阻塞的IO
系统调用: 低速系统调用,其他系统调用
低速系统调用的类别:
1)读网络设备,终端,管道等,暂时没有数据输入,则阻塞读操作
2)同上的写操作,但不能接收时,也阻塞写操作
3)等待某种条件的读写操作
4)加锁的文件的读写操作
5)某些ioctl操作
6)进程通信间的函数
通过文件描述符可以修改文件的状态
1)open 指定O_NONBLOCK状态
2)fcntl修改文件描述符状态为O_NONBLOCK
如果修改为非阻塞,无数据读,或写不进去会马上出错返回,read返回-1,errno值为EAGAIN
三 操作锁的总结
1.recording locking 其实是byte-range locking 记录(文件)锁
2 锁功能的历史
早期: flock 只能锁整个文件,不能锁文件部分
svr3: lockf 允许锁部分
posix: fcntl
3.fcntl的所有功能
复制现有描述符 F_DUPFD
获得或设置文件描述符标记 F_GETFD F_SETFD
获得或设置文件状态标志 F_GETFL F_SETFL 读写模式,阻塞模式,同步异步读写等
获得或设置异步IO所有权 F_GETOWN F_SETOWN
获得或设置记录锁(文件锁) F_GETLK F_SETLK F_SETLKW
4.fcntl记录锁(文件锁)
第三个参数指向数据结构 struct flock
a)多个进程锁规则是:只能多个读锁同时存在,不能再加写锁; 只有一个写锁存在,不能再加读锁;
b)单个进程锁规则是:多次锁操作,会将新锁替换以前的锁
c)如果多个锁的空间连续,系统就会合并到一个锁。否则拆分成多个锁
5.锁的继承和释放
a)进程终止的时候,它所建立的锁全部释放
b)关闭描述符时,则通过这一描述符引用的文件的所有锁都被释放
c)fork创建的子进程不继承父进程的锁
f)建议性锁与强制性锁
合作进程:使用所有函数都以相同方式处理锁的库的进程
g)强迫性锁 强制内核对每一个系统调用都进行文件锁的检查(排它锁)
强制性锁可以被程序ed避开
对一个文件打开其设置组ID位而关闭其组执行位就开启了强制性锁机制
h) 系统调用跟踪命令
solaris truss
freebsd和mac os X ktrace和kdump
linux strace
四 UNIX V 流streams机制
1)概念
流是在用户进程和设备驱动程序之间提供了一条全双工通路
需要时再细致研究
五 多个IO轮询
1)select
指定等待时间再返回,参数指定了可读可写及异常的文件描述符
select 支持最大文件描述符集合1024,
2)pselect
同上,但是时间跟细致,可以支持信号屏蔽
3)poll
每个数组元素是一个结构体pollfd,里面有期盼的文件描述符状态和实际的文件描述符状态
pollup后不可以写,但还可以继续读
pollin输入文件结束标志
4)epoll
六 异步IO
V中是信号SIGPOLL
ioctl 设置I_SETSIG,并建立信号处理程序
BSD中
SIGIO 异步IO信号
SIGURG 网络有带外数据
步骤如下:
1)sigaction建立信号处理程序
2)以命令F_SETOWN调用fcntl,设置进程id及进程组id
3)以F_SETFL调用fcntl设置O_ASYNC文件状态标志
1)缺点是: 每个进程只有一个信号,不能识别到多个文件描述符
七 readv和writev函数, readn和writen函数的知识点
1) readv及writev用于在一个函数中读写多个非连续缓冲区
减少系统的调用次数,优化时间
2)readn及writen
默认的read及write可能返回少于期待的数据量,通常他们不会返回失败,应该做判断并继续读写
readn及writen实现了这个多次调用满足指定字节数的条件
3)那如果是自定义封包解析的时候,这样写貌似有问题的哦!
typedef struct
{
unsigned id;
unsigned flag;
} io_type;
if (read(fd, buf, sizeof(io_type)) == sizeof(io_type))
//这里万一是2次read得到一个包,就球了!
八 存储映射IO
1) 关联映射
mmap(void* addr, size_t len, int prot, int flag, int fields, off_t off)
函数返回文件映射到的内存地址的起始位置
addr 指定内存的起始位置, 如果为0,则系统指定内存
fields关联到一个打开的文件
off指定文件内部开始映射的偏移位置
len映射的字节数
prot 映射区的操作权限,不能大于文件的最大权限
PROT_READ
PROT_WRITE
PROT_NONE 不可访问
PROT_EXEC
flag 影响存储区的属性
MAP_FIXED 返回值必须等于addr
MAP_SHARED 写内存直接写到文件
MAP_PRIVATE 对映射区的存储操作导致创建该映射文件的一个私有副本,以后的引用都关联到这个副本,而不是原来的文件
2) 映射到2个信号
SIGSEGV信号,表示进程访问不可用的存储区, 如果向只读的映射区写入数据则产生该信号
SIGBUS信号, 表示映射区对于的某个数据不存在了
3)fork后,子进程继承存储映射区,如果调用了exec就不再继承了
4)修改映射区的权限
mprotect
5)冲洗映射区的内容到文件
msync(void *, size_t len, int flags)
flags = MS_SYNC 等待写完成再返回
6)解决映射绑定
munmap
一 知识点非常重要
二 非阻塞的IO
系统调用: 低速系统调用,其他系统调用
低速系统调用的类别:
1)读网络设备,终端,管道等,暂时没有数据输入,则阻塞读操作
2)同上的写操作,但不能接收时,也阻塞写操作
3)等待某种条件的读写操作
4)加锁的文件的读写操作
5)某些ioctl操作
6)进程通信间的函数
通过文件描述符可以修改文件的状态
1)open 指定O_NONBLOCK状态
2)fcntl修改文件描述符状态为O_NONBLOCK
如果修改为非阻塞,无数据读,或写不进去会马上出错返回,read返回-1,errno值为EAGAIN
三 操作锁的总结
1.recording locking 其实是byte-range locking 记录(文件)锁
2 锁功能的历史
早期: flock 只能锁整个文件,不能锁文件部分
svr3: lockf 允许锁部分
posix: fcntl
3.fcntl的所有功能
复制现有描述符 F_DUPFD
获得或设置文件描述符标记 F_GETFD F_SETFD
获得或设置文件状态标志 F_GETFL F_SETFL 读写模式,阻塞模式,同步异步读写等
获得或设置异步IO所有权 F_GETOWN F_SETOWN
获得或设置记录锁(文件锁) F_GETLK F_SETLK F_SETLKW
4.fcntl记录锁(文件锁)
第三个参数指向数据结构 struct flock
a)多个进程锁规则是:只能多个读锁同时存在,不能再加写锁; 只有一个写锁存在,不能再加读锁;
b)单个进程锁规则是:多次锁操作,会将新锁替换以前的锁
c)如果多个锁的空间连续,系统就会合并到一个锁。否则拆分成多个锁
5.锁的继承和释放
a)进程终止的时候,它所建立的锁全部释放
b)关闭描述符时,则通过这一描述符引用的文件的所有锁都被释放
c)fork创建的子进程不继承父进程的锁
d)如果没对文件描述符设置close-on-exec,那么exec执行后,继承原程序的锁,否则会将原来的锁释放掉
如果利用F_SETFD设置了FD_CLOEXEC标识,
那么exec后会将关闭文件描述符,这样避免文件描述符被多个进程使用
fcntl(fd, F_SETFD, FD_CLOEXEC); // 这里设置为FD_CLOEXEC表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程, 如果设置为fcntl(fd, F_SETFD, 0);那么本fd将保持打开状态复制到exec创建的新进程中
f)建议性锁与强制性锁
合作进程:使用所有函数都以相同方式处理锁的库的进程
g)强迫性锁 强制内核对每一个系统调用都进行文件锁的检查(排它锁)
强制性锁可以被程序ed避开
对一个文件打开其设置组ID位而关闭其组执行位就开启了强制性锁机制
h) 系统调用跟踪命令
solaris truss
freebsd和mac os X ktrace和kdump
linux strace
四 UNIX V 流streams机制
1)概念
流是在用户进程和设备驱动程序之间提供了一条全双工通路
需要时再细致研究
五 多个IO轮询
1)select
指定等待时间再返回,参数指定了可读可写及异常的文件描述符
select 支持最大文件描述符集合1024,
2)pselect
同上,但是时间跟细致,可以支持信号屏蔽
3)poll
每个数组元素是一个结构体pollfd,里面有期盼的文件描述符状态和实际的文件描述符状态
pollup后不可以写,但还可以继续读
pollin输入文件结束标志
4)epoll
六 异步IO
V中是信号SIGPOLL
ioctl 设置I_SETSIG,并建立信号处理程序
BSD中
SIGIO 异步IO信号
SIGURG 网络有带外数据
步骤如下:
1)sigaction建立信号处理程序
2)以命令F_SETOWN调用fcntl,设置进程id及进程组id
3)以F_SETFL调用fcntl设置O_ASYNC文件状态标志
1)缺点是: 每个进程只有一个信号,不能识别到多个文件描述符
七 readv和writev函数, readn和writen函数的知识点
1) readv及writev用于在一个函数中读写多个非连续缓冲区
减少系统的调用次数,优化时间
2)readn及writen
默认的read及write可能返回少于期待的数据量,通常他们不会返回失败,应该做判断并继续读写
readn及writen实现了这个多次调用满足指定字节数的条件
3)那如果是自定义封包解析的时候,这样写貌似有问题的哦!
typedef struct
{
unsigned id;
unsigned flag;
} io_type;
if (read(fd, buf, sizeof(io_type)) == sizeof(io_type))
//这里万一是2次read得到一个包,就球了!
八 存储映射IO
1) 关联映射
mmap(void* addr, size_t len, int prot, int flag, int fields, off_t off)
函数返回文件映射到的内存地址的起始位置
addr 指定内存的起始位置, 如果为0,则系统指定内存
fields关联到一个打开的文件
off指定文件内部开始映射的偏移位置
len映射的字节数
prot 映射区的操作权限,不能大于文件的最大权限
PROT_READ
PROT_WRITE
PROT_NONE 不可访问
PROT_EXEC
flag 影响存储区的属性
MAP_FIXED 返回值必须等于addr
MAP_SHARED 写内存直接写到文件
MAP_PRIVATE 对映射区的存储操作导致创建该映射文件的一个私有副本,以后的引用都关联到这个副本,而不是原来的文件
2) 映射到2个信号
SIGSEGV信号,表示进程访问不可用的存储区, 如果向只读的映射区写入数据则产生该信号
SIGBUS信号, 表示映射区对于的某个数据不存在了
3)fork后,子进程继承存储映射区,如果调用了exec就不再继承了
4)修改映射区的权限
mprotect
5)冲洗映射区的内容到文件
msync(void *, size_t len, int flags)
flags = MS_SYNC 等待写完成再返回
6)解决映射绑定
munmap