6.1 pipe函数

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

 #include<unistd.h>
int pipe(int fd[]);

参数包含两个文件描述符fd[0]和fd[1],往fd[1]写入的数据可以从fd[0]读出

默认情况下这对文件描述符都是阻塞的。如果用read调用读取一个空管道,read将会阻塞直到有数据可读为止;write类似。

如果将fd[0]\fd[1]都设置为非阻塞,则read和write会有不同行为。如果fd[1]引用计数减少到0,即没有任何进程需要往管道写入数据,则对fd[0]的read操作返回0,即读到了EOF;反之,如果fd[0]引用计数减少至0,则对fd[1]的write操作将失败,并引发SIGPIPE信号。

管道内部传输的数据是字节流,这和TCP字节流的概念相同。从Linux 2.6.11开始,管道容量的大小是默认65536字节。可以使用fcntl修改。

socketpair函数可以方便的创建双向管道:

 #include<sys/types.h>
#include<sys/socket.h>
int socketpair(int domain, int type, int protocol, int fd[]);

6.2 dup函数和dup2函数 

复制文件描述符,它们经常用来重定向进程的stdin、stdout和stderr。文件描述符是与打开文件或者数据流 相关联的整数, 0、1、2 是系统保留的三个文件描述符,分别对应标准输入、标准输出、标准错误

 #include<unistd.h>
int dup(int file_descriptor);
int dup2(int file_descriptor_one, int file_descriptor_two);

利用函数dup,我们可以复制一个描述符。传给该函数一个既有的描述符,它就会返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝。这意味着,这两个描述符共享同一个数据结构。

dup2函数跟dup函数相似,但dup2函数允许调用者规定一个有效描述符和目标描述符的id。dup2函数成功返回时,目标描述符(dup2函数的第二个参数)将变成源描述符(dup2函数的第一个参数)的复制品,换句话说,两个文件描述符现在都指向同一个文件,并且是函数第一个参数指向的文件。

通过dup和dup2创建的文件描述符并不继承原来的文件描述符的属性,比如close-on-exec和non-blocking等。

例子:CGI服务器的基本原理

    int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength );
if ( connfd < )
{
printf( "errno is: %d\n", errno );
}
else
{
close( STDOUT_FILENO );
dup( connfd );
printf( "abcd\n" );
close( connfd );
}

关闭标准输出文件描述符,dup总返回系统最小的可用文件描述符,所以实际返回值是1,这样就将所连接的socket文件描述符connfd定位到标书输出,printf调用的输出将被客户端获得,这就是CGI服务器的基本原理

6.3 readv函数和writev函数 

读指从文件描述符读到内存,写指从内存写入文件描述符

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

 #include<sysy/uio.h>
ssize_t readv(int fd, const struct iovec* vector, int count);
ssize_t writev(int fd, const struct iovec* vector, int count);
struct iovec {
void *iov_base; //starting address
size_t iov_len; //number of bytes to transfer
};

例子:web服务器对客户端的HTTP请求响应,HTTP应答包含1个状态行,多个头部字段,1个空行和文档内容,这些可能不在一起,可以用writev写入一个文件描述符

 struct iovec iv[];
iv[ ].iov_base = header_buf;
iv[ ].iov_len = strlen( header_buf );
iv[ ].iov_base = file_buf;
iv[ ].iov_len = file_stat.st_size;
ret = writev( connfd, iv, );

6.4 sendfile函数

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

 #include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);

in_fd必须是一个支持类似mmap函数的文件描述符,即它必须指向真实的文件,不能是socket和管道;

而out_fd则必须是一个socket,由此可见,sendfile几乎是专门为在网络上传输文件设计的。

offset:读入位置

count:传输字节数

6.5 mmap函数和munmap函数

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

 #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时,系统自动分配一个地址。

prot参数用来设置访问权限。按位或:

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

flags参数控制内存段修改后的行为

6.6 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);

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

如果fd_in是管道描述符,那么off_in必须为NULL。若不是管道,则标示从什么位置读取,fd_out类似

flags参数:

 SPLICE_F_MOVE    //按整页内存移动数据,只是给内核一个提示,没有实际效果。
SPLICE_F_NONBLOCK //实际效果还会受到文件描述符本身的阻塞状态影响。
SPLICE_F_MORE //给内核一个提示:后续的splice调用将读取更多数据。
SPLICE_F_GIFT //没有效果

例子:使用splice函数实现的echo服务器

     int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength );
if ( connfd < )
{
printf( "errno is: %d\n", errno );
}
else
{
int pipefd[];
assert( ret != - );
ret = pipe( pipefd );
ret = splice( connfd, NULL, pipefd[], NULL, , SPLICE_F_MORE | SPLICE_F_MOVE ); //从connfd流入的客户端数据定向到管道
assert( ret != - );
ret = splice( pipefd[], NULL, connfd, NULL, , SPLICE_F_MORE | SPLICE_F_MOVE ); //将管道输出定向到connfd客户端连接的文件描述符
assert( ret != - );
close( connfd );
}

6.7 tee函数

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

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

6.8 fcntl函数

提供了对文件描述符的各种控制操作

 #include <fcntl.h>
int fcntl(int fd, int cmd, ...);

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

 #include <fcntl.h>
