C언어

sendfile

고요한하늘... 2009. 8. 5. 20:36

#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;
}