4.1 시스템 호출
시스템 호출(system call)
커널에 서비스 요청을 위한 프로그래밍 인터페이스.
응용 프로그램은 시스템 호출을 통해 커널에 서비스를 요청한다.
운영체제가 지원하는 라이브러리 함수라고 보면 이해하기 쉽다.
주요 시스템 호출
파일: open(), close(), read(), write(), dup(), lseek() 등
프로세스: fork(), exec(), exit(), wait(), getpid(), getppid() 등
메모리: malloc(), calloc(), free() 등
시그널: signal(), alarm(), kill(), sleep() 등
프로세스 간 통신: pipe(), socket() 등
4.2 파일
파일 입출력
파일 열고->읽기/쓰기 등->파일닫기
파일 열기: open()
int open (const char *path, int oflag, [mode_t mode]);
파일 열기에 성공하면 파일 디스크립터(열린 파일을 나타내는 번호)를, 실패하면 -1 리턴함.
path: 파일의 경로/이름
oflag: 파일을 어떤 형태로 열 것인지
- O_RDONLY :읽기 모드. read()호출 가능
- O_WRONLY: 쓰기 모드. write() 호출 가능
- O_RDWR: 읽기/쓰기모드. read(), write()호출 가능
- O_APPEND: 데이터를 쓰면 파일 끝에 첨부됨
- O_CREAT: 해당 파일이 없는 경우에 생성함. 세번째 매개변수 mode는 O_CREAT의 경우 생성할 파일의 사용권한을 나타냄
- O_TRUNC: 파일이 이미 있는 경우 내용 삭제
- O_EXCL: O_CREAT와 함께 사용되며, 해당 파일이 이미 있으면 오류 출력
- O_NONBLOCK
- O_SYNC
파일 열기 예시
fd = open("account", O_RDONLY);
fd = open(argv[1],O_RDWR); //첫 번째 명령 줄 인수
fd = open(argv[1],O_RDWR|O_CREAT,0600); //해당 파일이 없으면 권한600짜리 파일 생성
fd = open("tmpfile",O_WRONLY|O_CREAT|O_TRUNC, 0600);
//쓰기전용으로 열고, 없으면 권한 600으로 새로 생성하고, 기존 내용이 있으면 지운다.
fd = open("/sys/log",O_WRONLY|O_APPEND|O_CREAT, 0600);
//첨부용 쓰기전용으로 연다. 없으면 600권한으로 새로 생성
if((fd=open("tmpfile",O_WRONLY|O_CREAT|O_EXCL, 0666))==-1)
//파일이 없는 경우에만 권한 666으로 새로 생성하고 기존 파일이 있으면 오류.
if((fd=open(argv[1],O_RDWR))==-1)
perror(argv[1]); //오류출력
printf("파일 %s 열기 성공\n", argv[1]);
close(fd);
exit(0);
파일 생성: creat()
int creat(const char *path, mode_t mode);
path 파일을 생성하고 쓰기 전용으로 연다.생성된 파일의 사용권한은 mode로 설정.
기존 파일이 있는 경우에는 그 내용을 삭제하고 쓴다.
open(path, O_WRONLY|O_CREAT|O_TRUNC, mode) 와 동일하다
파일 닫기: close()
int close(int fd);
fd가 나타내는 파일을 닫는다. 성공하면 0, 실패하면 -1을 리턴함.
데이터 읽기: read()
ssize_t read(int fd, void *buf, size_t nbytes);
fd가 나타내는 파일에서
nbytes만큼의 데이터를 읽어 buf에 저장한다.
파일 읽기에 성공하면 읽은 바이트 수를 반환, 파일 끝을 만나면 0, 파일 읽기에 실패하면 -1을 반환한다.
데이터 읽기 예시: 파일의 크기 계산하기
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFSIZE 512
int main(int argc, char *argv[])
{
char buffer[BUFSIZE];
int fd;
ssize_t nread;
long total =0;
if((fd=open(argv[1],O_RDONLY))==-1)
perror(argv[1]); //파일 열기 실패한 경우 오류 출력
while((nread = read(fd, buffer, BUFSIZE)) >0) //파일의 끝에 도달할 때까지 반복
total += nread //읽어온 데이터 크기를 total에 더함
close(fd);
printf("%s파일 크기: %ld 바이트\n", argv[1],total);
exit(0);
}
데이터 쓰기: write()
ssize_t write(int fd, void *buf, size_t nbytes);
buf에 있는 nbytes만큼의 데이터를 fd가 나타내는 파일에 쓴다.
데이터 쓰기 예시: 파일 복사하기
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
main(int argc, char *argv[])
{
int fd1,fd2,n;
char buf[BUFSIZ]; //사전 정의 상수 512
if(argc !=3){
fprintf(stderr,"사용법: %s file1 file2\n",argv[0]);
exit(1);
}
if((fd1 = open(argv[1],O_RDONLY))==-1){//1번 파일 열기 실패
perror(argv[1]);
exit(2);}
if((fd2 = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0644))==-1){//2번 파일 열기 실패
perror(argv[2]);
exit(3);}
while((n=read(fd1,buf,BUFSIZ))>0)//fd1의 파일의 끝에 도달할 때 까지 내용을 읽어 buf에 저장
write(fd2,buf,n); //buf에 저장된 내용을 fd2의 파일에 작성
exit(0);
}
파일 디스크립터 복제
int dup(int oldfd);
//oldfd에 대한 복제본인 새로운 파일 디스크립터를 생성하여 그 번호를 반환하고, 실패하면 -1 반환
int dup2(int oldfd, int newfd);
//oldfd를 newfd에 복제하고, 복제된 새로운 파일 디스크립터 번호를 반환한다. 실패하면 -1 반환
fd2 = dup(fd1);
dup2(fd1, fd2);
위 두 코드는 사용상의 차이일 뿐 기능은 동일하다.
oldfd와 복제된 새로운 디스크립터는 하나의 파일을 공유한다.
입출력 재지정에 유용하게 사용가능함.
4.3 임의 접근 파일
파일 위치 포인터
파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일 위치를 가리킨다.
파일 위치 포인터 이동: lseek()
off_t lseek(int fd, off_t offset, int whence);
fd파일에서 whence에서부터 offset만큼 포인터를 이동
whence의 종류
- SEEK_SET: 처음
- SEEK_CUR: 현재
- SEEK_END: 끝
이동에 성공하면 현재 위치를 리턴하고 실패하면 -1을 리턴한다.
파일 위치 포인터 이동 예시
lseek(fd, 0L, SEEK_SET); //파일 시작으로 이동
lseek(fd, 100L, SEEK_SET);//파일 시작에서 100바이트 위치로
lseek(fd, 0L, SEEK_END);//파일 끝으로 이동
//레코드 단위로 이동
lseek(fd, n*sizeof(record),SEEK_SET); //n+1번째 레코드 시작위치로
lseek(fd, sizeof(record), SEEK_CUR); //다음 레코드 시작위치로
lseek(fd, -sizeof(record), SEEK_CUR); //전 레코드 시작위치로
lseek(fd, sizeof(record),SEEK_END); //파일 끝에서 한 레코드 다음 위치로
offset은 long type이기 때문에 L로 표현
댓글