Linux高性能服务器编程---高级I/O函数

来源:互联网 发布:舒适达抗敏感牙膏 知乎 编辑:程序博客网 时间:2024/05/17 05:57

【摘自《linux高性能服务器编程》】

管道容量默认大小是65536字节,可以使用fcntl函数来修改管道容量。

Socket的基础API中有一个socketpair函数,能够方便的创建双向管道。

#include<sys/types.h>

#include<sys/socket.h>

Int socketpair(int domain, int type,int protocol,int fd[2]);

Domain只能使用UNIX本地域协议族AF_UNIX,仅能在本地使用这个双向管道。


Pipe函数用于创建一个管道

#include<unistd.h>

Int pipe(int fd[2]);

 

dup函数和dup2函数

#include<unistd.h>

Int dup(int file_descriptor);

Int dup2(int file_descriptor_one ,int file_descriptor_two);

dup函数创建一个新的文件描述符,该新文件描述符和原有文件描述符file_descriptor指向相同的文件,管道或者网络连接。并且dup返回文件描述符总是取得系统当前可用最小的整数值。dup2dup类似,知识返回第一个不小于file_descriptor_two的整数值。

dupdup2创建文件描述符不继承原文件描述符的属性,比如close_on_exec non_blocking等。

 

readvwritev函数

readv函数将数据从文件描述符读到分散的内存块中,即分散读;writev函数则将多块分散的内存数据一并读入文件描述符中,即集中写。

#include<sys/uio.h>

ssize_t readv(int fd, const struct iovec* vector, int count);

ssize_t writev(int fd, const struct iovec* vector, int count);

fd参数是被操作的目标文件描述符。Vector参数的类型是iovec结构数组。

 

Sendfile函数

Sendfile函数在两个文件描述符之间直接传递数据,从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,这被称为零拷贝。

#include<sys/sendifle.h>

ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);

in_fd必须是一个支持类似mmap函数的文件描述符,即它必须指向 真实的文件,不能是socket和管道;而out_fd则必须是一个socket。由此sendfile几乎是专门为网络上传输文件而设计的。

 

mmap函数和munmap函数

mmap用于申请一段内存空间。用于进程间通信的共享或将文件映射到其中。Munmap函数则释放由mmap创建的这段内存空间。

#include<sys/mman.h>

void *mmap(void *start, size_t length,int prot, int flags, int fd, off_t offset);

Int munmap(void *start, size_t length);

Start参数允许用于使用特定的内存起始地址,如果设置为NULL系统自动分配一个地址。Length参数指定内存段的长度。Prot参数用来设置内存段的访问权限。取以下几个值的按位或:

PROT_READ,内存段可读。PROT_WRITE,内存段可写。PROT_EXEC,内存段可执行。PROT_NONE,内存段不能被访问。

Flags参数用于控制内存修改后的程序行为。按位或且与MAP_PRIVATE是互斥的不能同时指定。

MAP_SHARED,在进程间共享这段内存,对该内存段的修改将反映到被映射的文件中,它提供了进程间共享内存的POSIX方法。

MAP_PRIVATE,内存段为调用进程所私有,对该内存段的修改不会反映到被映射的文件中。

MAP_ANONYMOUS,这段内存不是从文件映射而来的,其内容被初始化为全为0,这种情况下,mmaps函数的最后两个参数将被忽略。

MAP_FIXED,内存段必须位于start参数指定的地址处。Start必须是内存页面大小的整数倍。

MAP_HUGETLB,按照“大内存页面”来分配内存空间。“大内存页面”的大小可通过、proc/meminfo文件来查看。

Fd参数是被映射文件对应的文件描述符。它一般通过open系统调用获得。Mmap成功时返回目标内存区域的指针,失败返回MAP_FAILED并设置errno;

 

SPLICE函数

Splice函数用于在两个文件描述符之间移动数据,也是零拷贝操作。

#include<fcntl.h>

Ssize_t splice(int fd_in, loff_t* off_in ,int fd_out, loff_t* off_out, size_t len, unsigned int flags);

Fd_in 参数是待输入数据文件描述符。如果fd_in是一个管道文件描述符,则off_in必须设置为NULL

Flags参数则控制数据如何移动,按位或。

SPLICE_F_MOVE,如果适合的话,按整页内存移动数据。这只是给内核的一个提示。不过,因为它的实现存在BUG,所以自内核2.6.21开始,它实际上没有任何效果。

