728x90
- 07-1 TCP 기반의 Half-close
- 일반적인 연결 종료의 문제점
- 리눅스의 close수호출과 윈도우의 closesocket함수호출은 완전종료를 의미
- 완전 종료는 데이터를 전송하는 것은 물론 수신하는 것 조차 더 이상 불가능한 상황을 의미한다.
- 호스트 A 가 마지막 데이터를 전송하고 나서 close 함수의 호출을 통해서 연결을 종료한다면 그 이후부터 호스트 A는 호스트 B가 전송하는 데이터를 수신하지 못한다. 결국엔 호스트 A가 반드시 수신해야 할 데이터라 할지라도 그냥 소멸되고 만다.
- 위 예시처럼 반드시 수신해야할 데이터가 소멸되지 않게 하기위해 스트림의 일부만종료(Half-close)하는 방법이 제공되고 있다.
- 일부를 종료한다는 것은 전송은 가능하지만 수신은 불가능한 상황 혹은 수신은 가능하지만 전송은 불가능한 상황을 뜻한다. 말 그대로 스트림의 반만 닫는 것이다.
- 소켓과 스트림(Stream)
- 소켓을 통해서 두 호스트가 연결되면 그 다음부터는 상호간에 데이터의 송수신이 가능한 상태가 된다.
- 상호간에 데이터의 송수신이 가능한상태를 가리켜 "스트림이 형성된 상태" 라고한다.
- 스트림은 물의 흐름을의미한다. 그런데 물의 흐름은 한쪽 방향으로만 형성된다 마찬가지로 소켓의 스트림 역시 한쪽 방향으로만 데이터의 이동이 가능하기 때문에 양방향 통신을 위해서는 두 개의 스트림이 필요하다.
- 두 호스트간에 소켓이 연결되면, 각 호스트 별로 입력 스트림과 출력 스트림이 형성된다.
- 한 호스트의 입력 스트림은 다른 호스트의 출력 스트림으로 이어지고, 한 호스트의 출력 스트림은 다른 호스트의 입력 스트림으로 이어진다.
- 우아한 종료라는 것은 한번에 입력 스트림과 출력 스트림을 모두 끊어버리는 것이 아니라 이 중 하나의 스트림만 끊는것이다. 물론 리눅스의 close함수와 윈도우의 closesocket함수는 두가지 스트림을 동시에 끊어버리기 때문에 우아한 연결종료와는 거리가 멀다.
- 우아한 종료를 위한 shutdown 함수
- #include<sys/socket.h>
int shutdown( int sock, int howto );
-> 성공시 0, 실패시 -1 반환
- 매개변수 의미
- sock : 종료할 소켓의 파일 디스크립터 전달.
- howto : 종료 방법에 대한 정보 전달
- 함수호출시 두번째 매개변수에 전달되는 인자에 따라서 종료의 방법이 결정된다. 두 번째 매개변수에 전달될 수 있는 인자의 종류는 다음과 같다.
- SHUT_RD : 입력 스트림 종료 ( shutdown read )
- SHUT_WR : 출력 스트림 종료 ( shutdown write )
- SHUT_RDWR : 입출력 스트림 종료 ( shutdown readwrite )
- shutdown 함수의 두번째 인자로 SHUT_RD가 전달되면 입력 스트림이 종료되어 더 이상 데이터를 수신할 수 없는 상태가 된다. 혹 데이터가 입력버퍼에 전달되더라도 그냥 지워져 버릴 뿐만 아니라 입력 관련 함수의 호출도 더 이상은 허용이 안 된다.
- SHUT_WR가 두 번째 인자로 전달되면 출력 스트림이 종료되어 더이상의 데이터 전송이 불가능해 진다. 단 출력 버퍼에 아직 전송되지 못한 상태로 남아있는 데이터가 존재하면 해당 데이터는 목적지로 전송된다.
- SHUT_RDWR가 전달되면 입력 스트림과 출력 스트림이 모두 종료되는데 이는 shutdown함수를 한번은 SHUT_RD를 인자로 또 한번은 SHUT_WR을 인자로 두 번 호출한 것과 같다.
- Half-close가 필요한 이유
- 연결종료 직전에 클라이언트가 서버에 전송해야할 데이터가 존재하는 상황에서 파일을 전송하는 서버는 단순히 파일 데이터를 연속해서 전송하면 되지만 클라이언트는 언제까지 데이터를 수신해야 할지 알수 없기 때문에 클라이언트 입장에서는 무턱대고 계속해서 입력함수를 호출할 수도 없다 만약 입력함수를 계속 호출한다면 블로킹상태(호출된 함수가 반환하지 않는 상태)에 빠질수 있기 때문이다.
- 서버와 클라이언트 사에에 파일의 끝을 의미하는 문자하나를 약속하면 되지않을까 싶지만 약속으로 정해진 문자와 일치하는 데이터가 파일에 존재할 수 있기 때문에 서버는 파일의 전송이 끝났음을 알리는 목적으로 EOF를 마지막에 전송해야한다. 클라이언트는 EOF의 수신을 함수의 반환값을 통해서 확인이 가능하기 때문에 파일에 저장된 데이터와 중복될 일도 없다.
- 출력 스트림을 종료하면 상대 호스트로 EOF가 전송된다.
- 물론 close함수호출을 통해서 입출력 스트림을 모두 종료해줘도 EOF는 전송되지만 이럴 경우 상대방이 전송하는 데이터를 더 이상 수신 못한다는 문제가 있다.
- 즉 close함수호출을 통해서 스트림을 종료하면 클라이언트가 마지막으로 보내는 문자열 Thank you를 수신할 수 없다. 따라서 shutdown함수호출을 통해서 서버의 출력 스트림만 half-close해야하는 것이다. 이럴경우 EOF도 전송되고 입력 스트림은 여전히 살아있어서 데이터의 수신도 가능하다.
728x90
'책 > 윤성우 TCPIP' 카테고리의 다른 글
09-1 소켓의 옵션과 입출력 버퍼의 크기 (0) | 2020.12.10 |
---|---|
chapter 08 -2 , ip주소와 도메인 이름 사이의 변환 (3) (0) | 2020.12.09 |
< 08-2 : IP 주소와 도메인 이름 사이의 변환 예제 > (0) | 2020.12.08 |
Chapter 08 도메인 이름과 인터넷 주소 (0) | 2020.12.07 |
ubuntu vscode 에서 메인함수 argv[] 인자에 값 넣는법 (0) | 2020.11.13 |