


이게 진짜 핀토스 "준비" 하는거라고요??
거짓말하지마!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
나 지금 장난칠 기분 아니야!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
지금까진 어떻게든 이해는 갔다..
근데 이제부터는 진짜 "이해"가 안감 "이해"가 안간다고요..
🎯 1. 키워드 공부
🎯 2. 테스트 케이스
echo
tiny
proxy
🎯 3. 책 읽기
진행률 : 30% ( 이해를 못하겠다.. )
Rio 함수는 시스템 수준의 read write를 좀 더 안전하게 하기 위한 래퍼(창모아님) 함수입니다.
최대한 이해하기 쉽게 단순화해서
Rio 함수는 어떤 파일에 읽고 쓰는 함수다! 라고 해볼게요.
우리가 구한 어떤 파일 디스크립터 fd 가 64Byte 짜리 File의 위치를 가리키고 있어요.
File 에는 64바이트 까지 다양한 값들로 채워져 있습니다.
저 File에 있는 정보를 읽고 써야해요. Rio 함수를 써서 안전하게요.
지금은 총 5가지의 Rio 함수가 있습니다.
Rio_readinitb 는 파일을 읽기 위해 준비하는 함수 예요.Rio_readn 은 n 바이트 만큼 파일을 메모리에서 직접 읽는 함수예요.Rio_readnb 는 n 바이트 만큼 파일을 버퍼를 사용해서 읽는 함수예요.Rio_readlineb 는 파일을 "한줄씩" 버퍼를 사용해서 읽는 함수예요.Rio_writen은 n 바이트 만큼 파일에 쓰는 함수예요.!!!!!주목!!!!!
버퍼를 사용하는 친구들이예요.ㅅ버퍼를 사용한 함수가 없는 점에 주목할 필요가 있어요.쓰기 작업은 굳이 버퍼를 거칠 필요 없이 즉각적이고 단순하게 반영하기 때문에 버퍼가 없이 바로 "n 바이트를 파일에 써줘!!"하고 요청하는게 좋아요.
Rio_readinitb 와 Rio_readlineb 만 시각화를 하면서 살펴볼게요.
본인의 파일에 있는 코드와 비교하면서 입력값이 어떻게 다른지 확인해보는 것도 좋아요.
Rio_readinitb는 읽기 위해 초기화하는 함수 라고 했죠?
void rio_readinitb(rio_t *rp, int fd)
{
rp->rio_fd = fd;
rp->rio_cnt = 0;
rp->rio_bufptr = rp->rio_buf;
}
void Rio_readinitb(rio_t *rp, int fd)
{
rio_readinitb(rp, fd);
}
rio_t RobustIO
Rio_readinitb(&RobustIO , fd);
// Rio_readinitb 함수는 인자로 rio_t 구조체의 주소와, 파일디스크립터 정보를 받습니다.
이렇게 사용했을 때 어떻게 변할까요?
정답을 말하자면: rio_t 타입의 RobustIO 구조체가 초기화 됩니다!
RobustIO 구조체의 값들 중 rio_fd 가 이제 fd로 변경되었기 때문에 파일에 접근할 수 있습니다.
그리고 따로 rio_buf 라는 데이터를 저장할 공간을 만들었어요.
뒤에 b가 붙은 함수들은 이렇게 만든 rio_buf공간을 계속 사용해 줄 겁니다.
Rio_readlineb 함수의 정의를 모으면 이렇게 돼요.
static ssize_t rio_read(rio_t *RobustIo, char *usrbuf, size_t n)
{
int cnt;
while (RobustIo->rio_cnt <= 0) {
/* 버퍼가 비어있으면 가득 채운다. */
/* 그리고 rio_cnt 를 read 의 return 값으로 채워준다 */
/* read 의 return 값은 "실제 읽은 데이터의 값" 이다. */
RobustIo->rio_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (RobustIo->rio_cnt < 0) {
if (errno != EINTR) /* Interrupted by sig handler return */
return -1;
} else if (RobustIo->rio_cnt == 0) {
/* EOF */
return 0;
} else {
RobustIo->rio_bufptr = RobustIo->rio_buf; /* Reset buffer ptr */
}
}
// 나머지 코드...
}
ssize_t rio_readlineb(rio_t *RobustIo, void *usrbuf, size_t maxlen)
{
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
/* rio_read 의 매개변수에 1 을 넣어줘서 한글자씩만 읽는다 */
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
}
// 나머지 코드..
}
ssize_t Rio_readlineb(rio_t *RobustIo, void *usrbuf, size_t maxlen)
{
ssize_t rc;
if ((rc = rio_readlineb(RobustIo, usrbuf, maxlen)) < 0)
unix_error("Rio_readlineb error");
return rc;
}
Rio_readlineb(&RobustIo, buf, MAXLINE);
이제 Rio_readinitb로 만들어준 RobustIO구조체를 활용해서 파일에 있는 값을 읽어볼게요.
구조체 안에 이미 fd정보가 들어있습니다.
Rio_readlineb 는
read시스템 콜에서 읽은 데이터 바이트로 변경해줍니다"구조체의 rio_buf 가 file 의 문자열 데이터로 채워졌고, rio_cnt가 32로 채워졌습니다.
rio_cnt 는 rio_buf안에 읽지 않은 데이터가 32바이트다라는 뜻입니다.
Rio_readlineb(&RobustIo, buf, MAXLINE);
보시는 것처럼 Rio_readlineb는 &RobustIO 주소와 buf를 받고있는데요.
&RobustIO주소에서 buf로 데이터를 한 줄만 읽어서 이동시켜요. 한 줄이란 /0 을 만날 때 까지 입니다
rio_cnt가 18로 줄어들었어요. rio_buf에서 읽을 수 있는 바이트가 18바이트 남았단 뜻입니다.rio_bufptr이 마지막으로 읽은 /0의 다음을 가리키고 있어요. 저 포인터를 기준으로 나머지 rio_buf를 읽습니다.엥?? 진짜 쓰일곳이 뭐지?? 라고 생각하실 수 있는데
잠시 echoclient.c 의 코드를 살펴볼게요.

RobustIO 구조체의 내부에서 메모리에 여러번 접근하지 않기 위해 buf를 사용해 데이터를 저장하는 거지, 실제 사용은 외부의 buf 에서하고 Fputs 로 출력하는 것을 확인할 수 있습니다.
Fputs 또한 buf 내에서 null 종료 문자를 만날때까지만 출력합니다.
null 종료문자는 readlineb 에서 나오기 때문에 무조건 한 줄 씩만 출력되죠.
Rio_readlineb함수는 그 파일에서 알아서 버퍼링해서 2번째 매개변수로 값을 한줄만 넣어줍니다.처음에는 c에서 값을 return 해서 넣어주지 않고
주소를 넣어서 주소의 값을 직접 바꾸는게 어색한데, 그것을 이해한다면 나머지 Rio 함수를 이해하기가 좀 더 쉬워집니다.
미안합니다. 모든 함수를 그리기엔 시간이 부족했습니다.
- 불안할 땐 증거 있어? 라고 묻기
- 나는 최고다. 나는 할 수 있다. 나는 핀토스를 부순다.
팬입니다