pipe函数

pipe函数可用于创建一个管道,以实现进程间通信。

#include<unistd.h>/* Create a one-way communication channel (pipe).If successful, two file descriptors are stored in PIPEDES;bytes written on PIPEDES[1] can be read from PIPEDES[0].Returns 0 if successful, -1 if not.  */
extern int pipe (int __pipedes[2]) __THROW __wur;

pipe函数的参数是-一个包含两个int 型整数的数组指针。该函数成功时返回0,并将一对打开的文件描述符值填入其参数指向的数组。如果失败,则返回-1并设置errmo。

通过pipe函数创建的这两个文件描述符fd[0]和fd[]分别构成管道的两端,往fd[1]写人的数据可以从fd[0] 读出。并且,fd[0] 只能用于从管道读出数据,fd[1] 则只能用于往管道写入数据,而不能反过来使用。如果要实现双向的数据传输,就应该使用两个管道。默认情况下,这一对文件描述符都是阻塞的。此时如果我们用read系统调用来读取一个空的管道,则read将被阻塞,直到管道内有数据可读;如果我们用write系统调用来往一个满的管道中写人数据,则write亦将被阻塞,直到管道有足够多的空闲空间可用。但如果应用程序将fd[0]和fd[1]都设置为非阻塞的,则read和write会有不同的行为。关于阻塞和非阻塞的讨论。如果管道的写端文件描述符fd[1]的引用计数减少至0,即没有任何进程需要往管道中写人数据,则针对该管道的读端文件描述符fd[0]的read操作将返回0,即读取到了文件结束标记(End Of File,EOF); 反之,如果管道的读端文件描述符fd[0]的引用计数减少至0,即没有任何进程需要从管道读取数据,则针对该管道的写端文件描述符fd[1]的write操作将失败,并引发SIGPIPE信号。

管道内部传输的数据是字节流,这和TCP字节流的概念相同。但二者又有细微的区别。应用层程序能往一个TCP连接中写人多少字节的数据,取决于对方的接收通告窗口的大小和本端的拥塞窗口的大小。而管道本身拥有一个容量限制,它规定如果应用程序不将数据从管道读走的话,该管道最多能被写人多少字节的数据。自Linux 2.6.11内核起,管道容量的大小默认是65536字节。我们可以使用fentl函数来修改管道容量。

此外,socket 的基础API中有-一个socketpair函数。它能够方便地创建双向管道。其定义如下:

#include<sys/types.h>
#include<sys/socket.h>/* Create two new sockets, of type TYPE in domain DOMAIN and usingprotocol PROTOCOL, which are connected to each other, and put filedescriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,one will be chosen automatically.  Returns 0 on success, -1 for errors.  */
extern int socketpair (int __domain, int __type, int __protocol,int __fds[2]) __THROW;

socketpair前三个参数的含义与socket系统调用的三个参数完全相同,但domain只能使用UNIX本地域协议族AF_ _UNIX,因为我们仅能在本地使用这个双向管道。最后一个参数则和pipe系统调用的参数一样,只不过socketpair创建的这对文件描述符都是既可读又可写的。socketpair 成功时返回0,失败时返回-1并设置ermno。

dup函数和dup2函数

#include<unistd.h>/* Duplicate FD, returning a new file descriptor on the same file.  */
extern int dup (int __fd) __THROW __wur;/* Duplicate FD to FD2, closing FD2 and making it open on the same file.  */
extern int dup2 (int __fd, int __fd2) __THROW;

dup函数创建一个新的文件描述符,该新文件描述符和原有文件描述符file_descriptor 指向相同的文件、管道或者网络连接。并且dup返回的文件描述符总是取系统当前可用的最小整数值。dup2 和dup类似,不过它将返回第一个不小于file_descriptor_two 的整数值。dup 和dup2系统调用失败时返回-1并设置errno。

readv函数和writev函数

readv函数将数据从文件描述符读到分散的内存块中,即分散读; writev 函数则将多块分散的内存数据一并写人文件描述符中,即集中写。它们的定义如下:

#include<sys/uio.h>/* Read data from file descriptor FD, and put the result in thebuffers described by IOVEC, which is a vector of COUNT 'struct iovec's.The buffers are filled in the order specified.Operates just like 'read' (see <unistd.h>) except that data areput in IOVEC instead of a contiguous buffer.This function is a cancellation point and therefore not marked with__THROW.  */
extern ssize_t readv (int __fd, const struct iovec *__iovec, int __count)__wur;/* Write data pointed by the buffers described by IOVEC, whichis a vector of COUNT 'struct iovec's, to file descriptor FD.The data is written in the order specified.Operates just like 'write' (see <unistd.h>) except that the dataare taken from IOVEC instead of a contiguous buffer.This function is a cancellation point and therefore not marked with__THROW.  */
extern ssize_t writev (int __fd, const struct iovec *__iovec, int __count)__wur;

fd参数是被操作的目标文件描述符。vector 参数的类型是iovec结构数组。该结构体描述一块内存区。 count 参数是vector数组的长度,即有多少块内存数据需要从fd读出或写到fd。readv和writev在成功时返回读出1写入fd的字节数,失败则返回-1并设置ermno。它们相当于简化版的recvmsg和sendmsg函数。

