파일 I/O: 범용 I/O 모델

System Program/I/O 2013. 10. 10. 07:28

1. 입출력 관련 시스템 호출

 

I/O를 수행하는 모든 시스템 호출은 파일 디스크립터라는 음이 아닌 정수를 통해 열려 있는 파일을 참조한다.

파일 디스크립터는 파이프, FIFO, 소켓, 터미널, 디바이스, 일반 파일 등 종류에 상관없이 모든 열려 있는 파일을 참조한다.

유닉스/리눅스의 I/O처리 철학이 모든 입출력 장치를 파일로 관주하는 맥락과 일치한다.

 

2. 표준 파일 디스트립터

 

 파일 디스트립터

 목적

POSIX 이름 

STDIO STREAM 

 0

 표준 입력

 STDIN_FILENO

 stdin

 1

 표준 출력

 STDOUT_FILENO

 stdout

 2

 표준 에러

 STDERR_FILENO

 stderr

 

위의 세 디스트립터는 항상 열려 있는데, 이유는 쉘을 통해 실행되는 프로그램은 쉘로부터 항상 열려있는 세개의 디스트립터를 상속받기 때문이다. 이 개념은 매우 중요하다. 네트워크나 이와 유사한 프로그램에서 dup()함수를 통해서 열려 있는 소켓의 디스크립터의 번호를 재 정의할 때 이 개념이 정립되어 있어야지 이해할 수 있다.

또한 프로그램에서 파일 디스트립터의 숫자를 통해서 파일을 처리할 수 있으나, 가능하면 <unistd.h>에 정의된 POSIX 표준 이름을 쓰는 편이 좋다.

 

2.1. 파일 열기: open()

 

#incldue <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags, ... /* mode_t mode */);

                                                   성공하면 파일 디스크립터를 리턴하고, 에러가 발생하면 -1을 리턴한다.

 

open()함수가 리턴하는 파일 디스크립터는 항상 프로세스에서 사용하지 않는 가장 작은 수를 리턴한다. 따라서 기본적으로 앞에서 설명했듯이 0 ~ 2는 사용하고 있으므로 상식적으로 3부터 차례로 리턴될 것이다.

이런 동작 방식에 대한 이해를 하는 것이 매우 중요하다.

 

open()함수에서 사용하는 flags에 대해서 아래와 같이 정리할 수 있다.

 

 플래그

목적 

표준 

 O_RDONLY

 읽기 전용으로 연다

 v3

 OWRONLY

 쓰기 전용으로 연다

 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 데이터 무결성을 제공한다

리눅스 : 2.6.33부터

O_NONBLOCK

비블로킹 모드로 연다

v3

O_SYNC

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

v3

 

■ open() error 값

 

에러가 발생하면 '-1'을 리턴하고, errno를 보면 에러의 원인을 알 수 있다. 발생 가능한 에러에 대해서 살펴본다.

 

 EACCES

호출하는 프로세스가 flags에 지정한 모드로 파일에 접근할 수 없다 

 EISDIR

지정된 파일이 디렉토리이고, 호출자가 쓰기용으로 열려고 했다

 EMFILE

파일디스크립터의 개수가 프로세스의 한도를 넘었다

 ENFILE

열린 파일의 개수가 시스템 전체 한도에 도달했다 

 ENOENT

지정된 파일이 존재하지 않고, O_CREAT가 지정되지 않았거나, 지정되었더라도 pathname으로 지정된 경로명이 존재하지 않는다

 EROFS

파일이 읽기전용인데 호출자 쓰기용으로 열려고 했다

 ETXBSY

지정된 파일이 실행 중에 있다.  

 

2.2. create() 시스템 호출

 

#include <fcntl.h>

int create(const char *pathname, mode_t mode );

                                                   성공하면 파일 디스크립터를 리턴하고, 에러가 발생하면 -1을 리턴한다.

 

open()과 동일한 기능이지만 현재는 사용되지 않는다.

 

2.3. read() 시스템 호출

 

#include <unistd.h>

ssize_t read(int fd, void *buffer, size_t count);

                                                   읽은 바이트 수를 리턴한다. EOF인 경우에는 0을 에러가 발생하면 -1을 리턴

 

위의 함수에서 size_t count는 매개변수는 읽을 최대 바이트 수를 지정한다.

 

2.4. write() 시스템 호출

 

#include <unistd.h>

ssize_t write(int fd, void *buffer, size_t count);

                                                   쓴 바이트 수를 리턴한다. 에러가 발생하면 -1을 리턴

 

디스크에서 I/O를 수행할 때 write()가 성공하였다고해서 데이터가 디스크로 전송되었다고 보증할 수는 없다. 커널의 디스크 I/O 동작에 대해서 버퍼링을 수행하기 때문이다. 자세한 내용은 차 후에 보도록 한다.

 

2.5. close() 시스템 호출

 

#include <unistd.h>

int close(int fd);

                                                   성공하면 0을 에러가 발생하면 -1을 리턴

 

2.6. lseek() 시스템 호출

 

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

                                                   성공하면 새로운 파일 오프셋을 리턴하고, 에러가 발생하면 -1을 리턴

 

위에서 offset은 바이트 단위로 설정하여 파일 시작에서 몇 바이트 떨어져 있는 지점을 지정하기 위해서 사용된다.

뒤의 whence는 아래와 같은 의미를 갖는다. 이 함수는 모든 종류의 디바이스에 적용할 수 있는 것은 아니다. 일반적으로

파일에 적용될 수 있다고 보면 된다.

 

  • SEEK_SET : 파일 오프셋 계산의 기준점이 파일의 시작점으로 설정 
  • SEEK_CUR : 파일 오프셋의 기준점을 현재 파일 오프셋으로 설정
  • SEEK_END : 파일 오프셋의 기준점을 파일 끝으로 설정

 

2.7. ioctl() 시스템 호출

 

#include <sys/ioctl.h>

int ioctl(int fd, int request, ... /*argp */);

                                                   성공하면 request에 따라 다르다, 에러가 발생하면 -1을 리턴

 

위의 사용은 일반적으로 디바이스 드라이버 응용에서 많이 사용하는 방식이다. 커널쪽에 ioctl의 request에 대응하는 코드가 별도로 구현되야 한다.

즉 위의 함수는 앞서 설명한 범용 I/O 모델에서 벗어나는 파일과 디바이스 오퍼레이션을 위한 범용 메카리즘이다.  

 

3. 기타

 

커널 2.6.22부터는 /proc/PID/fdinfo 디렉토리에서 각 프로세스에 대한 파일 디스크립터 정보를 얻을 수 있다.

자세한 내용은 참고서적 144Page 참조

 

 

 

 

 

'System Program > I/O' 카테고리의 다른 글

고급 I/O 모델 : poll() 함수  (0) 2014.03.12
고급 I/O 모델 : select() 시스템 호출  (0) 2014.03.01
access() 함수  (0) 2014.02.26
stat() 관련 함수  (0) 2014.02.26
fcntl() 함수  (0) 2014.02.21
: