순서

I. 일반적인 소켓 연결종료와 문제점
(close())

II. 소켓과 스트림

III. Half-close

IV. Half-close 구현 함수
(shutdown())


I. 일반적인 소켓 연결종료와 문제점

일반적인 통신 상황을 상상해보자.

연결 - 데이터 송/수신 - 연결종료

여기서 연결을 종료하는 부분에 집중해보자.

언제 연결을 끊을 것인가?

보통 서버는 서버대로, 클라이언트는 클라이언트 대로
데이터의 송수신이 끝나면 일방적으로 close()로 소켓을 닫아버린다.

이때 송신할 데이터는 다 송신했다고 해도,
아직 상대방이 데이터를 안보냈다면?? 이것은 데이터의 손실이다.

그렇다면 마지막 데이터 수신을 기다려야 한다.
하지만.....언제까지.....??

이런 딜레마는 close 함수가 스트림을 모두 끊는 문제 때문에 발생한다.

 


II. 소켓과 스트림(Stream)

소켓을 통해 우리는 서버와 클라이언트를 연결한다.

연결 이후 데이터를 송/수신 할 때,
각 소켓에는 입력버퍼, 출력버퍼가 존재하고
두 호스트의 버퍼끼리 연결되는 두 개의 스트림이 생성된다.

이를 그림으로 나타내면 아래와 같다.

두 호스트간 소켓이 연결되면 호스트는 각각 입력,출력 스트림이 형성된다.

일반적으로 사용하는 close() 함수는 두 개의 스트림을 동시에 모두 끊고,
half-close의 shutdown() 함수는 하나의 스트림만 끊는 것이다.

따라서 I. 에서 말한 문제점을 half-close를 이용해
출력 스트림만 끊어 해결할 수 있는 것이다.


(상대편도 다 보내면 half-close해주면 결과적으로 두 개 모두끊겨 연결 종료)

 


III. Half-Close

위에서 소켓을 반만 닫는 것에 대한 의미를 설명하였다.

그렇다면 왜 필요할까?

(I.에서 어느정도 문제점을 이야기 했지만..)

물론, 급히 종료하지 않고 충분히 여유를 두고 닫으면 된다.

하지만 데이터를 모두 수신하고 확인의 의미로 어떤 데이터를 송신한다고 생각해보자.

이 상황에서 얼마나 충분히 여유를 두어야 하는지도 모르고,
계속해서 read함수를 반복 호출 할 수도 없다.

따라서 우리는 shutdown함수를 통해서 EOF를 전송을 해야한다.

이렇게 되면 EOF도 전송되면서 하나의 스트림은 여전히 살아있어서 데이터 입력 혹은 출력도 가능하다.

 


IV. Half-close 구현 함수

Half-close를 구현하기 위한 함수는 다음과 같다.

Linux

#include <sys/socket.h>

int shutdown(int sock, int howto);
    --> 성공 시 0, 실패 시 -1반환
    ㄴ. sock    : 종료할 소켓의 파일 디스크립터
    ㄴ. howto   : 종료방법에 대한 전달.
    
howto 옵션정보

SHUT_RD   : 입력 스트림 종료
SHUT_WR   : 출력 스트림 종료
SHUT_RDWR : 입출력 스트림 모두 종료
Window

#include <winsock2.h>

int shutdown(SOCKET sock, int howto);
    --> 성공 시 0, 실패 시 -1반환
    ㄴ. sock    : 종료할 소켓핸들
    ㄴ. howto   : 종료방법에 대한 전달.
    
howto 옵션정보

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

만약 하나의 스트림을 종료시키면

함수호출도 안되지만, 만약 버퍼에 데이터가 남아있다면,
해당 데이터는 종료 전에 목적지로 전송 시켜준다.

+ Recent posts