sendfile

sendfile函数在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,这被称为零拷贝。sendfile 丽数的定义如下:

#include<sys/sendfile.h>/* Send up to COUNT bytes from file associated with IN_FD starting at*OFFSET to descriptor OUT_FD.  Set *OFFSET to the IN_FD's file positionfollowing the read bytes.  If OFFSET is a null pointer, use the normalfile position instead.  Return the number of written bytes, or -1 incase of error.  */
extern ssize_t sendfile (int __out_fd, int __in_fd, off_t *__offset,size_t __count) __THROW;

in_ fd 参数是待读出内容的文件描述符,out_fd参数是待写入内容的文件描述符。offset参数指定从读人文件流的哪个位置开始读,如果为空,则使用读人文件流默认的起始位置。count参数指定在文件描述符in_fd 和out_fd 之间传输的字节数。sendfile 成功时返回传输的字节数,失败则返回-1并设置errmo。该函数的man手册明确指出,in_fd 必须是一个支持类似mmap函数的文件描述符,即它必须指向真实的文件,不能是socket和管道;而out fd则必须是一个socket。由此可见,sendfile 几乎是专门为在网络上传输文件而设计的。

mmap函数和munmap函数

mmap函数用于申请一段内存空间。我们可以将这段内存作为进程间通信的共享内存,也可以将文件直接映射到其中。munmap 函数则释放由mmap创建的这段内存空间。它们的定义如下:

#include<sys/mman.h>/* Map addresses starting near ADDR and extending for LEN bytes.  fromOFFSET into the file FD describes according to PROT and FLAGS.  If ADDRis nonzero, it is the desired mapping address.  If the MAP_FIXED bit isset in FLAGS, the mapping will be at ADDR exactly (which must bepage-aligned); otherwise the system chooses a convenient nearby address.The return value is the actual mapping address chosen or MAP_FAILEDfor errors (in which case `errno' is set).  A successful `mmap' calldeallocates any previous mapping for the affected region.  */extern void *mmap (void *__addr, size_t __len, int __prot,int __flags, int __fd, __off_t __offset) __THROW;/* Deallocate any mapping for the region starting at ADDR and extending LENbytes.  Returns 0 if successful, -1 for errors (and sets errno).  */
extern int munmap (void *__addr, size_t __len) __THROW;
  • start参数允许用户使用某个特定的地址作为这段内存的起始地址。如果它被设置成NULL,则系统自动分配一个地址。length 参数指定内存段的长度。

  • prot 参数用来设置内存段的访问权限。它可以取以下几个值的按位或:

    • PROT_READ,内存段可读。
    • PROT_WRITE,内存段可写。
    • PROT_EXEC,内存段可执行。
    • PROT_NONE,内存段不能被访问。
  • flags参数控制内存段内容被修改后程序的行为。它可以被设置为下表中的某些值(这里仅列出了常用的值)的按位或(其中MAP_ SHARED和MAP_PRIVATE 是互斥的,不能同时指定)。

  • fd参数是被映射文件对应的文件描述符。它一般通过open系统调用获得。

  • offset 参数设置从文件的何处开始映射(对于不需要读入整个文件的情况)。

mmap函数成功时返回指向目标内存区域的指针,失败则返回MAP_FAILED((void*)-1)并设置errno。munmap函数成功时返回0,失败则返回-1并设置ermo。

splice函数

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。如果fd_in 不是一个管道文件描述符(比如socket),那么off_in表示从输人数据流的何处开始读取数据。此时,若off_in 被设置为NULL,则表示从输人数据流的当前偏移位置读人;若off_in 不为NULL,则它将指出具体的偏移位置。fd_out/off_out参数的含义与fd_in/off_in相同,不过用于输出数据流。len 参数指定移动数据的长度;flags参数则控制数据如何移动,它可以被设置为下表中的某些值的按位或。

使用splice函数时,fd_in和fd_out必须至少有一个是管道文件描述符。splice函数调用成功时返回移动字节的数量。它可能返回0,表示没有数据需要移动,这发生在从管道中读取数据(fd_in是管道文件描述符)而该管道没有被写人任何数据时。splice 丽数失败时返回-1并设置erro。常见的ermno如下表所示。

tee函数

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

#include<fcntl.h>ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

该函数的参数的含义与splice相同(但fd_in 和fd_out必须都是管道文件描述符)。tee函数成功时返回在两个文件描述符之间复制的数据数量(字节数)。返回0表示没有复制任何数据。tee 失败时返回-1并设置errno。

fcntl函数

fcntl函数,正如其名字(file control)描述的那样,提供了对文件描述符的各种控制操作。另外一个常见的控制文件描述符属性和行为的系统调用是ioctl,而且ioctl比fentI能够执行更多的控制。但是,对于控制文件描述符常用的属性和行为,fentl函数是由POSIX规范指定的首选方法。fentl 函数的定义如下:

#include<fcntl.h>/* Do the file control operation described by CMD on FD.The remaining arguments are interpreted depending on CMD.This function is a cancellation point and therefore not marked with__THROW.  */
extern int fcntl (int __fd, int __cmd, ...);

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


