정보공간_1

[2기 부산 배보람] 리눅스 파일 I/O와 파일 디스크립터 본문

IT 놀이터/Elite Member Tech & Talk

[2기 부산 배보람] 리눅스 파일 I/O와 파일 디스크립터

알 수 없는 사용자 2012. 10. 20. 20:17

오늘은 리눅스 시스템 프로그래밍의 출발 점이라 볼수 있는 파일 I/O와 파일디스크립터에 대해 살펴 보겠습니다.


1. 개요

 컴퓨터 프로그래밍 분야에서 파일 서술자(file descriptor) 또는 파일 기술자는 특정한 파일에 접근하기 위한 추상적인 키이다. 이 용어는 일반적으로 POSIX 운영 체제에 쓰인다. 마이크로소프트 윈도와 C 표준 입출력 라이브러리 환경에서 "파일 핸들"(file handle)이라는 말이 선호되지만 후자의 경우 기술적으로 다른 객체이다.

POSIX에서 파일 서술자는 정수, 곧 C형 int를 말한다. 모든 프로세스가 갖추어야 하는 표준 POSIX 파일 서술자는 다음과 같이 세 개가 있다. 

파일 디스크립터 

목적 

POSIX  이름 

stdio 스트림 

 0  

 표준 입력 

 STDIN_FILENO 

 stdin 

 1 

 표준 출력 

 STDOUT_FILENO 

 stdout 

 2 

 표준 에러 

 STDERR_FILENO 

 stderr 

 *wikipedia 참조


리눅스에서 I/O를 수행하는 모든 시스템 호출은 파일 디스크립터라는 음이 아닌 정수를 통해 열려 있는 파일을 참조 합니다. 파일 디스크립터는 파이프 FIFO,소켓, 터미널, 디바이스, 일반 파일 등 종류에 상관 없이 모든 열러 있는 파일을 참조 할때 사용 합니다.

 위의 표의 세가지 표준 파일 디스크립터는 프로그램이 시작될 때 쉘로부터 프로그램이 디스크립터의 복사본을 물려 받습니다.


2. 네가지 핵심 시스템 콜

다음은 파일I/O를 위한 네가지 핵심 시스템 콜 입니다. 

  • fd = open(pathname, flags, mode) 

    open() 은 지정된 패스의 파일을 열고 이후의 호출에서 참조 할 때 쓸 파일 디스크립터를 리턴 합니다. 

    pathname - 파일 패스

    flags - 읽기,쓰기 둘다를 위해 열지 지정

    플래그 

     목적 

     SUS? 

     O_RDONLY

     읽기 전용으로 연다. 

     v3 

     O_WRONLY  

     쓰기 전용으로 연다.  

     v3

     O_RDWR

     읽고 쓰기용으로 연다. 

     v3

     O_CLOEXEC 

     실행 시 닫기 플래그를 설정한다. 

     v4 

     O_CREAT 

     파일이 존재하지 않으면 새로 만든다.

     v3
     O_DIRECT

     파일 I/O가 버퍼 캐시를 우회한다. 

     

     O_DIRECTORY

     pathname이 디렉토리가 아니면 실패한다. 

     v4

     O_EXCL

     O_CREAT와 함께, 배타적으로 파일을 만든다.

     v3 

     O_LARGEFILE

     32비트 시스템에서 큰 파일을 열 때 쓴다. 

     
     O_NOATIME

     read() 시에 파일 최종 접근시간을 갱신하지 않는다. 

     
     O_NOCTTY

     pathname으로 제어 터미널이 되지 않게 한다.  

     v3

     O_NOFOLLOW

     심볼릭 링크를 역참조하지 않는다. 

     v4 

     O_TRUNC

     기존 파일의 길이를 0으로 설정한다. 

     v3

     O_APPEND 언제나 파일의 끝에 추가해서 쓴다.   v3

     O_ASYNC

     I/O가 가능해 지면 시그널을 보낸다. 

     
     O_DSYNC 동기 I/O 데이터 무결성을 제공한다.  

     v3

     O_NONBLOCK

     비블로킹 모드로 연다. 

     v3
     O_SYNC 파일 쓰기를 동기 모드로 설정한다. 

     v3


    mode - 파일에 부여할 권한을 지정, open()이 파일을 만들지 않을 경우 인자는 무시 

     접근 모드 

    설명 

     O_RDONLY 

     읽기 전용으로 파일을 연다. 

     O_WRONLY 

     쓰기 전용으로 파일을 연다. 

     O_RDWR 

     읽고 쓰기용으로 파일을 연다.



  • numread = read(fd, buffer, count)

    read()는 fd가 가리키는 파일에서 최대 count만큼의 바이트를 읽어 buffer에 저장하고, 실제 읽어 드린 바이트를 리턴합니다. 파일의 끝에서 더 읽으려고 한 경우에는 0을 리턴하고, 에러 발생시에는 -1을 리턴합니다. 

     

    fd - 파일 디스크립터

    buffer - 읽어 드린 데이터를 저장할 공간

    count - 파일 디스크립터가 가리키는 파일에서 읽어드릴 바이트 길이


  • numwritten = write(fd,buffer,count)

    write()는 buffer에 서 최대 count바이트를 fd가 가리키는 파일에 쓰고 실제로 쓴 바이트를 리턴합니다. 실제로 쓴 바이트 수는 count보다 작을 수 있고, 디스크 파일의 경우 디스크가 가득 찼거나, 파일 크기에 대한 프로세스 자원 한도에 다다랐을 경우 등에 발생 할 수 있습니다. 디스크 파일에 I/O를 수행 할 때는, wirte()가 성공했다고 해서 데이터가 디스크로 전송됐다고 보장할 수는 없습니다.


    fd - 파일 디스크립터

    buffer - 파일에 쓸 데이터를 담고 있는 공간

    count - buffer가 가지고 있는 데이터중 파일 디스크립터가 가리키는 파일에 쓸 데이터 길이 


  • status = close(fd)

    모든 I/O를 마친 뒤에파일 디스크립터 fd와 관련 커널 자원을 해제하기 위해 호출합니다. 

    성공하면 0을 리턴하고 에러가 발생하면 -1을 리턴합니다. 일반적으로 불필요한 파일 디스크립터는 명시적으로 닫아주는 것이 좋은 습관입니다. 특히 오래동안 프로세스가 활동 하는 쉘이나 서버프로그램에서는 특히 중요한 이슈 입니다. 


