이것은 한낱 대학생이 교수의 수업을 듣고 작성한 개인저장용 복습 문서입니다.
그렇지만, 물론 지적과 수정은 환영합니다.
• Peripheral device (주변기기)
– 컴퓨터시스템에 의해 접근 가능한 하드웨어의 일종
– ex) disks, tapes, CD-ROMs, screens, keyboards, printers, mouse devices and network interfaces
• Device driver
– 'device driver'라 불리는 시스템모듈에 의해 실행되는 시스템콜 함수가 각 입출력 장치를 제어할 수 있게 해준다.
– 'device driver'는 용인되지 않은 사용을 막고, 디바이스의 실행의 디테일적인 부분을 숨긴다.
입출력은 어디에나 필요한 common한 task이다. 따라서 좀 더 간편할 필요성이 있다.
그래서 생긴것이 I/O 함수들. (open,close,read,write and octl)
이 함수들은 디바이스의 종류와 상관없이 모두 파일로 처리한다.
(called special files, /dev에 위치.)
유닉스 파일은 byte단위의 개체가 모여있는 것 (B0, B1, .... , Bk , .... , Bm-1)
I/O도 바이트 단위로 진행된다.
– /dev/sda2 (hard disk partition)
– /dev/tty2 (terminal)
심지어 OS 커널 이미지로 파일로 표현된다.
– /dev/kmem (kernel memory image)
– /proc (kernel data structures)
기본적인 Unix I/O operations (system calls)
– Opening and closing files
• open()- 사용자가 I/O 디바이스에 접근 의사를 밝히는 것.
• close()- 접근을 종료하는 것.
– 현재 파일의 포지션 변경 (seek)
• 커널이 file position을 변경한다. 처음엔 모든 파일이 0이다.
• seek()- 명시적으로 file position을 변경하는 것.
– Reading and writing a file
• read()- 파일로부터 메모리에 n 바이트만큼 읽는다.
• write()- 메모리로부터 파일에 n바이트만큼 쓴다.
Reading
#include
ssize_t read(int fildes, void * buf, size_t nbyte);
-fildes : 파일디스크립터, 오픈된 파일을 가르키는 값
-buf : 파일이 써질 메모리의 위치. nbyte보다 커야한다.
-nbyte : 몇 바이트를 읽을지. buf보다 커선 안된다.
-ssize_t : signed integer data type의 일종. 읽은 바이트 수
-size_t : unsigned integer data type.
-실제로 읽은 바이트 수 리턴
-실패시 -1 리턴
-nbyte만큼 읽기 전에 파일이 끝나버리면 nbyte보다 더 적게 리턴될 수도 있다.
File descriptor
오픈된 파일을 가르키는 지시자
오픈함수의 리턴값
단, 예외 3가지는 오픈함수 없이도 File descriptor를 읽어올 수 있다.
• STDIN_FILENO (표준 입력장치)
– 키보드입력에 대응
– In legacy code : 0.
• STDOUT_FILENO (표준 출력 장치)
– 스크린출력에 대응
– In legacy code : 1.
• STDERR_FILENO (표준 에러 장치)
– 프로그램이 절대 이것을 종료해선 안됨
– In legacy code : 2.
표준 입력장치로부터 buf에 최대 100바이트의 code segment를 입력하게 하려고 한다면?
char buf[100];
ssize_t bytesread;
bytesread = read (STDIN_FILENO, buf, 100);
-> code segment가 할당을 제대로 안해서 결과가 이상하게 나올 수 있다.
Readline.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <errno.h>
#include <unistd.h>
int readline(int fd, char *buf, int nbyte) {
int numread = 0;
int returnval;
while (numread < nbytes -1) {
returnval = read (fd, buf + numread, 1);
if ((returnval == -1) && (errorno == EINTR))
continue;
if ((returnval == 0) && (numread == 0)
return 0;
if (returnval == 0)
break;
if (returnval == -1)
return -1;
numread++;
If (buf[numread-1] == ‘\n’) {
buf[numread] = ‘\0;
return numread;
}
}
errno = EINVAL;
return -1;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
-numred : 읽은 바이트 수 저장용
-하나의 라인을 바이트 하나하나씩 읽어주는 함수
-buf + numred에 쓰기 시작하므로 이어쓰기 가능 (buf+0, buf+1,....)
-개행문자 ('\n')을 만나면 끝난 것으로 인식하고 해당자리에 '\0'을 넣어서 하나의 string으로 처리해놓는다.
-numred가 nbyte만큼 읽기 전에 무언가로 리턴이 되지 않고 반복문을 빠져나오면 오류 (EINVAL : 한줄이 아니다.)
-EINTR인 에러가 발생하면 다시 리드
-0만큼 읽혔는데 numred도 0이면 0리턴
-0만큼 읽혔는데 numred가 0이 아니면 오류 -> break -> EINVAL 오류리턴
-EINTR가 아닌 에러가 발생하면 -1 (그냥 오류, EINVAL은 아님) 리턴
When does an error occur?
1. read()에서 에러발생가능
2. 하나 이상의 파일을 읽고나면 새 라인을 읽기 전에 파일 종료가 될 수 있음.
3. nbytes-1 바이트만큼 읽고 더 이상 새로운 라인이 발견되지 않는다.
-> 아래와 같은 코드는 표준입력장치로부터 최대 99바이트를 한줄 읽어온다.
int bytesread;
char mybuf[100];
bytesread = readline(STDIN_FILENO, mybuf, sizeof(mybuf));
Writing
#include
ssize_t write(int fildes, const void *buf, size_t nbyte);
-기본적 구조는 read()와 유사
-실질적으로 쓴 바이트값 리턴
-0보다 크고 nbyte보다 작은 값이라면 오류가 나지 않은것
File offset
다음에 수행할 I/O operation의 위치를 가르키는 값
read/write는 file offset 자리에서부터 시작되고,
read/write가 실행될때마다 자동적으로 file offset이 변경된다.
fd = open(“test.dat”, O_RDWR);
read(fd, buf, 100);
write(fd, buf,200);
read(fd, buf, 200); //이와 같은 상황에서는 이 read는 100만 리턴한다. (write할 공간부족)
close(fd);
echo1
#define BLKSIZE 1024
char buf[BLKSIZE];
read(STDIN_FILENO, buf, BLKSIZE); // 키보드로부터, buf에 BLKSIZE 만큼 읽는다.
write(STDOUT_FILENO, buf, BLKSIZE); // buf에 있는 것을 스크린에 BLKSIZE 만큼 쓴다.
문제점 : read() 작동시 읽어오는 것을 실패하거나 혹은 BLKSIZE 바이트만큼 불러오지 않을 수 있다.
그러면 write() 작동시 그만큼 garbage값을 출력한다.
echo2
#define BLKSIZE 1024
char buf[BLKSIZE];
ssize_t bytesread;
bytesread = read(STDIN_FILENO, buf, BLKSIZE);
if (bytesread >0)
write(STDOUT_FILENO, buf, bytesread);
개선 : write() 사용시 0보다 클때, read()의 리턴값인 bytesread만큼만 쓴다.
문제점 : write()의 특성상 bytesread만큼 못하는 경우가 있을 수 있다. (함수의 특성)
read()나 write()나 둘 다 signal에 의해 인터럽트될 위험이 있다. (-1 리턴시 에러일수도 있지만 시그널일수도 있다.)
echo3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include <errno.h>
#include <unistd.h>
#define BLKSIZE 1024
int copyfile(int fromfd, int tofd) { // fromfd : 소스, tofd : 타겟(빈파일)
char *bp;
char buf[BLKSIZE];
int bytesread;
int byteswritten = 0;
int totalbytes = 0;
for ( ; ; ) {
while (((bytesread = read(fromfd, buf, BLKSIZE)) == -1) && (errno == EINTR)) ; /* handle interruption by signal */
if (bytesread <= 0) /* real error or end-of-file on fromfd */
break;
bp = buf; // bp : 얼마나 썼나 확인하면서 이동 vs buf : 진짜 주소값
while (bytesread > 0) {
while(((byteswritten =write(tofd, bp, bytesread)) == -1 ) &&(errno == EINTR)) ;/* handle interruption by signal */
if (byteswritten <= 0) /* real error on tofd */
break;
totalbytes += byteswritten;
bytesread -= byteswritten; // 쓴만큼 빼주면서 0이 될때까지 계속 재입력
bp += byteswritten; // 쓴만큼 bp에 더하기 (bp위치 이동)
}
if (byteswritten == -1) /* real error on tofd */
break;
}
return totalbytes;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
s |
개선 : signal 일경우 반복문 돌려서 재진행.
bp 업데이트 해가면서 반복적으로 write해서 조금 write되는 일이 없도록 방지
byteread가 0이 될때까지 무한 루프
bytesread의 역할 : 이번 스탭 타겟파일에 써야하는 byte수이면서 read의 리턴값
• r_read(), r_write()
– 시그널에 의한 인터럽트 시 계속 다시 읽기/쓰기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
ssize_t r_read(int fd, void *buf, size_t size) {
ssize_t retval;
while (retval = read(fd, buf, size), retval == -1 && errno == EINTR) ;
return retval;
}
ssize_t r_write(int fd, void *buf, size_t size) {
char *bufp;
size_t bytestowrite;
ssize_t byteswritten;
size_t totalbytes;
for (bufp = buf, bytestowrite = size, totalbytes = 0;
bytestowrite > 0;
bufp += byteswritten, bytestowrite -= byteswritten) {
byteswritten = write(fd, bufp, bytestowrite);
if ((byteswritten == -1) && (errno != EINTR))
return -1;
if (byteswritten == -1)
byteswritten = 0;
totalbytes += byteswritten;
}
return totalbytes;
}
|
• readwrite()
– 어떠한 파일로부터 byte를 받고 다른 파일에 그것을 써준다.(using r_read() and r_write())
– 어떤 buffer의 사이즈가 PIPE_BUF이면, 이는 파이프에 writing할때 유용하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
int readwrite(int fromfd, int tofd) {
char buf[BLKSIZE];
int bytesread;
if ((bytesread = r_read(fromfd, buf, BLKSIZE)) == -1)
return -1;
if (bytesread == 0)
return 0;
if (r_write(tofd, buf, bytesread) == -1)
return -1;
return bytesread;
}
|
왜냐하면 파이프에 PIPE_BUF(혹은 그보다 조금)만큼 쓰는 것은 atomic하기 때문이다.
즉, 쪼개지는 오류가 없다.
• copyfile()
– readwrite()를 이용해 파일을 카피
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
int copyfile(int fromfd, int tofd) {
char buf[BLKSIZE];
int bytesread, byteswritten;
int totalbytes = 0;
for ( ; ; ) {
if ((bytesread = r_read(fromfd, buf, BLKSIZE)) <= 0)
break;
if ((byteswritten = r_write(tofd, buf, bytesread)) == -1)
break;
totalbytes += byteswritten;
}
return totalbytes;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
readblock()
100바이트만큼 읽겠다고 요청하면 100바이트만큼 읽을 때까지 무조건 반복하는 함수
인터럽트되거나 더 적게 읽었을때 계속 반복
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
ssize_t readblock(int fd, void *buf, size_t size) {
char *bufp;
size_t bytestoread;
ssize_t bytesread;
size_t totalbytes;
for (bufp = buf, bytestoread = size, totalbytes = 0;
bytestoread > 0;
bufp += bytesread, bytestoread -= bytesread) {
bytesread = read(fd, bufp, bytestoread);
if ((bytesread == 0) && (totalbytes == 0))
return 0;
if (bytesread == 0) {
errno = EINVAL;
return -1;
}
if ((bytesread) == -1 && (errno != EINTR))
return -1;
if (bytesread == -1)
bytesread = 0;
totalbytes += bytesread;
}
return totalbytes;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
요청 바이트 수만큼 읽지 못하면 끝나면 0 리턴
요청 바이트 수만큼 읽으면 해당 바이트수 리턴
에러시 -1 리턴
'💻 CS > 시스템프로그래밍' 카테고리의 다른 글
[시스템프로그래밍] Files and Directories (0) | 2019.11.26 |
---|---|
[시스템프로그래밍] UNIX I/O - 2 (0) | 2019.11.07 |
[시스템프로그래밍] 중간고사 대비 (0) | 2019.10.22 |
[시스템프로그래밍] Processes in UNIX (1) | 2019.10.12 |
[시스템프로그래밍] Programs, Processes and Threads (0) | 2019.10.12 |