본문 바로가기

진리는어디에

[socket] shutdown (half close)

"Half-close"?? 절반만 닫는다는게 무슨 소리야?

half-close의 의미는 소켓의 레퍼런스 카운트나 기타 등등 들은 유지한체 write stream이나 read stream만을 선별적으로 닫는다는 뜻이다. 그에 대한 API는 아래와 같다.

#include <sys/socket.h>
int shutdown(int fd, int how);
  • fd : half-close 하고자하는 파일 디스크립터
  • how : close 모드. 아래 값 중 하나를 가질 수 있다.
    • SHUT_RD : 입력 스트림 종료. 상수 값 0
    • SHUT_WR : 출력 스트림 종료. 상수 값 1
    • SHUT_REWR : 입출력 스트림 모두 종료. 상수 값 2

도데체 이게 왜 필요한거지? 그냥 닫아 버리면 무슨 문제라도 생기나?

위와 같은 의문을 충분히 가질 수 있다. 설명을 위해 다음과 상황을 가정해 보자.

서버와 클라이언트가 있다. 클라이언트가 소켓을 닫는 시점에 서버는 클라이언트에게 특정 메시지를 전달 해야만 한다.
음..클라이언트의 접속 종료 시간을 서버로 부터 받아와 클라이언트가 기록 한다고 가정하자. 그런데 클라이언트의 소켓이 종료 되버려 서버가 클라이언트에게 연락할 방법이 다 막혔는데 어떻게 서버가 클라이언트에게 시간을 전달 할 수 있단 말인가?

이런 경우에 half-close를 유용하게 쓸 수 있다. 클라이언트는 shutdown을 SHUT_WR 인자와 함께 호출하여 더 이상 서버에게 할 보낼 메시지가 없다는 것을 알리면, 서버는 클라이언트가 종료되는 것으로 인식 한다. 분명히 종료가 되었지만 반만 종료 - half-close. 출력 스트림만 닫았기에 여전히 수신은 가능 상태 - 되었기에 서버가 보내는 시간을 클라이언트는 제대로 인식하고 로그에 남길 수가 있다.

NOTE - shutdown을 이용해 half-close를 하면 나는 아직 소켓이 닫히지 않았지만 상대방은 닫힌 것으로 인식한다.

이번에는 상황을 벗어 나서 좀 더 깊이 들어가보자.

close함수를 호출하여 소켓을 종료 시키려고 한다는 것은 소켓의 레퍼런스 카운트 하나를 줄인다는 것이다. 만일 우리가 dup함수들을 이용해서 파일 디스크립터를 복사 했다고 하자. 그러면 그 파일의 레퍼런스 카운터는 2가 되고, 둘 중에 하나를 close해도 파일은 닫히지 않는다. 결국 dup를 두 번했으면 close도 두번 해줘야 한다는 소리다. 하지만 shutdown을 레퍼런스 카운터에 상관없이 정상적인 connection termination 과정을 시작 할 수 있다는 것이다.(FD가 확실히 닫히는지는 아직 실험 해보지 않아서 잘 모르겠다.)

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!