fentl丽数成功时的返回值如表最后一列所示,失败则返回-1并设置ermo。

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

int setnonblocking(int fd)
{int old_option = fcntl(fd, F_GETFL);      /*获取文件描述符旧的状态标志*/int new_option = old_option | O_NONBLOCK;   /* 设置非阻塞标志*/fcnt1(fd, F_SETFL, new_option);               /*返回文件描述符旧的状态标志,以便日后恢复该状态标志*/return old_option;
}

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

Linux I/O函数相关推荐

  1. linux c数字转字符串函数,Linux常用C函数—字符串转换篇

    Linux 常用C 函数-字符串转换篇 atof (将字符串转换成浮点型数) 相关函数 atoi ,atol ,strtod ,strtol ,strtoul 定义函数 double atof(con ...

  2. linux下syscall函数,SYS_gettid,SYS_tgkill

    出处:http://blog.chinaunix.net/uid-28458801-id-4630215.html linux下syscall函数,SYS_gettid,SYS_tgkill 2014 ...

  3. linux中probe函数传递参数的寻找(下)

    点击打开链接 linux中probe函数传递参数的寻找(下) 通过追寻driver的脚步,我们有了努力的方向:只有找到spi_bus_type的填充device即可,下面该从device去打通,当两个 ...

  4. linux中 probe函数的何时调用的?

    点击打开链接 linux中 probe函数何时调用的 所以的驱动教程上都说:只有设备和驱动的名字匹配,BUS就会调用驱动的probe函数,但是有时我们要看看probe函数里面到底做了什么,还有传递给p ...

  5. [C++] 为什么Linux需要itoa函数

    char buf[100]; for (int i = 0; i < 10000000; i++) {     itoa(12345, buf, 10); } 这段代码将耗时327毫秒. cha ...

  6. 每天学一点儿shell:linux中时间函数的date的用法

    文章目录 1.linux中date函数格式 2.date日期函数的具体用法 2.1.获取相应格式的日期 2.2.获取相隔时间段的日期 2.2.1.获取今天的日期 2.2.2.获取昨天的日期 2.2.3 ...

  7. linux下system函数的深入理解

    这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以为 ...

  8. linux '$^t' 时间,Linux C时间函数 time_t struct tm

    Linux C时间函数 time_t struct tm #include 关于时间的类型: time_t long型,表示从1970年1月1日到现在经过的秒数. struct tm { int tm ...

  9. Linux Kernel ‘_xfs_buf_find()’函数空指针引用拒绝服务漏洞

    漏洞名称: Linux Kernel '_xfs_buf_find()'函数空指针引用拒绝服务漏洞 CNNVD编号: CNNVD-201303-071 发布时间: 2013-03-06 更新时间: 2 ...

  10. Linux C 时间函数

    各种标准时间解释及主要Linux C标准时间函数说明 http://www.cnblogs.com/ziwuge/archive/2012/02/22/2364066.html 增加弥补mktime缺 ...

最新文章

  1. 指针 与 swift 中的引用
  2. python连接mongo_Python连接MongoDB操作
  3. 4月17日云栖精选夜读 | 在阿里做了五年技术主管,我有话想说
  4. OSPF如何选举DR/BDR规则
  5. 【数据平台】centos下部署anaconda2和pyhs2组件
  6. mysql 存儲過程調用_mysql-VS2010+MYSQL 存儲過程調用出錯
  7. MATLAB计算卫星相对位置、速度和加速度
  8. MYSQL 安装时出现的问题error: Failed dependencies
  9. linux 该文件的owner,Linux修改文件/目录的owner/group方法(转载)
  10. 新技术在支付清算行业的创新应用
  11. 华为鸿蒙跑了个“hello world”!跑通后,我特么开始怀疑人生....
  12. 计算机网络 同步传输和异步传输
  13. 什么是你最关键的人脉
  14. 拆分可再生能源业务上市,华润电力意欲何为?
  15. vue中使用canvas手写输入识别中文
  16. RT-Thread功耗调优项目实战 - 如何做好功耗
  17. 计算机考试答题设计用例图,学生网上考试系统的设计与实现
  18. 单片机——PWM调光工作原理
  19. 打印机部件到了服务期限的解决办法-复位法
  20. 一起学习用Verilog在FPGA上实现CNN----(三)激活层设计

热门文章

  1. 用input type=file调取手机照相机以及相册选择照片上传
  2. u盘盘符不显示 win10_Win10不显示U盘的盘符怎么办
  3. 英语口语练习四十六之旅行
  4. xxd命令(反编译、二进制文件转十六进制文件)
  5. python成绩统计系统xlwings_科学网—利用Python扩展Excel能力的xlwings库使用体会 - 丁祥欢的博文...
  6. C#: double转int , String转int
  7. 按字节寻址和按字寻址
  8. mondrian in action 第一章翻译 (主要用百度翻译完成,稍加整理)
  9. Pruning paper 合集
  10. python支持向量机库安装,使用python学习【机器学习】需要安装的库~