1、sendfile和splice相同之處
sendfile和splice這兩個函數都是在文件描述符之間傳輸數據的,而且兩者都是“零拷貝”,數據不需要內核空間和用戶空間直接做無謂的複製,區別在於,
sendfile函數的兩個文件描述符參數out_fd必須爲socket,
而splice函數的兩個文件描述符參數必須有一個是管道
#include<sys/sendfile.h>
ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count);
#include <fcntl.h>
ssize_t splice(int fdin, loff_t *offin, int fdout, loff_t *offout, size_t len, unsigned int flags);
2、下面用兩個函數寫個簡單例子
用sendfile將文件的內容通過服務器發送給連接上的客戶端。
用splice函數寫一個簡單的回射服務器(將客戶端的數據返回給客戶端)。
3、sendfile
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
/*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<sys/sendfile.h>
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;
}
4、splice
#define _GNU_SOURCE 1
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
/*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;
}