sendfile
#include <sys/sendfile.h>
ssize_t sendfile(int out0_fd, int in_fd, off_t *offset, size_t count);
DESCRIPTION
파일 디스크립터와 다른 것으로 데이터를 복사할수 있다.
하나의 파일 디스크립터나 두개의 파일디스크립터중에 소켓이 될수도 있다.
in_fd는 파일을 열어서 읽을 파일 디스크립터이고 out_fd를 파일을 열어서 쓸 파일 디스크립터이다.
offset은 sendfile()에서 읽기 시작할 입력 파일의 위치를 가르키고 있는 변수 의 포인터이다.
sendfile()이 리턴할때 읽은 마지막 바이트의 offset으로 설정된다.
count는 파일 디스크립터 사이에 복사를 실행한 횟수이다.
sendfile()은 유저공간으로부터 데이터를 전송시간이 필요없다. 왜냐하면 복사는 커널내부에서 동작한다.
RETURN VALUE
전송에 성공하면 out_fd에 쓴 바이트 수를 리턴한다
-1은 ERROR이고 errno로 확인할수 있다.
ERRORS
EBADF : 입력파일이 열리지 않거나, 출력파일이 열리지 않는다.
EAGAIN : Non-blocking I/O는 O_NONBLOCK를 이용해서 선택할수 있다. 그리고 쓰기가 BLOCK되었다.
EINVAL : 파일 디스크립터가 잠겨있거나 유효하지 않다.
ENOMEM I: in_fd로부터 데이터를 읽기에 메모리가 충분하지 않다.
EIO : in_fd를 읽는 동안 특정화되지 않는 에러
EFAULT : 잘못된 주소
디스크와 디스크간 네트워크와 네트워크간 전송에 사용한다
디스크간 전송시는 copy 명령어와 동일하겠고
네트워크간 전송시는 read, write 함수의 역할과 동일하다
user area에 데이터 복사가 이뤄지지 않기 때문에 cpu를 덜 사용하기는 하지만
read, write보다 속도가 빠르지는 않다.
쉽게 풀면
read(fd, buffer, xxx ), write( fd, buffer, xxx )
에서 buffer에 복사하는 과정이 sendfile에서는 필요하지 않다.
첨언. 테스트용으로 file copy프로그램을 작성했으나
로컬 파일에 대한 copy는 실행되지 않았다.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
int main( int argc, char *argv[] )
{
off_t offset;
int fd1 = 0, fd2 = 0;
ssize_t ret = 1;
char path[1024];
struct stat stat_buf;
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
sprintf(path,"%s/%s","/data2/jchern/sendfile_test", argv[1]);
fd1 = open( path, O_RDONLY );
fstat(fd1,&stat_buf);
sprintf(path,"%s/%s","/data2/jchern/sendfile_test", argv[2]);
fd2 = open( path, O_WRONLY|O_CREAT, stat_buf.st_mode );
fstat(fd1,&stat_buf);
offset = 0;
if(( ret = sendfile( fd2, fd1, &offset, stat_buf.st_size ) ) == -1 )
{
switch(errno)
{
case EBADF :
printf("읽을 파일이 없거나 쓸 파일이 열리지 않았다\n" ); break;
case EAGAIN :
printf("난블락I/O가 선택되었는데 쓰기가 블락되었다\n"); break;
case EINVAL :
printf("파일 디스크립터가 유효하지 않거나 잠겨있다\n"); break;
case ENOMEM :
printf("in_fd로부터 읽기 위한 충분한 메모리가 없다\n"); break;
case EIO :
printf("in_fd에서 읽는 동안 불분명한 에러가 발생\n"); break;
case EFAULT :
printf("잘못된 주소\\n"); break;
}
}
close(fd1);
close(fd2);
return 0;
}