C Linux上sendfileapi的测量
我编写了一个简单的文件复制应用程序来衡量使用sendfileapi对大文件的有效性,而不是常规的从文件读取和向套接字写入方法。然而,在使用这两种方法运行应用程序时,我发现两种方法之间完成文件拷贝所需的时间差异非常小 我从多个来源了解到,“sendfile”API将比普通的从文件读取和向套接字写入的方法提供巨大的性能改进。但当我尝试使用单个2GB文件进行基准测试时,以下是我观察到的数字(平均4次迭代):C Linux上sendfileapi的测量,c,linux,network-programming,C,Linux,Network Programming,我编写了一个简单的文件复制应用程序来衡量使用sendfileapi对大文件的有效性,而不是常规的从文件读取和向套接字写入方法。然而,在使用这两种方法运行应用程序时,我发现两种方法之间完成文件拷贝所需的时间差异非常小 我从多个来源了解到,“sendfile”API将比普通的从文件读取和向套接字写入的方法提供巨大的性能改进。但当我尝试使用单个2GB文件进行基准测试时,以下是我观察到的数字(平均4次迭代): 正常的文件读写套接字方法:17秒444840 usecs sendfileapi:17秒431
#define _GNU_SOURCE
#include "file_details.h"
void calculate_execution_time(struct timeval start, struct timeval end)
{
struct timeval time_diff;
time_diff.tv_sec = end.tv_sec - start.tv_sec;
time_diff.tv_usec = end.tv_usec - start.tv_usec;
// Adjust the time appropriately
while (time_diff.tv_usec < 0) {
time_diff.tv_sec--;
time_diff.tv_usec += 1000000;
}
printf("total execution time: = %lds.%ldus\n", time_diff.tv_sec, time_diff.tv_usec);
}
int read_from_file_pread(int client_sockfd, char *file_name, int fd, off_t file_size_in_bytes, int chunk_size)
{
ssize_t bytes_read = 0, bytes_sent = 0, total_bytes_sent = 0, bytes_sent_this_itr = 0;
off_t offset = 0;
char *buffer = NULL;
struct timeval start_time, end_time;
buffer = calloc(chunk_size, sizeof(char));
if (buffer == NULL) {
printf("Failed to allocate memory of size: %d bytes\n", chunk_size);
return -1;
}
gettimeofday(&start_time, NULL);
do {
bytes_read = pread(fd, buffer, chunk_size, offset);
switch (bytes_read) {
case -1:
printf("Failed to read from file: %s, offset: %lu, error: %d\n", file_name, offset, errno);
free(buffer);
return -1;
case 0:
printf("Completed reading from file and sending\n");
break;
default:
do {
bytes_sent = send(client_sockfd, buffer, (bytes_read - bytes_sent_this_itr), 0);
if (bytes_sent == -1) {
printf("Failed to send %lu bytes, error: %d\n", (bytes_read - bytes_sent_this_itr), errno);
free(buffer);
return -1;
}
bytes_sent_this_itr += bytes_sent;
} while (bytes_sent_this_itr < bytes_read);
bytes_sent = 0;
bytes_sent_this_itr = 0;
offset += bytes_read;
total_bytes_sent += bytes_read;
break;
}
} while (total_bytes_sent < file_size_in_bytes);
gettimeofday(&end_time, NULL);
printf("File size: %lu bytes, total bytes read from file: %lu, ", file_size_in_bytes, total_bytes_sent);
calculate_execution_time(start_time, end_time);
free(buffer);
return 0;
}
int read_from_file_sendfile(int client_sockfd, char *file_name, int fd, off_t file_size_in_bytes, int chunk_size)
{
ssize_t bytes_sent = 0, total_bytes_sent = 0;
off_t offset = 0;
struct timeval start_time, end_time;
gettimeofday(&start_time, NULL);
do {
bytes_sent = sendfile(client_sockfd, fd, &offset, chunk_size);
if (bytes_sent == -1) {
printf("Failed to sendfile: %s, offset: %lu, error: %d\n", file_name, offset, errno);
return -1;
}
total_bytes_sent += bytes_sent;
} while (total_bytes_sent < file_size_in_bytes);
gettimeofday(&end_time, NULL);
printf("File size: %lu bytes, total bytes read from file: %lu, ", file_size_in_bytes, total_bytes_sent);
calculate_execution_time(start_time, end_time);
return 0;
}
int read_from_file(int client_sockfd, char *file_name, char *type, int chunk_size)
{
int error_code = 0, fd = 0;
ssize_t hdr_length = 0, bytes_sent = 0, file_name_length = strlen(file_name);
struct stat file_stat = {0};
struct file_details *file_details_to_send = NULL;
fd = open(file_name, O_RDONLY, S_IRUSR);
if (fd == -1) {
printf("Failed to open file: %s, error: %d\n", file_name, errno);
return -1;
}
error_code = fstat(fd, &file_stat);
if (error_code == -1) {
printf("Failed to get status of file: %s, error: %d\n", file_name, errno);
close(fd);
return -1;
}
hdr_length = (sizeof(struct file_details) + file_name_length + 1);
file_details_to_send = calloc(hdr_length, sizeof(char));
if (file_details_to_send == NULL) {
perror("Failed to allocate memory");
close(fd);
return -1;
}
file_details_to_send->file_name_length = file_name_length;
file_details_to_send->file_size_in_bytes = file_stat.st_size;
strcpy(file_details_to_send->file_name, file_name);
printf("File name: %s, size: %lu bytes\n", file_name, file_stat.st_size);
bytes_sent = send(client_sockfd, file_details_to_send, hdr_length, 0);
if (bytes_sent == -1) {
printf("Failed to send header of size: %lu bytes, error: %d\n", hdr_length, errno);
close(fd);
return -1;
}
if (strcmp(type, "rw") == 0) {
printf("By pread and send\n");
read_from_file_pread(client_sockfd, file_name, fd, file_stat.st_size, chunk_size);
} else {
printf("By sendfile\n");
read_from_file_sendfile(client_sockfd, file_name, fd, file_stat.st_size, chunk_size);
}
close(fd);
return 0;
}
int main(int argc, char *argv[])
{
...
...
option_value = 1;
error_code = setsockopt(client_sockfd, SOL_TCP, TCP_NODELAY, &option_value, sizeof(int));
if (error_code == -1) {
printf("Failed to set socket option TCP_NODELAY to socket descriptor: %d, error: %d", client_sockfd, errno);
}
read_from_file(client_sockfd, file_name, type, chunk_size);
...
}
定义GNU源
#包括“文件\u details.h”
无效计算执行时间(结构时间值开始,结构时间值结束)
{
结构时间差;
time_diff.tv_sec=end.tv_sec-start.tv_sec;
time_diff.tv_usec=end.tv_usec-start.tv_usec;
//适当调整时间
同时(时间差电视节目<0){
时差电视秒;
时间差电视使用次数+=1000000;
}
printf(“总执行时间:=%lds.%ldus\n”,时间差电视秒,时间差电视秒);
}
int从文件读取(int客户端sockfd,字符*文件名,int fd,关闭文件大小(以字节为单位),int块大小)
{
ssize_t bytes_read=0,bytes_sent=0,total_bytes_sent=0,bytes_sent_this_itr=0;
off_t offset=0;
char*buffer=NULL;
结构时间值开始时间、结束时间;
buffer=calloc(chunk_size,sizeof(char));
if(buffer==NULL){
printf(“分配大小为%d字节的内存失败”,chunk\u size);
返回-1;
}
gettimeofday(&开始时间,NULL);
做{
字节读取=前置(fd、缓冲区、块大小、偏移量);
开关(字节\读取){
案例1:
printf(“读取文件%s失败,偏移量:%lu,错误:%d\n”,文件名,偏移量,错误号);
自由(缓冲);
返回-1;
案例0:
printf(“从文件读取并发送完成”);
打破
违约:
做{
字节发送=发送(客户端sockfd,缓冲区,(字节读取-字节发送,此itr),0);
如果(发送的字节数==-1){
printf(“发送%lu字节失败,错误:%d\n”,(字节\u读取-字节\u发送\u此itr),错误号);
自由(缓冲);
返回-1;
}
已发送字节数\u此\u itr+=已发送字节数;
}while(已发送的字节数<读取的字节数);
发送的字节数=0;
发送的字节数=0;
偏移量+=读取的字节数;
发送的总字节数+=读取的字节数;
打破
}
}while(发送的总字节数<文件大小,以字节为单位);
gettimeofday(&end_time,NULL);
printf(“文件大小:%lu字节,从文件读取的总字节数:%lu,”,文件大小(单位:字节),发送的总字节数);
计算执行时间(开始时间、结束时间);
自由(缓冲);
返回0;
}
int read_from_file_sendfile(int client_sockfd,char*file_name,int fd,off_t file_size_字节,int chunk_size)
{
ssize_t bytes_sent=0,total_bytes_sent=0;
off_t offset=0;
结构时间值开始时间、结束时间;
gettimeofday(&开始时间,NULL);
做{
字节\u发送=发送文件(客户端\u sockfd、fd和偏移量、块大小);
如果(发送的字节数==-1){
printf(“发送文件失败:%s,偏移量:%lu,错误:%d\n”,文件名,偏移量,错误号);
返回-1;
}
发送的总字节数+=发送的字节数;
}while(发送的总字节数<文件大小,以字节为单位);
gettimeofday(&end_time,NULL);
printf(“文件大小:%lu字节,从文件读取的总字节数:%lu,”,文件大小(单位:字节),发送的总字节数);
计算执行时间(开始时间、结束时间);
返回0;
}
从文件读取的整型数据(整型客户端数据,字符*文件名,字符*类型,整型数据块大小)
{
int error_code=0,fd=0;
ssize_t hdr_length=0,bytes_sent=0,file_name_length=strlen(file_name);
struct stat file_stat={0};
struct file_details*file_details_to_send=NULL;
fd=打开(文件名,仅限O rdu,S IRUSR);
如果(fd==-1){
printf(“无法打开文件:%s,错误:%d\n”,文件名,错误号);
返回-1;
}
错误代码=fstat(fd和文件统计);
如果(错误代码==-1){
printf(“无法获取文件%s的状态,错误:%d\n”,文件名,错误号);
关闭(fd);
返回-1;
}
hdr_长度=(sizeof(结构文件_详细信息)+文件名_长度+1);
file_details_to_send=calloc(hdr_长度,sizeof(char));
if(文件详细信息到发送==NULL){
perror(“分配内存失败”);
关闭(fd);
返回-1;
}
文件\详细信息\发送->文件\名称\长度=文件\名称\长度;
文件详细信息发送->文件大小(以字节为单位)=file\u stat.st\u size;
strcpy(文件详细信息发送->文件名,文件名);
printf(“文件名:%s,大小:%lu字节\n”,文件名,文件统计.st\u大小);
字节发送=发送(客户端sockfd,文件详细信息发送,hdr长度,0);
如果(发送的字节数==-1){
printf(“未能发送大小为:%lu字节的标头,错误:%d\n”,hdr\u长度,错误号);
关闭(fd);
返回-1;
}
if(strcmp(类型,“rw”)==0){
printf(“通过pread和send\n”);
从文件序言中读取(客户端、文件名、文件名、文件大小、块大小);
}否则{
printf(“通过sendfile\n”);