sendfile和splice这两个函数都是在文件描述符之间传输数据的,而且两者都是“零拷贝”,数据不需要内核空间和用户空间直接做无谓的复制,区别在于,
sendfile函数的两个文件描述符参数out_fd必须为socket,
而splice函数的两个文件描述符参数必须有一个是管道
#include
ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count);
#include
ssize_t splice(int fdin, loff_t *offin, int fdout, loff_t *offout, size_t len, unsigned int flags);
用sendfile将文件的内容通过服务器发送给连接上的客户端。
用splice函数写一个简单的回射服务器(将客户端的数据返回给客户端)。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*sendfile 将文件内的数据发送给连接上的客户端*/
const int g_port = 10086;
const char* file_name = "test.txt";
int main(void)
{
int filefd = open(file_name, O_RDONLY);
if (filefd < 0) {
printf("open err\n");
return -1;
}
/*int fstat(int fdp, struct stat *struct_stat); //通过文件描述符获取文件对应的属性。fdp为文件描述符
下面是这个结构的结构
struct stat {
mode_t st_mode; //文件对应的模式,文件,目录等
ino_t st_ino; //inode节点号
dev_t st_dev; //设备号码
dev_t st_rdev; //特殊设备号码
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者
gid_t st_gid; //文件所有者对应的组
off_t st_size; //普通文件,对应的文件字节数
ime_t st_atime; //文件最后被访问的时间
time_t st_mtime; //文件内容最后被修改的时间
time_t st_ctime; //文件状态改变时间
blksize_t st_blksize; //文件内容对应的块大小
blkcnt_t st_blocks; //伟建内容对应的块数量
};*/
struct stat stat_buf;
fstat(filefd, &stat_buf);
struct sockaddr_in addr_server;
bzero(&addr_server, sizeof(addr_server));
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(g_port);
addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0) {
printf("socket err \n");
return -1;
}
int ret = bind(sfd, (struct sockaddr*)&addr_server, sizeof(addr_server));
if (ret < 0) {
printf("binf err \n");
return -1;
}
ret = listen(sfd, 10);
if (ret < 0) {
printf("listen err\n");
return -1;
}
struct sockaddr_in addr_client;
socklen_t addrlen_client = sizeof(addr_client);
//bzero(&addr_client, addrlen_client);
int cfd = accept(sfd, (struct sockaddr*)&addr_client, &addrlen_client);
if (cfd < 0) {
printf("accept err \n");
return -1;
}
else
{
/*出现了*/
/*#include
ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count);*/
sendfile(cfd, filefd, NULL, stat_buf.st_size);
close(cfd);
}
close(sfd);
return 0;
}
#define _GNU_SOURCE 1
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*splice 实现的回射服务器*/
const int g_port = 10086;
int main(void)
{
int ret = 0;
struct sockaddr_in addr_server;
bzero(&addr_server, sizeof(addr_server));
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(g_port);
addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0) {
printf("socket err \n");
return -1;
}
ret = bind(sfd, (struct sockaddr*)&addr_server, sizeof(addr_server));
if (ret < 0) {
printf("binf err \n");
return -1;
}
ret = listen(sfd, 10);
if (ret < 0) {
printf("listen err\n");
return -1;
}
struct sockaddr_in addr_client;
socklen_t addrlen_client = sizeof(addr_client);
//bzero(&addr_client, addrlen_client);
int cfd = accept(sfd, (struct sockaddr*)&addr_client, &addrlen_client);
if (cfd < 0) {
printf("accept err \n");
return -1;
}
else
{
int pipefd[2];
ret = pipe(pipefd);
if (ret < 0) {
printf("pipe err \n");
return -1;
}
ret = splice(cfd, NULL, pipefd[1], NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);
if (ret < 0) {
printf("splice1 err\n");
return -1;
}
ret = splice(pipefd[0], NULL, cfd, NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);
if (ret < 0) {
printf("splice2 err\n");
return -1;
}
close(cfd);
}
close(sfd);
return 0;
}