이 네가지의 핵심 시스템 콜은 범용성을 가지게 디자인 되어 있습니다.

각 파일 시스템과 디바이스 드라이버가 위의 네가지 시스템 콜을 공통으로 사용해서 범용적으로 프로그램이 동작 하게 만들어져 있습니다. 그외에 특유의 기능을 써야 할 때에는 다목적 시스템 호출인 ioctl()을 사용 하면 됩니다. 

더욱 자세한 설명은 여기서 확인 가능하십니다. 

 

3. 예제 

다음은 위의 네가지 시스템 콜을 이용해서 cp 명령을 흉내낸 간단한 예제 코드 입니다. 



해당 코드를 컴파일 한 후 

./copy file1 file2 

라고 실행하면 잘 동작하는 것을 확인 할 수 있습니다. 

또한 ./copy file1 /dev/tty 라고 실행하면 터미널에 그대로 출력이 되는 모습을 확인 할 수 있을 것입니다. ^^ 


리눅스의 I/O가 범용성을 가지도록 디자인 되어 있기 때문에 하나의 소스로 이런 여러가지 입출력이 가능 한 것 입니다. 

파일 시스템이나 디바이스에 고유한 구체적인 사항은 커널에서 처리 하기때문에 응용프로그램에선 일반 적으로 그런 것까지 신경 쓸 필요가 없는것이죠 ^^ 


4.마치며

 리눅스 시스템 프로그래밍의 첫 걸음 이라 할 수 있는 파일 I/O의 기초와 파일 디스크립터에대해 간략하게 알아 보았습니다. 

이런 것들을 응용해서 리눅스의 명령어를 흉내내 보거나 나만의 명령어를 만들어 보면 더 욱 재미 있을 것 입니다. 내가 흉내내서 만든 명령어 코드와 실제 리눅스에서 사용되는 명령어의 코드를 비교해 보는것도 공부에 많은 도움이 될 거라 생각합니다. ^^ 

추가로  프로그램으로 전달 받을 옵션을 해석할때 쓰는 유용하게 쓸 수 있는 getopt() 함수가 있는데 이것에 대한 정보는 여기서 자세하게 얻을수 있습니다. 


 


[참고 문헌 및 웹] 

- 리눅스 API의 모든 것 vol1 기초 리눅스 API , 마이클 커리크스 지음  

-http://www.gnu.org/software/libc/manual/html_node/Low_002dLevel-I_002fO.html