int fcntl(int fd, int cmd, ...);
int setnonblocking(int fd)
{
int old_option = fcntl( fd ,F_GETFD ); //获取文件描述符旧状态标志
int new_option = odl_option | O_NONBLOCK; //设置非阻塞标志
funcl( fd, F_SETFL, new_option);
return old_option; //返回旧状态以便日后恢复
}

6 高级IO函数的更多相关文章

  1. 第14章——高级IO函数

    1.套接字超时 套接字IO函数设置超时的方法有三种: (1)调用alarm. (2)select (3)使用SO_RECTIMEO和 SO_SNDTIMEO 选项 上面三种方法适用于输入输出操作(re ...

  2. UNIX高级环境编程(7)标准IO函数库 - 二进制文件IO,流定位,创建临时文件和内存流

    1 二进制IO(Binary IO) 在前一篇我们了解了逐字符读写和逐行读写函数. 如果我们在读写二进制文件,希望以此读写整个文件内容,这两个函数虽然可以实现,但是明显会很麻烦且多次循环明显效率很低. ...

  3. UNIX高级环境编程(6)标准IO函数库 - 流的概念和操作

    标准IO函数库隐藏了buffer大小和分配的细节,使得我们可以不用关心预分配的内存大小是否正确的问题. 虽然这使得这个函数库很容易用,但是如果我们对函数的原理不熟悉的话,也容易遇到很多问题.   1 ...

  4. (十一) 一起学 Unix 环境高级编程 (APUE) 之 高级 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  5. 标准C IO函数和 内核IO函数 效率(时间)比较

    前言 标准C提供的文件相关的IO函数,除标准错误输出是不带缓冲的(可以尽快的将错误消息显示出来)之外,所有与终端相关的都是行缓冲,其余都是全缓冲的. 我们可以使用setbuf,setvbuf改变指定流 ...

  6. 高级IO

    # 高级IO 特殊的IO操作,包括文件锁.系统V的流.信号驱动的I/O.多路转I/O(select和pull函数).readv和writev函数以及存贮映射I/O等概念和函数. ## 文件锁 文件锁是 ...

  7. linux网络编程之IO函数

    Linux操作系统中的IO函数主要有read(),write(),recv(),send(),recvmsg(),sendmsg(),readv(),writev(). 接收数据的recv()函数 # ...

  8. linux_api之高级IO

    本篇索引: 1.引言 2.非阻塞IO 3.记录锁(文件锁) 4.io多路复用(I/O multiplexing ) 5.异步IO 6.存储映射IO 1.引言 我们第三篇学习了对IO的open.read ...

  9. python高级之函数

    python高级之函数 本节内容 函数的介绍 函数的创建 函数参数及返回值 LEGB作用域 特殊函数 函数式编程 1.函数的介绍 为什么要有函数?因为在平时写代码时,如果没有函数的话,那么将会出现很多 ...

随机推荐

  1. 安装Google框架服务并突破Google Play下载限制

    请注明出处:http://www.cnblogs.com/killerlegend/p/3546235.html Written By KillerLegend 关于谷歌服务框架以及安装 安装前请先获 ...

  2. ViewPager中GridView问题

    GridView 嵌套在ViewPager中问题. 1. GridView属性设置无法显示. 正常显示方式 <GridView android:padding="8dip" ...

  3. ASP.NET MVC5学习笔记之Action参数模型绑定基本过程

    当我们在Controller中定义一个Action,通常会定义一个或多个参数,每个参数称为一个模型,ASP.NET MVC框架提供了一种机制称为模型绑定,会尝试自动从请求的信息中实例化每一个模型并赋值 ...

  4. 种树 (codevs 1653) 题解

    [问题描述] 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号为1..n.每个块大小为一个单位尺寸并最多可种一棵树.每个居民想在门前种些树并指定了三个号码b,e ...

  5. 在EF的code frist下写稳健的权限管理系统:数据库模型(二)

    先从数据库开始,因为是用EF的code frist,所以所有的设计都在解决项目中进行. 先是数据模型开始 我已经建立了四个模型,user,role,action,actiongroup user里面有 ...

  6. Python学习教程(learning Python)--2.3 Python自定义函数传参函数设计

    Python里自定义子函数时,可以在调用时携带一些参数到子函数里去处理.具体用法结构如下: def func(arguments): statement statement etc. 定义子函数一定要 ...

  7. 通过java反射实现简单的关于MongoDB的对象关系映射(ORM).

    通过阅读MongoDB  3.2.1的官方文档中关于java 编程发现最新的文档并没有实现对对象到Document的映射,所以自己有了利用反射实现简单的关系映射. 1.定义抽象类:AbstractMo ...

  8. 019C#中使用移位运算符获取汉字编码值

    在进行移位运算时,当数值的二进制数每次向左移1位就相当于乘以2,当数值每次向右移一位就相当于除以2 private void button1_Click(object sender, EventArg ...

  9. SQL Server基本操作积累

    一.基本操作 1.将数据绑定到DataGridVirw控件上显示的数据列标题将会是数据库中的字段名称,可以在使用select语句时使用AS关键字将转化为列名的别名 select name AS 姓名 ...

  10. bzoj 3223/tyvj 1729 文艺平衡树 splay tree

    原题链接:http://www.tyvj.cn/p/1729 这道题以前用c语言写的splay tree水过了.. 现在接触了c++重写一遍... 只涉及区间翻转,由于没有删除操作故不带垃圾回收,具体 ...