高级I/O函数(1)-writev、readv、sendfile函数

 1.前言

Linux提供了很多的高级I/O函数,它们在特定的条件下表现出优秀的特性。这里主要讨论的是和网络编程相关的几个。

用于读写数据的函数,包括writev/readv、sendfile。

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

struct iovec{   void *iov_base;/*内存的起始地址*/   size_t iov_len;  /*内存的长度*/
};

/*fd参数是被操作的文件描述符。结构体iovec描述的是一块内存。count参数是vector数组的长度,即有多少块内存数据需要从fd读出或写到fd。*/返回值:readv和writev在成功时返回读出或写入fd的字节数。失败时则返回-1并设置errno.

sendfile函数

1 #include <sys/sendfile.h>
2  ssize_t sendfile(int out_fd,int in_fd,off_t* offset,size_t count);
3 /*返回值:成功时返回传输的字节数,失败时则返回-1并设置errno.

函数说明:

  • in_fd参数是待读出内容的文件描述符,out_fd是待写入内容的文件描述符。offset参数指定从读入文件流的哪个位置开始读,如果为空,则使用读入文件流默认的起始位置。count参数指定在文件描述in_fd和out_fd之间的传输的字节数。
  • in_fd必须指向真实的文件,不能使socket的管道;而out_fd则必须是一个socket。因此可知,sendfile函数几乎是专门为了网络上传输文件而设计的。
  • 下面是利用sendfile函数将服务器上的一个文件传送给客户端
 1 /*****************利用sendfile函数传送文件***************/
 2
 3 #include <sys/socket.h>
 4 #include <netinet/in.h>
 5 #include <arpa/inet.h>
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <string.h>
 9 #include <assert.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <sys/sendfile.h>
13
14 int main(int argc,const char* argv[]){
15      if(argc<=3){
16            printf("usage:%s ip_addresport_number filename\n",argv[0]);
17            return -1;
18      }
19
20      const char* ip=argv[1];
21      int  port=atoi(argv[2]);
22
23      int filefd=open(argv[3],O_RDONLY);
24      assert(filefd!=-1);
25
26      struct stat stat_buf;
27      fstat(filefd,&stat_buf);
28
29      struct sockaddr_in address;
30      bzero(&address,sizeof(address));
31      address.sin_family=AF_INET;
32      inet_pton(AF_INET,ip,&address.sin_addr);
33
34      int sock=socket(AF_INET,SOCK_STREAM,0);
35      assert(sock!=-1);
36
37
38       int ret=bind(sock,(strucsockaddr*)&address,sizeof(address));
39       assert(ret!=-1);
40
41       ret=listen(sock,5);
42       assert(ret!=-1);
43
44       struct sockaddr_in client;
45       socklen_t addrlen;
46       int connfd=accept(sock,(struct sockaddr*)&client,&addrlen);
47       if(connfd<0){
48             printf("errno is:%d \n",errno);
49       }
50
51       else{
52            sendfile(connfd,filefd,NULL,stat_buf.st_size);
53            close(connfd);
54        }
55
56         close(sock);
57         return 0;
58 }

/*代码没有为目标文件分配任何用户空间的缓存,也没有执行读取文件的操作,但同样实现了文件的发送,其效率显然要高得很多.*/
时间: 2024-07-31 14:31:29

高级I/O函数(1)-writev、readv、sendfile函数的相关文章

套接字I/O函数write/read writev/readv send/recv sendto/recvfrom sendmsg/recvmsg

函数原型 read/write系原型 1 #include <unistd.h> 2 3 ssize_t read(int fd, void *buf, size_t count); 1 #include <unistd.h> 2 3 ssize_t write(int fd, const void *buf, size_t count); 1 #include <sys/uio.h> 2 3 ssize_t readv(int fd, const struct iov

UNIX高级环境编程(13)信号 - 概念、signal函数、可重入函数