SPLICE_F_NONBLOCK,非阻塞的splice操作,但实际效果还会受文件描述符本身的阻塞状态影响。

SPLICE_F_MORE,给内核一个提示;后续的splice调用将读取更多数据。

SPLICE_F_GIFT,对splice没有效果。

使用splice函数时,fd_infd_out必须至少有一个是管道文件描述符。Splice函数调用成功时返回移动字节的数量。

Errno

EBADF,参数所指文件描述符有错。

EINVAL,目标文件系统不支持splice,或者目标文件以追加方式打开,或者两个文件描述符都不是管道那文件描述符,或者某个offset参数被用于不支持随机访问的设备。

ENOMEM,内存不够。

ESPIPE,参数fd_in(或fd_out)是管道文件描述符,而off_in(off_out)不为NULL

 

Tee函数

Tee函数在两个管道文件描述符之间复制数据,也是零拷贝操作。它不消耗数据,因此源文件描述符上的数据仍然可以用于后续的读操作。

#include<fcntl.h>

ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

该函数的参数的含义与splice相同。

 

Fcntl函数

Fcntl函数,提供了对文件描述符的各种控制操作。另外一个ioctl是控制文件描述符属性和行为的系统调用。而且ioctlfcntl能够执行更多的控制。但是对于控制文件描述符常用的属性和行为,fcntl函数时由POSIX规范制定的首选方法。

#include<fcntl.h>

Int fcntl(int fd, int cmd, ...);

Fd参数是被操作的文件描述符,cmd参数指定执行何种类型的操作。根据操作类型的不同,该函数可能还需要第三个可选参数argFcntl函数支持的常用操作及其参数。

复制文件描述符 F_DUPFD,创建一个新的文件描述符,其值大于或等于arg  long 新创建的文件描述符。

                             F_DUPFD_CLOSEEXEC,与上面相似,但是创建同时,设置其close_on_exec标志。        Long 新创建的文件描述符的值。

获取和设置文件描述符的标志。 F_GETFD 获取fd的标志,比如close_on_exec标志  fd标志。

                              F_SETFD 设置fd的标志   long 0


获取和设置文件描述符的状态标志

                              F_GETFL 获取fd状态标志,这些标志包括可由open系统调用设置的标志(O_APPEND,O_CREAT等)和访问模式(O_RDONLY,O_WRONLYO_RDWR)   void fd的状态标志。

                              F_SETFL 设置fd的状态标志,但部分标志是不能被修改的(比如访问模式标志) long  0

 

管理信号   F_GETOWN  获得SIGIOSIGURG信号的宿主进程的PID或进程组的组ID 无 信号的宿主进程的PID或进程组的组ID

                  F_SETOWN 设定SIGIOSIGURG信号的宿主进程的PID或者进程组的组ID long o

                  F_GETSIG 获取当应用程序被通知fd可读可写时,是哪个信号通知该事件。 无 信号值 ,0标志SIGIO

                  F_SETSIG 设置当fd可读可写时,系统应该触发哪个信号来通知应用程序 ,long 0 

 

操作管道容量  F_SETPIPE_SZ设置由fd指定的管道容量,/proc/sys/fs/pipe-size-max内核参数制定了fcntl能设置的管道容量的上限。  Long 0;

                          F_GETPIPE_SZ 获取由fd指定的管道容量 无 管道容量

在网络编程中,fcntl函数通常用来将一个文件描述符设置为非阻塞的

 Int setnonblocking(int fd)

{

   Int old_option= fcntl(fd, F_GETFL);

   Int new_option = old_option | O_NONBLOCK;//设置非阻塞标志。

Fcntl(fd,F_SETFL,new_option);

Return old_option;

}

此外,SIGIOSIGURG这两个信号与其他Linux信号不同,他们必须与某个文件描述符相关联方可使用;当被关联的文件描述符可读或可写时,系统将触发SIGIO信号;当被关联的文件描述符(而且必须是一个socket)上有外带数据可读时,系统将触发SIGURG信号。将信号和文件描述符关联的方法,就是使用fcntl函数为目标文件描述符指定宿主进程或进程组,那么被指定的宿主进程或进程组将捕获这两个信号。使用SIGIO时,还需要利用fcntl设置其O_ASYNC标志(异步I/O标志,不过SIGIO信号模型并非真正意义上的异步I/O模型。

0 0
原创粉丝点击