정글 54일차

10. 시스템 수준 입출력
- 어떻게 파일이 공유되는가
- I/O 재설정의 동작 방식
- 메타 데이터로의 접근 방식
버퍼 : 데이터를 모아두는 임시 저장소
Unix I/O
- 현재 파일 위치의 변경
- seek 연산을 통해 파일의 읽기/쓰기 포인터를 원하는 위치로 이동시킨다.
- 파일 읽기와 쓰기
- 읽기 연산은 현재 파일의 위치 k부터 시작해서 n>0 바이트를 파일에서 메모리로 복사하고, k를 n증가시킨다.
- k >= m인 연산을 수행하면 EOF(end-of-file)가 발생한다.
- 쓰기는 메모리에서 파일로 바이트를 복사하고 k를 갱신한다.
- 파일 닫기
- 커널에 파일 닫아줄것을 요청
- 프로세스가 종료할 때, 커널은 모든 열려있는 파일을 닫는다.
파일
- 뭔가 말이 어려운데 터미널에서 뜨는 파일 위치를 생각 하면 될듯
cd 폴더명을 사용하면 폴더명을 위치로 이동하는 거처럼
- 절대 경로 : 루트부터 시작. 언제나 고정된 위치 (/로 시작)
- 상대 경로 : 현재 작업 디렉터리부터 시작. 내가 지금 어디 있냐에 따라 달라짐 (/없이 혹은 ./,///로 시작)
파일 디스크립터
파일 디스크립터(fd) : 열린 파일이나 I/O 자원을 가리키는 파일의 정수 번호
- open함수는 파일이름을 파일 디스크립터로 변환하고, 그 디스크립터의 번호를 리턴한다.
- 리눅스 프로세스는 시작할 때 기본적으로 3개의 디스크립터가 자동으로 열려 있다.
| 디스크립터 번호 | 의미 |
|---|
| 0 | 표준 입력(stdin) |
| 1 | 표준 출력(stdout) |
| 2 | 표준 에러(stderr) |
fd = open("foo.txt", O_WRONLY | O_APPEND, 0);
printf("%d", fd);
- 가장 작은 번호를 반환하므로 open()은 그 다음인 3이다.
- 만약 close(1) 처럼 stdout을 닫고 나서 open()을 호출하면, fd는 1이 된다.
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("test.txt", O_RDONLY);
if (fd == -1) return 1;
char buf[100];
int n = read(fd, buf, sizeof(buf));
write(1, buf, n);
close(fd);
return 0;
}
- open() -> 파일 디스크립터 반환 (ex:3,4,5...)
- read(fd, buf, size) -> fd에 해당하는 파일에서 읽음
- write(fd, buf, size) ->fd에 해당하는 파일/장치로 씀
- close(fd) -> 사용 완료된 디스크립터 해제
파일 공유

- 각각의 프로세스는 Descriptor table을 가지고 있다.
- Descriptor table은 모든 프로세스가 공유하는 open file table을 가리키고 있고,open file tadle에는 offset, mode, v-node로의 포인터등 파일에 대한 정보가 있다.
- v-node table에는 실제 파일의 내용과 위치 등 상세한 파일 정보가 들어있다.
I/O 재지정

- I/O 재지정 동작은 dup2함수를 사용하는 것이다.
#include <unistd.h>
int dup2(int oldfd, int newfd);
- oldfd : 복제할 원본 파일 디스크립터
- newfd : oldfd를 복제해서 newfd에 덮어쓴다.
__dup2(4,1)을 호출한 후 상황

- 두 개의 식별자가 파일 B를 가리키고, 파일 A는 닫혔으며, 파일 테이블과 v-node 테이블 엔트리는 삭제되었다.
- 파일 B의 참조 횟수는 2로 증가 -> 이 지점에서 표준 출력에 쓰인 모든 데이터는 파일 B로 재지정된다.