信号就是软中断. 信号提供了异步处理事件的一种方式.例如,用户在终端按下结束进程键,使一个进程提前终止. ? 1 信号的概念 每一个信号都有一个名字,它们的名字都以SIG打头.例如,每当进程调用了abort函数时,都会产生一个SIGABRT信号. 每一个信号对应一个正整数,定义在头文件<signal.h>中. 没有信号对应整数0,kill函数使用信号编号0表示一种特殊情况,所以信号编号0又叫做空信号(null signal). 下面的各种情况会产生一个信号: 当用户在终端按下特定的键时,会产生

linux内核系统调用--sendfile函数

在apache,nginx,lighttpd等web服务器当中,都有一项sendfile相关的配置,在一些网上的资料都有谈到sendfile会提升文件传输性能,那sendfile到底是什么呢?它的原理又是如何呢? 在传统的文件传输里面(read/write方式),在实现上其实是比较复杂的,需要经过多次上下文的切换,我们看一下如下两行代码: Java代码 read(file, tmp_buf, len); write(socket, tmp_buf, len); 以上两行代码是传统的read/wr

Linux &quot;零拷贝&quot; sendfile函数中文说明及实际操作

Sendfile函数说明 #include ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); sendfile()是作用于数据拷贝在两个文件描述符之间的操作函数.这个拷贝操作是内核中操作的,所以称为"零拷贝".sendfile函数比起read和write函数高效得多,因为read和write是要把数据拷贝到用户应用层操作. 参数说明: out_fd 是已经打开了,用于写操作(write)的文件描述

JavaScript高级程序设计学习笔记第五章--引用类型(函数部分)

四.Function类型: 1.函数定义的方法: 函数声明:function sum (num1, num2) {return num1 + num2;} 函数表达式:var sum = function(num1, num2){return num1 + num2;};//注意有个分号 构造函数的方式:var sum = new Function("num1", "num2", "return num1 + num2");// 2.函数的重复声

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

? 1 二进制IO(Binary IO) 在前一篇我们了解了逐字符读写和逐行读写函数. 如果我们在读写二进制文件,希望以此读写整个文件内容,这两个函数虽然可以实现,但是明显会很麻烦且多次循环明显效率很低. 为了应对这种场景,标准IO库提供了fread和fwrite函数. 函数声明: #include <stdio.h> size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp); size_t fw

嵌套函数和作用域和匿名函数

#嵌套函数 def func1(): print('alex') def func2(): print('eric') func2() func1() #===>1.函数内部可以再次定义函数.2.执行需要被调用 age = 19 def func1(): print(age) def func2(): print(age) func2() #==>19 func1() #==>19 #由内而外调用直 age = 19 def func1(): print(age) def func2()

为什么if else 语句里不能用函数声明定义函数,而可以用函数表达式定义函数

在<JavaScript高级程序设计>第三版第7章函数表达式部分讲到,定义函数有两种方式:一种是函数声明,另一种就是函数表达式.函数声明的语法是这样的.function functionName(arg0, arg1, arg2) {//函数体} 关于函数声明,它的一个重要特征就是函数声明提升( function declaration hoisting),意思是在执行代码之前会先读取函数声明.这就意味着可以把函数声明放在调用它的语句后面.sayHi();function sayHi(){al

C++学习笔记(2)---2.5 C++函数编译原理和成员函数的实现

转载自:http://c.biancheng.NET/cpp/biancheng/view/2996.html点击打开链接 从上节的例子可以看出,对象的内存模型中只保留了成员变量,除此之外没有任何其他信息,程序运行时不知道 obj 的类型为 Demo,也不知道它还有一个成员函数 display().那么,究竟是如何通过对象调用成员函数的呢? C++函数的编译 C++和C语言的编译方式不同.C语言中的函数在编译时名字不变,或者只是简单的加一个下划线_(不同的编译器有不同的实现),例如,func()