파일 디스크립터(File Descriptor)
파일 디스크립터(File Descriptor, FD)는 운영체제가 프로세스가 접근할 수 있는 파일, 소켓, 파이프 등을 구분하기 위해 부여하는 정수 값이다. 리눅스나 유닉스 계열 시스템에서 자주 사용되며, 시스템 콜(system call)을 통해 파일이나 네트워크 자원에 접근할 때 핵심적으로 활용된다.
간단히 말해, 프로세스 입장에서 파일 디스크립터는 파일을 가리키는 핸들(handle) 역할을 한다. 이 정수값을 통해 프로세스는 운영체제에게 어떤 파일에 어떤 작업을 수행할지를 요청할 수 있다.
프로세스가 시작되면, 기본적으로 세 개의 파일 디스크립터가 자동으로 열리게 된다.
파일 디스크립터 번호 | 이름 | 설명 |
0 | stdin | 표준 입력 |
1 | stdout | 표준 출력 |
2 | stderr | 표준 오류 출력 |
예를 들어, printf() 함수는 내부적으로 stdout, 즉 파일 디스크립터 1번을 사용하여 화면에 출력을 한다. 마찬가지로 scanf()는 stdin, 즉 0번 디스크립터를 통해 입력을 받는다.
예제
C 언어나 Python에서는 파일을 열 때 내부적으로 파일 디스크립터가 생성된다. 다음은 C 언어에서 open() 시스템 콜을 사용하는 예이다.
C
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("파일 열기 실패");
return 1;
}
printf("할당된 파일 디스크립터: %d\n", fd);
close(fd);
return 0;
}
Python
# 파일 열기
f = open("example.txt", "r")
# 파일 디스크립터 확인
print(f"파일 디스크립터: {f.fileno()}")
# 파일 닫기
f.close()
이 예제는 example.txt 파일을 읽기 전용으로 열고, 할당된 파일 디스크립터를 출력한 후 닫는 코드이다.
아래는 리눅스 커맨드를 이용하여 파일 디스크립터를 확인하는 방법이다.
실행중인 프로세스 PID 확인
ps aux | grep python
PID로 해당 프로세스의 FD 디렉토리 확인
ls -l /proc/12345/fd/
여기서 12345는 해당 Python 프로세스의 PID이다. 이 디렉토리에는 해당 프로세스가 열고 있는 모든 파일 디스크립터가 심볼릭 링크로 나열된다. 다음과 같은 형태의 출력이 나올 것이다.
lrwx------ 1 user user 64 May 13 10:15 0 -> /dev/pts/0
lrwx------ 1 user user 64 May 13 10:15 1 -> /dev/pts/0
lrwx------ 1 user user 64 May 13 10:15 2 -> /dev/pts/0
lr-x------ 1 user user 64 May 13 10:15 3 -> /home/user/example.txt
여기서 0, 1, 2는 각각 stdin, stdout, stderr을 의미하며, 3은 example.txt를 open()해서 열었을 때 생성된 파일 디스크립터를 의미한다.
파일 디스크립터와 리소스 관리
운영체제는 하나의 프로세스에 대해 열 수 있는 파일 디스크립터 수에 제한을 둔다. 이 제한은 ulimit -n 명령어를 통해 확인하거나 변경할 수 있다. 파일 디스크립터를 적절히 닫지 않으면 리소스 누수로 이어져 시스템 전체의 안정성을 해칠 수 있으므로, 파일을 사용한 후 반드시 close() 함수를 호출하여 반환하는 것이 중요하다.
파일 디스크립터와 소켓
네트워크 프로그래밍에서도 파일 디스크립터는 동일하게 사용된다. socket() 함수로 생성된 소켓도 파일 디스크립터로 관리되며, read(), write() 또는 select(), poll() 같은 함수에서 활용된다.
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
이와 같이 생성된 소켓도 일반 파일과 동일하게 정수값(파일 디스크립터)을 가진다.