소켓을 통해 두 호스트 간의 연결이 성립되고 나면, 두 호스트는 서로 정보를 주고받을 수 있다. 이렇게 서로 의사소통이 가능한 상태를 '스트림이 형성되었다' 라고 한다.
스트림은 단방향이다. 즉 양쪽에서 모두 송수신이 가능하려면 두 개의 스트림이 필요하다. A와 B 호스트가 연결되어 있다고 하면, A의 입력 버퍼와 B의 출력 버퍼가 하나의 스트림을, A의 출력 버퍼와 B의 입력 버퍼가 또 하나의 스트림을 형성한다.
우리는 소켓 통신이 끝나면 흔히들 close() 함수를 이용해 연결을 종료한다. 이 때, close() 함수를 막 사용하면 안 되는 경우가 있다.
다음과 같은 상황을 가정해 보자.
A, B 두 개의 프로세스가 있다. A가 B에게 데이터를 계속해서 보낸다. 이 때, A가 데이터를 모두 보내고 나면 B는 A에게 잘 받았다는 뜻으로 'Receive Complete' 라는 메시지를 보내야 한다.
이 때, B는 언제까지나 receive 할 수만은 없다. A는 이제 다 보냈는데 B는 아직 더 보낼 것이 남은 줄 알고 recv 하고 있으면 블로킹이 발생할 수도 있기 때문에, A 입장에서는 데이터 송신이 끝나면 끝났다고 알려주어야 한다. EOF
를 보냄으로써 송신의 끝을 B에게 알릴 수 있다. 이 때 EOF
는 스트림을 닫는 것으로 보낼 수 있다.
하지만 그렇다고 해서 아예 연결을 끊어버릴 수는 없다. B에게서 메시지를 받아야 할 게 남았기 때문이다. 이 때 Half close가 사용될 수 있다.
Half close, 말 그대로 반만(Half) 닫는다(Close) 라는 뜻이다. 즉, 두 개의 스트림 중 하나만 닫아서 한 쪽 스트림은 열어두는 상태를 뜻한다.
A가 데이터를 모두 보내고, A의 입력 스트림을 닫음으로써 B에게 EOF를 전달한다.
B는 EOF를 확인하고, 데이터 수신의 끝임을 알 수 있고, 메시지를 보내면 된다.
Half close는 shutdown 함수를 이용해 사용할 수 있다.
함수의 형태는 매우매우 간단하다.
#include <sys/socket.h>
int shutdown(int sock, int howto);
성공 시 0, 실패 시 -1 반환
- sock : 종료할 소켓의 파일 디스크립터
- 종료 방법에 대한 정보
두 번째 파라미터로 전달되는 인자에 따라 종료의 종류가 결정된다.
SHUT_RD
: 입력 스트림을 종료SHUT_WR
: 출력 스트림을 종료SHUT_RDWR
: 입, 출력 스트림 종료