[리눅스] 네트워크 등 read,write 시 다 못 쓸때, 읽어 올때 readn, writen 함수 구현 코드
리눅스에 관한 더 많은 정보와 예제를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.
https://reakwon.tistory.com/233
readn, writen
네트워크같은 환경에서 어마어마한 데이터가 쓰여질 경우 일반 read함수로는 전부 읽어올 수 없는 상황이 발생할 수 있습니다. 또 반대의 경우에도 마찬가지입니다. 큰 데이터가 한번에 쓰여질 경우 write함수로는 쓰여지지 않을 수 있습니다. 아래와 같은 두가지의 상황이 발생하기 때문인데요.
1) read 연산이 요청보다 작은 바이트를 되돌려줄 경우에는 이는 오류가 아닙니다. 단지, 더 읽어야할 데이터가 있다는 뜻입니다. 2) write 역시 요청보다 작은 바이트를 돌려줄 수 있는 경우가 있는데, 커널의 출력 버퍼가 꽉 찼을때 이런 경우가 발생합니다.
1), 2)는 어떻게 해결할 수 있을까요? 답은 데이터가 요청된 값이 될때까지 읽거나 쓰는 것입니다. 이런 함수가 아래의 readn, writen 함수입니다.
- 아래의 코드는 Advanced Programming in the UNIX Environment 3판을 참고하여 만든 코드입니다.
rean 함수
ssize_t readn(int fd, void *data, size_t n){
size_t left; //남은 바이트
size_t read_n; //읽은 바이트
left = n;
while(left > 0){
if((read_n = read(fd, data, left)) < 0){
if(left == n) return -1;
else break;
}else if(read_n == 0) break;
left -= read_n; //얼마나 남았는지 갱신
data += read_n; //남은 바이트 읽기 위해 포인터 이동
}
return n-left;
}
readn 함수를 보면 while문을 통해서 계속 다 읽을때까지 read를 호출하는 것을 볼 수 있습니다. read가 0을 반환하면 다 읽었다고 판단하여 while 루프를 종료하고 빠져나오면 됩니다.
writen 함수
ssize_t writen(int fd, const void *data, size_t n){
size_t left; //쓰기까지 남은 바이트
ssize_t written_n; //쓴 바이트
left = n;
while(left > 0){
if((written_n = write(fd, data, left)) <0){
if(left == n) return -1;
else break;
}else if(written_n == 0) break;
left -= written_n; //얼마나 남았는지 갱신
data += written_n; //남은 바이트 쓰기 위해 포인터 이동
}
return n-left;
}
writen 함수 역시 계속 data를 쓸때까지 while 루프로 계속 write를 호출하는 것을 볼 수 있습니다. write가 0을 반환하게 되면 다 썼다는 의미로 반복문을 빠져나오고 writen 함수가 종료됩니다.
readn, writen 함수는 read, write함수와 동일하게 사용이 가능합니다. 이 함수들은 socket과 같은 네트워크, 파이프, FIFO 등에서 대량의 바이트를 읽거나 쓰기위한 함수라는 것을 기억하시기 바랍니다. 일반 파일 IO에서는 read, write만 사용해도 무관합니다.