-
TCP/IP 소켓 프로그래밍 - 16장 : 입출력 스트림 분리네트워크 2024. 6. 26. 15:54
16장16-1 입력 스트림과 출력 스트림의 분리
입력과 출력을 위한 도구가 별도로 나뉘어 구분할 수 있으면,
입출력 스트림이 분리되었다고 표현한다.
앞서 공부한 입출력 스트림의 분리 방법 2가지는 아래와 같았다.
- 입력, 출력에 사용되는 파일 디스크립터 구분 ( 10장 )
- 읽기, 쓰기 모드에 따른 FILE 포인터 구분 ( 15장 )
스트림 분리 방법 또는 목적에 따라 기대할 수 있는 장점이 달라진다.
- 10장에서의 파일 디스크립터 구분 : 입력 상관없이 출력이 가능 ⇒ 속도 향상
- 15장에서의 FILE 포인터 구분 : 입력버퍼와 출력버퍼를 구분해 버퍼링 기능 향상
파일 포인터를 대상으로 Half-close를 진행할 때에는 파일 디스크립터와 달리 좀 더 주의해야 한다.
(단순히 서버측에서 fclose함수로 writefp를 닫아버리는 것만으로는 원하는 결과를 얻지 못한다!)
16-2 파일 디스크립터의 복사와 Half - close
책의 예제에서 스트림 종료 시 ( “fclose(writefp)” ) half-close가 진행되지 않은 이유는
FILE 포인터와 파일 디스크립터, 그리고 소켓의 관계를 살펴보면 알 수 있다.

예제에서의 FILE 포인터들은 1개의 FD 를 기반으로 만들어졌다.
( FILE * readfp = fdopen ( sock, “r” ); FILE * writefp = fdopen( sock, “w”); )
이때, fclose 함수로 FILE 포인터를 지우면, 파일 디스크립터도 종료되고, 소켓도 종료된다.

이를 해결하는 방법은, 파일 포인터를 만들기 전에 파일 디스크립터를 복사해 하나 더 만드는 것이다.

이렇게만 하면 될 수 있는 이유 중 하나로,
소켓은 모든 파일 디스크립터가 소멸되어야 소멸되는 점을 들 수 있다.
파일 디스크립터는 입력과 출력이 모두 가능하고, 때문에 하나라도 남아있으면
상대 호스트로 EOF가 전송되지 않으며 파일 디스크립터를 이용하면 문제없이 송수신이 가능하다.
(별도의 EOF 전송 코드가 필요하다. )
이 때문에 EOF가 전송되는 half-close를 위해서는 shutdown 함수를 이용해주어야 한다.
이제는, 파일 디스크립터를 복사하는 방법을 알아보자.
fork 함수 호출 시 진행되는 파일 디스크립터(FD) 복사와 위에서 언급한 FD 복사에는 차이가 있다.
fork 함수 호출로 인한 복사
- 프로세스를 그대로 복사 → 한 프로세스에 원본과 복사본 FD 동시에 존재하지 않음.
위에서 말한 복사
- 프로세스 생성 x → 한 프로세스 내부에 원본과 복사본 FD 모두 존재.
주의할 점은, 파일 디스크립터는 값이 중복될 수 없어서
파일 디스크립터 정수값은 서로 다르다는 점이다.
복사의 표현을 좀 더 정확히하면,
"동일한 파일 또는 소켓을 가리키는 또 다른 파일 디스크립터의 생성"에 가깝다.
파일 디스크립터 복사는 아래 두 함수 중 하나를 이용한다.
#include <unistd.h> int dup(int fildes); int dup2(int fildes, int fildes2); // 성공 시 복사된 파일 디스크립터, 실패 시 -1 리턴 // fildes2 : 만들어질 파일 디스크립터의 정수를 명시적으로 전달책의 예제 코드를 실행해보면 모든 파일 디스크립터(원본, 복사본)가 닫히기 전까지는 출력이 되다가, 다 닫힌 이후로는 더 이상 출력되지 않는다.
아래는 예제코드 실행 결과이다.
(궁금하면 책 따라 쳐보자. )
마지막으로 파일 포인터를 이용해 스트림을 분리했을 때,
파일 디스크립터 복사와 EOF를 날려주는 shutdown함수를 이용해
아래와 같은 코드를 넣어주면 문제없이 half-close를 이룰 수 있다.
... readfp = fdopen(clnt_sock, "r"); writefp = fdopen(dup(clnt_sock), "w"); ... shutdown(fileno(writefp), SHUT_WR); fclose(writefp); ... fclose(readfp); ...위 코드를 바탕으로 한 마지막 예제를 실행한 결과는 아래와 같다.

클라이언트로부터 마지막 메시지를 수신 받으며 종료되는 모습이다.
'네트워크' 카테고리의 다른 글
TCP/IP 소켓 프로그래밍 - 18장 : 멀티쓰레드 기반의 서버구현 (0) 2024.06.29 TCP/IP 소켓 프로그래밍 - 17장 : select 보다 나은 epoll (0) 2024.06.26 TCP/IP 소켓 프로그래밍 - 15장 : 소켓과 표준 입출력 (0) 2024.06.25 TCP/IP 소켓 프로그래밍 - 14장 : 멀티캐스트 & 브로드캐스트 (0) 2024.06.25 TCP/IP 소켓 프로그래밍 - 13장 : 다양한 입출력 함수들 (0) 2024.06.24