2021. 5. 16. 00:00ㆍC & C++
파일 디스크립터란?
파일을 대표하기 위해 시스템에서 할당받은 음수가 아닌 (unsigned) 0 혹은 양수의 값
프로세스에서 열린 파일의 목록을 관리하기 위한 테이블의 인덱스
POSIX 환경에서 일반적인 정규(Regular)파일, 디렉토리(Directory), 소켓(Socket), 파이프(PIPE), 객체(Object)등은 전부 파일로 관리되며, 이들에 접근하기 위해 파일 디스크립터라는 개념을 통해 접근한다.
응용 프로세서가 파일을 열거나 생성, 수정하게 되면 정수로 된 파일 디스크럽터를 할당받게 되는데, 이 부분에서 할당받은 파일 디스크럽터는 이후에 일어나는 모든 read(읽기), write(쓰기), fcntl(제어), cloese(종료)에서 해당 파일을 가리키는 인덱스로 사용되게 된다.
기본 할당 파일 디스크립터
기본적으로
- 0 : stdin(표준 입력) // unistd.h의 매크로 상수 - STDIN_FILENO
- 1 : stdout(표준 출력) // STDOUT_FILENO
- 2 : stderr(표준 에러) // STDERR_FILENO
이렇게 표준 디스크럽터가 0 - 2까지 상수로써 존재하므로 실제 우리가 생성, 관리하는 파일 디스크럽터는 3부터 순차적으로 할당을 받게 된다.
시작은 0부터인데, 끝은 어디까지?
일반적으로 파일 디스크럽터는 0부터 OPEN_MAX라는 매크로 상수의 수 까지 생성이 가능한데, OPEN_MAX 값은 프로그램이 실행되는 환경에 따라 다르다.
limits.h 또는 stdio.h의 FOPENMAX(윈도우)에서 확인할 수 있으며, 맥의 경우 터미널에서 getconf OPEN_MAX를 통해 확인 가능함.
허나 실제로는 OPEN_MAX까지 fit하게 전부 사용이 불가하니, 적당히 여유를 두고 메모리 관리, 프로세스 관리를 해주어야한다.
파일 디스크립터 확인
파일 디스크립터를 확인하기 위해 OPEN()함수를 사용해보쟈
OPEN 함수는 파일의 생성, 제어 및 파일을 열기위한 fcntl.h에 정의되어 있다.
fcntl.h에는 creat(), fcntl(), open()함수가 있다.
// open() - 파일 열기
#include <fcntl.h>
int open(const char *path, int oflag, ...);
open 함수의 프로토 타입이며 parameter로는 파일 경로, 파일 열기 속성, 가변인자들이 있다.
해당 파일은 새로운 파일 디스크립터를 생성하고, 파일 경로 path와 연결시킨다. 파일이 열리면 생성된 파일 디스크립터를 반환하며, 파일 오프셋은 파일의 시작에 위치한다.
여기서 파일의 상태와 접근 모드는 oflag 인자에 의해 결정되어진다.
O_flag에는 O_CREAT, O_APPEND 또는 파일 접근을 위한 O_RDONLY, O_WRONLY, O_RDWR 등이 쓰인다.
// DESCRIPTOR 확인 연습 코드
// close()
#include <unistd.h>
// open()
#include <fcntl.h>
// printf()
#include <stdio.h>
int main(void)
{
int fd, fd2;
fd = open("test.txt", O_RDONLY);
fd2 = open("test2.txt", O_RDONLY);
if (fd == -1 || fd2 == -1)
return (printf("ERROR\n"));
printf("FILE_DESCRIPTOR : %d\n", fd);
printf("FILE_DESCRIPTOR : %d\n", fd2);
close(fd);
close(fd2);
return (0);
}
변수 fd와 fd2는 각각 test와 test2 파일을 열고 디스크립터 값을 할당받아 값을 출력한 후 종료시키는 절차의 코드이다.
결과
'3부터 순차적으로 2개의 파일 디스크럽터를 할당한 후 출력한다.
반대로 할당 실패의 예를 확인해보자.
// close()
#include <unistd.h>
// open()
#include <fcntl.h>
// printf()
#include <stdio.h>
int main(void)
{
int fd_err;
fd_err = open("asd.txt", O_RDONLY);
// file_descriptor가 할당 실패하였을 때 에러메세지 출력하며 종료
if (fd_err == -1)
return (printf("ERROR\n"));
printf("FILE_DESCRIPTOR : %d\n", fd_err);
close(fd_err);
return (0);
}
결과
이렇듯, 파일 디스크립터는 C에서의 포인터처럼 파일의 경로로 접근해 파일을 읽고 쓰는 등의 작업을 수행할 수 있게한다.
예를 들어 위의 코드에서 파일 디스크립터로 3을 할당받았다면, 프로세스의 파일 테이블 중 3번 인덱스로 가 작업을 할 수 있게 한다는 것
FD TABLE
- File Descriptor 테이블은 각 Fd Flag와 File table pointer를 가짐, Fd가 단순 숫자인 이유는 file 테이블을 가리키는 단순 인덱스이기 때문이다.
- File Table은 읽기 전용, 쓰기 전용 등의 file mode와 i-node 테이블의 포인터를 지닌다.
- i-node는 파일을 기술하는 데이터 상의 데이터 구조로써, 파일의 데이터 블록이 디스크 상의 어느 주소에 위치하고 있는가와 같은 파일에 대한 정보를 가지고 있다. 각각의 i-node 들은 i-node number라는 고유 넘버를 가지고 있어, 파일을 식별할 때에 사용된다.
- I-node는 터미널에서 ls -i 명령어를 통해 확인할 수 있다.
FD의 복제
File descriptor는 dup()함수를 통해 복제할 수 있는데, 복제 시 이미 파일 디스크립터가 열려있다면 다시 새로운 인덱스를 할당한다.
#include "stdlib.h"
#include "stdio.h"
#include "fcntl.h"
#include "unistd.h"
int main()
{
int fd, fd2, fdup;
fd = open("test.txt", O_RDONLY);
fd2 = open("test.txt", O_RDONLY);
printf("fd : %d, fd2 : %d\n", fd, fd2);
printf("fd2 = dup(fd)\n");
fd2 = dup(fd);
printf("fd : %d, fd2 : %d\n", fd, fd2);
close(fd);
close(fd2);
return 0;
}
위의 함수를 실행하면 fd가 처음에 3을 할당받고, fd2가 두번째로 4를 할당받게된다.
그 후 dup()함수를 통해 fd 변수를 fd2에 복제하면, fd가 가리키는 파일 테이블의 주소를 새로운 디스크립터에 복제하게 된다.
'C & C++' 카테고리의 다른 글
C++ ) Template (0) | 2022.09.09 |
---|