2장부터 4장까지는 파일에 대해 다루는데, 2장에서는 파일 입출력의 기본을 알아보고 파일을 다루는 가장 기본적이고 간단한 방법인 시스템 콜(syscall)에 대해 이야기한다.
OS = Kernel+ Shell
- 커널은 운영체제의 핵심으로 운영체제가 수행하는 모든 것이 저장됨.
- 쉘은 리눅스 환경에서 일반적으로 쓰는 명령어들을 읽어들여 해석하고 결과를 출력해주는 역할을 함.
사용자 영역과 커널 영역이 나뉘어져 있고 각 영역엔 버퍼가 있음.
- syscall을 통해 파일 입출력을 하게 되면 커널을 통해 입출력을 수행함.
- 예를 들어 open() 이라는 시스템콜을 호출하면, kernel 모드에 들어가서 시스템 콜에 대한 명령어를 수행함.
파일을 읽고 쓰기 전에 open()이나 creat() 시스템 콜을 사용해서 파일을 열어야 한다.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open (const char *name, int flags);
int open(const char *name, int flags, mode_t mode);
name
인 파일을 파일 디스크립터에 맵핑하고, 성공하면 이 파일 디스크립터를 반환함.flags
flags
매개 변수에 비트 OR연산으로 값을 더 추가해서 열기 동작 변경 가능mode
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat (const char *name, mode_t mode);
가장 대표적인 읽기 메커니즘은 POSIX.1에 정의된 read() 시스템 콜을 사용하는 것.
#include <unistd.h>
ssize_t read (int fd, void *buf, size_t len);
len
바이트만큼 buf
로 읽어 들임.buf
에 쓴 바이트 숫자를 반환. 실패시 -1 반환.len
바이트만큼 읽지만, 읽을 데이터가 len
바이트 보다 더 적을 경우 더 적게 읽기도 함.파일에 데이터를 기록하기 위해 사용하는 가장 기본적이며 일반적인 시스템 콜은 write()임.
#include <unistd.h>
ssize_t write (int fd, const void *buf, size_t count);
count
바이트 만큼 파일 디스크립터 fd
가 참조하는 파일의 현재 파일 위치에 시작지점이 buf
인 내용을 기록.파일 디스크립터로 읽고 쓰는 작업을 마치고 나면 close() 시스템 콜을 이용해서 파일 맵핑을 끊어야 함.
#include <unistd.h>
int close (int fd);
fd
에 연관된 파일과의 맵핑을 해제하며 프로세스에서 파일을 떼어냄.코드를 입력하세요
파일 디스크립터에 연결된 파일의 오프셋을 특정 값으로 지정함.
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t pos, int origin);
origin
인자fd
의 파일 오프셋을 현재 오프셋에서 pos
를 더한 값으로 설정.fd
의 파일 오프셋을 현재 파일 크기에서 pos
를 더한 값으로 설정.fd
의 파일 오프셋을 pos
값으로 설정.애플리케이션에서 직접 데이터가 디스크에 기록되는 시점을 제어하고 싶을 때가 있음. 이런 때를 위해 리눅스 커널에서는 성능을 희생하는 대신 입출력을 동기화하는 옵션 제공.
#include <unistd.h>
int fsync (int fd);
fd
에 맵핑된 파일의 모든 변경점을 디스크에 기록.fd
는 반드시 쓰기 모드로 열려야 함.애플리케이션이 여러 개의 파일 디스크립터를 동시에 블록하고 그중 하나라도 블록되지 않고 읽고 쓸 준비가 되면 알려주는 기능. 어떤 파일 디스크립터에 이벤트가 발생했는 지 주기적으로 확인.
#include <sys/select.h>
int select (int n, fd_set *readfds, fd_set *writefds, fd_set, *exceptfds, struct timeval *timeout);
FD_CLR (int fd, fd_set *set);
FD_ISSET (int fd, fd_set *set);
FD_SET (int fd, fd_set *set);
FD_ZERO (fd_set *set);
readfds
: 데이터 읽기가 가능한지(블록되지 않고 read() 작업이 가능한지) 파악writefds
: 블록되지 않고 write() 작업이 가능한지 감시exceptfds
: 예외가 발생했거나 대역을 넘어서는 데이터가 존재하는지 감시#include <poll.h>
int poll (struct pollfd *fds, nfds_t nfds, int timeout);
fds
가 가리키는 단일 pollfd 구조체 배열을 nfds
개수만큼 사용.#include <poll.h>
struct pollfd{
int fd; //파일 디스크립터
short events; //감시할 이벤트
short revents; //발생한 이벤트