현생/TCP 소켓 프로그래밍

16. 파일 포인터 기반 입출력 스트림 분리에서 Half-close [TCP/IP][C][LINUX]

푸더기 2022. 2. 16. 19:25
반응형

 

https://pupuduck.tistory.com/85에서 다뤘듯 fdopen 함수로 파일 디스크립터를 FILE형 포인터로 변환시킬 수 있습니다. 

그리고 https://pupuduck.tistory.com/70에서 입출력 스트림 분리와 분리했을 때의 장점을 다뤘습니다.

 

위 글에서는 스트림 분리목적으로 입출력 루틴 독립을 통한 편의성을 느리고, 입력에 상관없이 출력이 가능하게 함으로 속도의 향상을 기대할 수 있었는데, 이 글에서는 읽기모드와 쓰기모드를 구분해야 하는 FILE 포인터를 사용하므로 두 모드의 구분을 통한 편의성 증대와 버퍼링 기능의 향상을 기대할 수 있습니다.

 

분리된 파일 포인터와 파일 디스크립터, 소켓의 관계는 위와 같이 표현됩니다. 그런데 만약, Half-close를 위해서, 예를 들어 읽기모드의 FILE 포인터를 대상으로 fclose를 호출한다면 소켓이 완전 종료되게 됩니다.

읽기모드의 FILE 포인터만 닫았는데도, 쓰기모드의 FILE 포인터는 당연히 작동하지 않습니다.

 

이 문제의 해결책은 소켓은 자신과 연결된 파일 디스크립터가 1개라도 남아있으면 닫히지 않기때문에 파일 디스크립터를 복사하면 됩니다. 여기서 파일 디스크립터 복사는 기존 파일 디스크립터의 정수를 복사하는 것이 아닌 같은 소켓을 향하는 새로운 파일 디스크립터를 만드는 것입니다.

 

#include<unistd.h>

int dup(int fildes);
int dup2(int fildes,int fildes2);
// success: 파일 디스크립터   fail: -1

여기서 fildes는 복사할 파일 디스크립터를 뜻하고, dup2의 fildes2는 파일 디스크립터의 정수값로 지정이 가능한 값을 넣어주면 복사된 파일 디스크립터의 값은 그 값으로 설정됩니다. fildes2의 존재를 제외하곤 두 함수의 기능은 같습니다.

 

그런데, Half-close가 이뤄질 때는 상대에게 EOF를 전달해야합니다. 이를 위해서는 https://pupuduck.tistory.com/40에서 다룬 shutdown 함수를 사용하면 됩니다.

...

shutdown(fileno(writefp),SHUT_WR);
fclose(writefp);

fgets(buf, sizeof(buf), readfp); fputs(buf, stdout);
fclose(readfp);

쓰기모드를 먼저 닫고 전송된 데이터를 읽은 뒤 쓰기모드 마저 닫는 예제입니다. 쓰기모드 FILE 포인터와 연결된 파일 디스크립터를 shutdown 해주는데 이때 상대에게 EOF가 전송됩니다.

반응형