시프 07-inputOutput

강준호·2024년 6월 2일

시스템프로그래밍

목록 보기
5/18
post-thumbnail

입력과 출력 (I/O) 시스템 프로그래밍

I/O 커널 서비스

  • C 표준 라이브러리를 사용한 텍스트 I/O: fread(), fgets(), printf() 등.
  • 그러나 모든 I/O는 커널 시스템 호출을 기반으로 합니다.

UNIX 시스템의 파일 개념

모든 것이 파일

  • UNIX에서 "모든 것은 파일"입니다.
  • 장치 노드도 파일처럼 동작합니다.
    • 예: /dev/null은 항상 읽을 수 있고, 데이터를 버림.
    • 예: /dev/urandom은 암호학적으로 안전한 무작위 데이터를 읽음.

파일의 유형

  • 정규 파일: 임의의 데이터를 포함.
  • 디렉토리: 관련된 파일 그룹의 인덱스.
  • 소켓: 다른 머신의 프로세스와 통신.
  • 심볼릭 링크, 문자 및 블록 장치 등.

정규 파일

텍스트 파일과 바이너리 파일

  • 텍스트 파일: ASCII 또는 유니코드 문자만 포함.
  • 바이너리 파일: 객체 파일, JPEG 이미지 등.
  • 텍스트 파일은 텍스트 줄의 시퀀스.
  • 각 텍스트 줄은 개행 문자('\n')로 종료.

줄 끝 표시

  • 리눅스와 macOS: \n (0xa, 줄 바꿈 문자).
  • Windows와 인터넷 프로토콜: \r\n (0xd 0xa, 캐리지 리턴 + 줄 바꿈).

디렉토리

디렉토리 구조

  • 디렉토리는 파일명을 파일에 매핑하는 링크 배열로 구성.
  • 각 디렉토리에는 최소한 두 개의 항목이 있음: . (자신을 가리키는 링크), .. (부모 디렉토리를 가리키는 링크).
  • 디렉토리 명령: mkdir, ls, rmdir.

디렉토리 계층 구조

  • 모든 파일은 루트 디렉토리 /를 기준으로 계층적으로 조직됨.
  • 각 프로세스는 현재 작업 디렉토리 (cwd)를 가짐.
  • cd 명령으로 cwd를 변경할 수 있음.

파일 디스크립터

파일 디스크립터의 개념

  • 파일 디스크립터는 특정 프로세스에서 열린 파일을 나타내는 작은 정수.
  • 표준 파일 디스크립터:
    • 0: 표준 입력 (stdin)
    • 1: 표준 출력 (stdout)
    • 2: 표준 오류 (stderr)

파일 모드

  • 모든 파일에는 소유자와 그룹이 있으며, 모드 비트로 파일 권한이 처리됨.
  • 모드 비트 형식: rwxrwxrwx
    • 사용자, 그룹, 기타 사용자의 읽기, 쓰기, 실행 권한.

모드 예제

  • 모드 비트는 보통 8진수로 표현.
    • 예: 750 (사용자는 읽기, 쓰기, 실행 가능; 그룹은 읽기, 실행 가능; 다른 사용자는 접근 불가)
    • 예: 664 (사용자와 그룹은 읽기, 쓰기 가능; 다른 사용자는 읽기 가능)

UNIX I/O 개요

UNIX I/O 시스템 호출

  • 파일 열기/닫기: open(), close()
  • 파일 읽기/쓰기: read(), write()
  • 현재 파일 위치 변경: lseek()

시스템 호출 실패 처리

  • 시스템 호출이 실패하면 음수를 반환하고, 전역 변수 errno에 실패 이유를 설정.
  • perror()strerror()errno에서 사람이 읽을 수 있는 오류 메시지를 생성.

파일 열기

  • open() 시스템 호출: 파일 열기.
  • creat() 시스템 호출: 파일 생성 (동일한 open() 호출 사용).

파일 열기 플래그

  • O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_APPEND, O_TRUNC, O_CLOEXEC.

파일 읽기

  • read() 시스템 호출은 열린 파일에서 데이터를 읽음.
  • 반환 값:
    • 0: 파일 끝 (EOF)
    • 0: 읽은 바이트 수

    • <0: 오류

파일 쓰기

  • write() 시스템 호출은 열린 파일에 데이터를 씀.
  • 반환 값:
    • ≥0: 쓴 바이트 수
    • <0: 오류

파일 디스크립터 닫기

  • close() 시스템 호출로 열린 파일을 닫음.

UNIX I/O 예제

#include <unistd.h> 
#include <fcntl.h> 
int main(int argc, char *argv[]) { 
    char buf[1024]; 
    int fd, bytes; 
    if ((fd = open(argv[1], O_RDONLY)) < 0) return -1; 
    while ((bytes = read(fd, buf, sizeof(buf))) > 0) { 
        if (write(1, buf, bytes) < 0) return -1; 
    } 
    return bytes >= 0; 
}

표준 I/O 스트림

  • 표준 I/O 스트림은 파일 디스크립터를 래핑.
  • fopen()은 파일을 열고, fdopen()은 열린 파일 디스크립터를 래핑.
  • 모드:
    • "r": 읽기
    • "w": 쓰기, 파일 초기화
    • "a": 추가 모드로 쓰기
    • "r+": 읽기 및 쓰기
    • "w+": 읽기 및 쓰기, 파일 초기화

이진 I/O

  • "b" 모드를 사용하여 이진 I/O 수행.
  • POSIX 시스템에서는 "b" 모드가 무시됨.

읽기 및 쓰기

  • fread(), fwrite() 함수는 이진 데이터를 읽고 씀.
  • 반환 값:
    • 읽거나 쓴 항목 수
    • 오류 또는 EOF 시 0

오류 및 EOF

  • feof()ferror() 함수는 EOF 또는 오류 발생 시 0이 아닌 값을 반환.
  • clearerr()는 스트림의 오류/EOF 상태를 재설정.

표준 I/O 예제

#include <stdio.h> 
int main(int argc, char *argv[]) { 
    char buf[1024]; 
    FILE *fp; int bytes; 
    if ((fp = fopen(argv[1], "r")) == NULL) return -1; 
    while (!feof(fp) && (bytes = fread(buf, 1, sizeof(buf), fp)) > 0) { 
        if (fwrite(buf, 1, bytes, stdout) == 0) return -1; 
    } 
    return ferror(fp) || ferror(stdout); 
}

시스템 호출 오버헤드

  • 시스템 호출의 오버헤드는 작지 않음.
  • 보호 도메인 변경, 포인터 검증, 메모리 맵 조정 등이 원인.
  • 더 많은 작업을 수행하는 적은 수의 시스템 호출이 바람직.

표준 I/O 버퍼링

  • 표준 I/O 함수는 오버헤드를 줄이기 위해 버퍼링 사용.
  • fread()는 1바이트를 읽더라도 전체 디스크 블록을 읽을 수 있음.
  • 장치 I/O는 매우 정확한 읽기/쓰기 크기가 필요할 수 있음.
  • 버퍼 플러싱은 짧은 쓰기 문제를 해결:
    int fflush(FILE *fp);

요약

  • UNIX I/O는 POSIX 표준에 의해 정의됨.
  • 표준 I/O는 C 표준에 의해 정의됨.
  • 모든 파일 I/O는 커널을 통해 수행됨.
  • 표준 I/O 라이브러리는 버퍼링을 사용하여 성능을 향상.

이 설명은 입력 및 출력에 대한 커널 서비스, 파일 시스템의 개념, 파일 디스크립터, UNIX와 표준 I/O의 차이점을 다룹니다.

0개의 댓글