공부/Server

TCP 기반의 소켓의 우아한 연결 종료(Half-close)

sudo 2021. 8. 1. 02:12

지금까지 TCP 종료 과정은 closesocket()으로 해왔다. 하지만 이 함수 호출은 완전 종료를 의미하며, 완전 종료는 입출력 스트림 모두를 종료한다는 의미이다. 참고로 두 호스트가 연결돼서 상호간의 송수신이 가능한 상태가 된다면 이걸 가리켜 '스트림이 형성된 상태'라고 한다. 이렇게 한쪽 호스트에서 일방적으로 스트림을 끊으면 반대 호스트에서 전송해야할 데이터를 수신 받지 못하게 된다. 연결을 종료했는데 왜 반대쪽에서 보내는 데이터를 또 받으려고 하는가?와 같은 의문이 생길 수도 있다. 

 

예를 들어, 서버와 클라이언트가 스트림이 형성됐다면 서버는 클라이언트에게 파일을 전송하고 서버가 모든 파일의 모든 내용을 전송했다면 끝이라는 의미로 EOF를 전송해야 한다고 해보자. 클라이언트는 서버로부터 EOF를 받으면 바로 "Thank you"와 같은 메세지를 전송해야 한다고 가정해보자. 이 Thank you가 아주 중요한 데이터라고 생각해보자. 만약 서버가 데이터를 모두 전송하고 closesocket()을 호출하면 클라이언트로부터의 Thank you메세지를 받지 못한다.

이때 half-close를 통해 출력 스트림만 종료하고 입력 스트림은 열어둬서 클라이언트로부터 메세지를 받을 수 있다. 

Half-close를 사용하는 방법은 shutdown() 함수를 이용하면 된다.

#include <winsock2.h>
// 성공 시 0, 실패시 SOCKET_ERROR 반환
int shutdown(SOCKET sock, int howto);

sock : 종료할 소켓의 핸들
howto : 종료방법에 대한 정보 전달

howto에 줄 수 있는 옵션들

  • SD_RECEIVE : 입력 스트림 종료
  • SD_SEND : 출력 스트림 종료
  • SD_BOTH : 입출력 스트림 종료