sendfile函数:
函数原型:
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
sendfile在两个文件描述符之间直接传输数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间拷贝数据,效率很高,这被称为零拷贝.
out_fd: 待写入数据的文件描述符
in_fd:待读出数据的文件描述符
offset:指定从读入文件流的哪个位置开始读书据,如果为空,则采用默认的读入文件其起始位置
count:指定在in_fd 和out_fd 之间传输的数据字节数
函数返回值:成功传输的字节数
注意:
in_fd 必须是真实存在的文件,不能是socket和管道
out_fd 必须是一个socket.
测试代码:
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#include<sys/epoll.h>
#include<pthread.h>
#include<libgen.h>
ser.c文件:
#include"../utili.h"
int main(int argc,char *argv[])
{
if(argc<=3)
{
printf("usage: %s ip port_number\n",basename(argv[0]));
return 1;
}
const char*ip = argv[1];
int port = atoi(argv[2]);
const char *file_name = argv[3];
int filefd = open(file_name,O_RDONLY);
assert(filefd>0);
struct stat stat_buf;
fstat(filefd,&stat_buf);
struct sockaddr_in address;
bzero(&address,sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET,ip,&address.sin_addr);
int sock = socket(AF_INET,SOCK_STREAM,0);
assert(sock>=0);
socklen_t len = sizeof(address);
int ret = bind(sock,(struct sockaddr*)&address,len);
assert(ret!=-1);
ret = listen(sock,5);
assert(ret!=-1);
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
int connfd = accept(sock,(struct sockaddr*)&client,&client_len);
if(connfd<0)
{
printf("errno: %d\n",errno);
}
else
{
sendfile(connfd,filefd,NULL,stat_buf.st_size);
close(connfd);
}
close(sock);
return 0;
}
cli.c文件:
#include"../utili.h"
int main(int argc,char *argv[])
{
const char *ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in addrSer;
bzero(&addrSer,sizeof(addrSer));
addrSer.sin_family = AF_INET;
addrSer.sin_port = htons(port);
inet_pton(AF_INET,ip ,&addrSer.sin_addr);
int sock = socket(AF_INET,SOCK_STREAM,0);
assert(sock>=0);
int ret = connect(sock,(struct sockaddr*)&addrSer,sizeof(addrSer));
assert(ret>=0);
char buf[50];
while(1)
{
ret = recv(sock,buf,50,0);
if(ret<0)
break;
else if(ret == 0)
{
printf("sever close connextion\n");
break;
}
else
printf("get %d bytes : %s\n",(int)strlen(buf),buf);
}
close(sock);
}