TCP에서는 연결과정보다 중요한 것이 종료과정인데, 종료과정에서는 예상치 못한 일이 발생할 수 있기 때문입니다.
close 함수 호출은 송수신을 바로 불가능하게 만드는 완전종료를 의미합니다. 만약 호스트 B가 전송한 데이터가 호스트 A가 꼭 전송받아야 하는데 A가 close를 호출해버리면 호스트 B가 전송한 데이터는 소멸됩니다. 따라서 송신은 가능하지만 발신은 종료하거나 또는 그 반대를 하게 해주는, 데이터의 송수신에 사용되는 스트림의 일부만 종료(half-close)하는 방법이 제공됩니다.
여기서 스트림이란 말이 사용됐는데, 소켓을 통해 두 호스트가 연결되고 데이터의 송수신이 가능한 상태를 스트림이 형성된 상태라고 합니다. 스트림은 단방향성을 가지고 있어, 서로 송수신을 주고받으려면 (양방향 통신을 하려면) 스트림이 2개가 필요합니다. 따라서 두 호스트간 소켓이 연결되면 각 호스트마다 출력 스트림과 입력 스트림이 형성되고, 각자의 출력 스트림은 각자의 입력 스트림을 향합니다. 위에서 말한 half-close는 둘 중 한 스트림만 끊는 것을 뜻합니다.
다음은 half-close에 사용되는 shutdown() 함수입니다.
#include<sys/socket.h>
int shutdown(int sock, int howto);
// success:0 fail:-1
// sock: 종료할 소켓의 파일 디스크립터
// howto: 종료 방법에 대한 정보
howto는 종료 방법에 대한 정보를 담고 있는데, 출력 스트림만 종료할 수도, 입력 스트림만 종료할 수도, 또는 둘 다 종료할 수도 있습니다. 각각 인자 이름은 다음과 같이 define 되어있습니다.
SHUT_RD : 입력 스트림 종료
SHUT_WR : 출력 스트림 종료
SHUT_RDWR : 입출력 스트림 종료
half-close가 필요한 이유는 만약 서버가 클라이언트에게 파일을 전송하고, 파일이 전부 전송되면 클라이언트가 서버에게 무언가의 데이터를 전송하는 상황이라고 가정할 때, 클라이언트는 파일 데이터의 끝이 어딘지, 언제까지 수신해야하는지 모르기 때문입니다. 만약 계속 입력함수를 호출하면 들어온 데이터가 없어 함수가 반환되지 않아 멈출 수 있고, 서로 파일의 끝을 의미하는 문자를 두기엔 서버가 보내는 파일에 그 문자가 있을 수도 있습니다. 따라서 서버는 파일의 전송이 끝났음을 의미하는 EOF를 전송해야 합니다.
EOF는 출력스트림이 종료되면 전송됩니다. 물론 close 함수를 사용해도 출력스트림이 종료되어 EOF가 전송되지만 이 경우 클라이언트가 서버에 보내는 데이터를 서버가 받을 수 없습니다. 따라서 shutdown()함수를 통해 서버의 출력스트림만 종료하면 EOF도 전송되고 서버가 데이터를 수신할 수도 있습니다.
다음은 위 예시의 소스코드입니다.
https://github.com/kjmin622/TCP-IP-Socket-Programing/blob/master/src/file_client.c
https://github.com/kjmin622/TCP-IP-Socket-Programing/blob/master/src/file_server.c
while(1){
read_cnt=fread((void*)buf, 1, BUF_SIZE, fp);
if(read_cnt<BUF_SIZE){
write(clnt_sd, buf, read_cnt);
break;
}
write(clnt_sd, buf, BUF_SIZE);
}
shutdown(clnt_sd, SHUT_WR);
read(clnt_sd, buf, BUF_SIZE);
printf("Message from client: %s \n",buf);
file_server에서, 문자열을 송신한 후, shutdown 함수를 호출해서 출력 스트림을 닫고 클라이언트가 보낸 문자열을 받아오는 모습을 볼 수 있습니다.
'현생 > TCP 소켓 프로그래밍' 카테고리의 다른 글
8-2. 도메인 이름과 IP 간의 변환 [TCP/IP][C][LINUX] (0) | 2022.01.23 |
---|---|
8-1. 도메인이란? 왜 쓰는 걸까? (0) | 2022.01.23 |
6-4 UDP에서의 connect (connected UDP 소켓) [UDP/IP][C][LINUX] (0) | 2022.01.18 |
6-3. UDP의 데이터 송수신 특성 - 데이터의 경계 [UDP/IP][C][LINUX] (0) | 2022.01.18 |
6-2. UDP 기반 간단한 서버와 클라이언트 구현 [UDP/IP][C][LINUX] (0) | 2022.01.18 |