-
Linux Programming - File Descriptor(1)Tech/Development 2021. 5. 21. 00:49반응형
Everything is a file
파일은 Linux에서 가장 기본적이면서도 중요한 개념입니다. Linux에서는 거의 모든 객체를 파일로 관리하기에 Linux는 모든 것이 파일이다 라고 말할 수도 있죠. 예를 들어, 키보드를 통해 데이터를 입력하는 행위도 키보다를 나타내는 특정 파일에서부터 데이터를 읽어오는 행위라고 볼 수 있습니다. 디스플레이에 데이터가 출력되는 것은, 디스플레이라는 파일에 데이터를 쓰는 행위로 볼 수 있겠죠.
File Descriptor
시스템에서 파일을 사용할 때 파일명이 단순하면 상관 없겠지만, 파일의 이름이 길고 복잡하다면 사용할 때마다 복잡한 파일명을 계속 참조해야만 합니다. 불편함도 따르고 자원이 낭비되겠죠. 이에 나온 개념이, '파일디스크립터(File Descriptor)'입니다.
파일 디스크립터는 'Non-negative integer' 값으로 음수가 아닌 0과 양수인 정수 값을 가집니다. 간단히 말해서, index와 같은 개념이라고 볼 수도 있습니다. 프로세스가 실행되어 특정 파일을 Open할 때마다 프로세스는 자신의 파일 디스크립터 테이블에 파일 디스크립터 숫자를 할당하게 됩니다. 할당할 때는 사용하지 않는 가장 작은 값을 할당해주며, 이후 프로세스가 다시 파일에 접근할 때는 해당하는 파일 디스크립터 값을 통해 파일을 사용할 수 있게 됩니다.
파일 디스크립터가 생성될 때 0과 양수인 정수 값으로 생성된다고 하였지만, 추가적인 규칙이 있습니다. 첫 번째는 0~2 이외의 가장 작은 값이 할당된다는 것입니다. 프로세스가 메모리에 탑재되어 실행될 때는 기본적으로 할당되는 파일 디스크립터가 있습니다. 그 파일 디스크럽터는 다음과 같습니다. 0(표준입력, stdin), 1(표준출력, stdout), 2(표준에러, stderr)이 정의되어 있습니다. 이렇게 미리 정의 하는 이유는, 프로세스와 실행환경 사이의 소통을 원활하게 하기 위해 미리 연결할 필요가 있기 때문인 것이죠.
두 번째로는, 0부터 OPEN_MAX까지의 값을 가질 수 있다는 것입니다. OPEN_MAX 값은, ulimit 명령어를 통해 확인해볼 수 있고 open_files를 통해 확인할 수 있습니다. 좌측은 Soft limit이고, 우측인 Hard limit입니다. 해당 옵션은, 하나의 프로세스에 대해서 할당할 자원량의 한계를 설정하는 것으로, 다중 속성을 기본으로 하는 Linux 시스템의 과부하를 막아주는 유용한 설정입니다. Soft limit는 사용자가 해당 수치를 초과했을 때 시스템에서 경고 메시지를 뿌리는 정도의 Alert을 발생시키는 가이드라인이고, Hard limit의 경우에는 절대 초과할 수 없는 절대치를 말하는 것입니다. 물론, Soft limit나 Hard limit는 수정 가능하기에 적절히 조정해주는 게 좋습니다. 참고로, 플랫폼마다 설정 값마다 해당 수치가 다릅니다.
다음은, 파일 디스크립터를 실제로 확인할 수 있는 명령어 입니다. 우선, 어떤 프로세스의 파일 디스크립터를 살펴볼지 ps -ef 명령어를 통해 확인합니다. 참고로 ps는 실행 중인 프로세스의 목록을 보는 명령어이며, -e 는 실행 중인 프로세스의 정보를, -f는 프로세스에 대한 자세한 정보를 출력하는 옵션입니다(-F의 경우, 더욱 더 자세한 정보)
sudo ls -l /proc/[#PID]/fd 를 통해 원하는 프로세스의 파일 디스크립터를 확인합니다. 아래를 보면, 0과 1의 경우 /dev/null에 연결되어 있는데, 이는 작업의 출력되는 결과를 보고 싶지 않을 때 사용하는 것으로 출력을 버릴 때 사용합니다(/dev/null은 항상 비어있는 파일이며, /dev/null에 전송된 데이터는 버려진다). 무튼, 프로세스 1126의 파일 디스크립터 목록은 0~10까지 지정되어 있습니다. 해당 목록은 파일 디스크립터의 집합으로 파일 디스크립터 테이블이라고도 불립니다. 하단 화면을 통해 알 수 있는 것은, 프로세스 마다 하나의 파일 디스크립터 테이블을 가진다는 것입니다. 참고로, 파일 스크립터는 위에서 말한 것처럼 파일을 Open 하게 되면서 생성이 되고, 파일 디스크립터를 삭제하는 것은 파일을 Close하면 된다.
마지막으로, 파일 디스크립터에 대해 더 자세히 알아보기 위해 직접 Linux Programming을 진행합니다. 하단의 코드에서 fd1과 fd2는 같은 파일을 Open하였음에도 다른 파일 디스크립터를 지녔음을 확인할 수 있는 예제입니다. 만약, 같은 파일 디스크립터를 지녔다면, fd1 출력 이후 fd2를 Read하여 출력할 때는, File Offset 값인 buf를 통해 'helloworld'가 아닌 그 다음 줄인 'linuxworld'라는 텍스트가 출력되었을 것입니다. 참고로 하단의 예제에서는, \n 때문에 '\nlinuxworl'가 출력되었습니다.
C언어 참고사항 : 1) 출력하고자 하는 텍스트의 길이가 10임에도 11로 char을 할당하는 이유는, 문자열의 끝을 의미하는 문자인 '\0'이 삽입되어야 하기 때문입니다. 해당 문자는 Null 문자라고도 불리며, 아스키 코드값 0에 해당합니다. 이는 문자가 깨지는 것을 방지하기 위해 넣어집니다. 2) int main(int argc, char **argv[]), 우선 main 함수는 프로그램에서 최초로 실행되는 곳이며, 매개변수는 함수를 호출할 때 전달되는 데이터를 의미합니다. main() 함수의 매개변수인 argc는 main() 함수에 전달되는 데이터의 개수를 의미합니다. char **argv[]는 함수에 전달되는 실제 데이터로 char형 포인터 배열로 구성되어 있습니다. 첫 번째 문자열은 프로그램의 실행 경로를 나타냅니다.
반응형'Tech > Development' 카테고리의 다른 글
Linux Programming - C언어 VScode 설정(for Mac) (0) 2021.05.22 Linux Programming - File Descriptor(2) (0) 2021.05.22 Golang #3 - Interface (0) 2021.03.01 Golang #2 - Method vs Function (0) 2021.03.01 Golang #1 - Map (0) 2021.02.14