File Descriptor (파일 디스크립터) [출처: http://dev.plusblog.co.kr/22]
1. 파일 디스크립터
- 시스템으로부터 할당 받은 파일을 대표하는 0이 아닌 정수 값
- 프로세스에서 열린 파일의 목록을 관리하는 테이블의 인덱스
흔히 유닉스 시스템에서 모든 것은 파일이라고 한다. 일반적인 정규파일(Regular File)에서부터 디렉토리(Directory), 소켓(Socket), 파이프(PIPE), 블록 디바이스, 캐릭터 디바이스 등등 모든 객체들은 파일로써 관리된다. 유닉스 시스템에서 프로세스가 이 파일들을 접근할 때에 파일 디스크립터(File Descriptor)라는 개념을 이용한다.
파일 디스크립터는 '0이 아닌 정수', 'Non-negative Integer' 값이다. 즉, 음수가 아닌 0과 양수인 정수 값을 갖는다. (unsigned int 값이라고 보면 된다.) 프로세스가 실행 중에 파일을 Open 하면 커널은 해당 프로세스의 파일 디스크립터 숫자 중에 사용하지 않는 가장 작은 값을 할당해 준다. 그 다음 프로세스가 열려있는 파일에 시스템 콜을 이용해서 접근 할 때, FD 값을 이용해 파일을 지칭 할 수 있다.
프로그램이 프로세스로 메모리에서 실행을 시작 할 때, 기본적으로 할당되는 파일 디스크립터들이 있다. 바로 표준 입력(Standard Input), 표준 출력(Standard Output), 표준 에러(Standard Error)이다. 이 들에게 각각 0, 1, 2 라는 정수가 할당되며, POSIX 표준에서는 STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO로 참조된다. 이 매크로는 <unistd.h> 헤더 파일에서 찾아 볼 수 있다.
0이 아닌 정수로 표현되는 파일 디스크립터는 0 ~ OPEN_MAX 까지의 값을 가질 수 있으며, OPEN_MAX 값은 플랫폼에 따라 다르다.
파일 디스크립터는 위 그림을 보면서 개념 정리를 하면 좋다. 파일 디스크립터가 단순히 숫자인 이유는 프로세스가 유지하고 있는 FD 테이블의 인덱스이기 때문이다. FD 3번이라는 의미는 FD 테이블의 3번 항목이 가리키는 파일이라는 의미이다. FD 테이블의 각 항목은 FD 플래그와 파일 테이블로의 포인터를 가지고 있다. 이 포인터를 이용하여 FD 를 통해 시스템의 파일을 참조 할 수 있는 것이다.
프로세스는 이런 FD 테이블과 파일 테이블의 정보를 직접 고칠 수 없으며, 반드시 커널을 통해서 수정을 해야 한다.
파일 디스크립터란 뭔가?! [출처: http://z-man.tistory.com/151]
파일 디스크립터는 파이프, FIFO, 소켓, 터미널, 디바이스, 일반파일 등 종류에 상관없이 모든 열려있는 파일을 참조할때 쓴다.
파일디스크립터 | 목적 | POSIX 이름 | stdio 스트림 |
0 | 표준 입력 | STDIN_FILENO | stdin |
1 | 표준 출력 | STDOUT_FILENO | stdout |
2 | 표준 에러 | STDERR_FILENO | stderr |
표에 있는 3가지 디스크립터는 프로그램이 시작할때 셸의 디스크립터의 복사본을 상속 받고, 셸은 보통 3가지 파일 디스크립터가 언제나 열린채로 동작 한다.
프로그램에서 파일 디스크립터를 참조할때는 번호(0,1,2)를 쓸 수도 있지만 가능하면 "UNISTD.H"에 정의된 POSIX 이름을 쓰는편이 좋다..
1 2 3 4 5 6 7 8 | fd = open( pathname, flags, mode ) // pathname 이 가리키는 파일을 열고 열린 파일을 이후 호출에서 참조 할 때 쓸 파일 디스크립터를 리턴. // flags는 파일을 읽기, 쓰기, 둘다를 위해 열지를 지정 한다. numread = read( fd, buffer, count ) // fd가 가리키는 파일에서 최대 count 바이트를 읽어 buffer에 저장. numwritten = write( fd, buffer, count ) // 버퍼에서 최대 count 바이트를 fd가 가리키는 열려 있는 파일에 쓴다. status = close(fd) 모든 i/o 를 마친뒤 fd와 관련 커널 자원을 해제 한다. |
fd는 해당 프로세스의 open file 을 관리하는 구조체 배열의 index.
그 구조체의 index 가 가리키는 객체가 dentry 라는 객체이고, 그 dentry 객체는 또다시 해당 파일을 나타내는 inode 객체를 가리키게 됩니다.
커널 구조체중 struct files_struct 보시면 struct file fd_array 라는 배열이 있다.
실제로 open()을 통해 얻는 fd 는 저 구조체의 index 를 나타냅니다.
일반적으로 0, 1, 2 index 는 std-in/std-out/error 와 관련된 fd 로 미리 할당이되고, 보통 open()을 하게 되면 fd 값은 3이 됩니다.
3 번 index 로 test.txt 를 찾는 방법은
우선 fd_array[3] 이 pointing 하고 있는 file 구조체의 f_dentry 를 얻어오게됩니다. dentry 란 것은 directory entry 를 의미하는데, 리눅스에서 디렉토리에 접근을 빠르게 하기 위한 구조체로 사용하고 있습니다. open() 시스템 콜을 호출하게 되면, test.txt 가 존재하는 위치와 관련되어 dentry 구조체가 만들어집니다.
dentry 구조체는 관련된 inode 구조체를 가리키는 필드를 포함합니다.
따라서 open("test.txt',...) 함수로 호출된 파일은 test.txt 에 대한 dentry 생성, inode 생성(또는 읽음) 후에 해당 프로세스의 open 파일 관리 구조체인 files_struct 의 fd_array 의 비어있는 위치에 test.txt 의 dentry 를 포인팅하고 그 index 인 3을 넘겨주는 것입니다.
이후 사용자가 3번을 가지고 시스템 콜을 수행하게되면, 해당 프로세스의 files_struct 의 fd_array index 를 통해서 관련 inode에 접근할 수 있게 되는 것입니다.
파일 디스크립터와 열려 있는 파일의 관계
각 프로세스별로 커널은 open file descriptor table 을 갖고 있다. 테이블의 각 엔트리는 하나의 파일 디스크립터에 대한 동작 제어 플래그, 열린 파일을 가리키는 참조를 담고 있다.
open file description은 현재 파일의 offset, flag, 접근 모드, i/o 관련 설정, 파일의 i-node 객체를 가리키는 레퍼런스를 갖고 있다.
i-node는 파일 종류 (일반파일, 소켓, fifo)와 권한, lock 목록 포인터, 여러 파일 오퍼레이션과 다양한 파일 속성(크기, 타임스탬프등)을 갖고 있다.
만약 같은 open file description을 가리키는 2개의 fd는 offset값을 공유 한다.
'Major > Linux' 카테고리의 다른 글
리눅스 - Ext4 File System (0) | 2016.02.01 |
---|---|
리눅스 - 가상 파일 시스템 (0) | 2016.01.28 |
리눅스 - 파일 시스템 (0) | 2016.01.28 |
리눅스 - System Call (0) | 2016.01.28 |
리눅스 - 기초 (0) | 2016.01.28 |