일반적인 상황에서는 소켓을 생성한 뒤 그대로 사용하여 통신을 진행해도 무방하지만 소켓에 옵션을 설정해서 동작을 바꿔야하는 상황이 발생하기도 한다. 이번 글에서는 소켓의 옵션을 확인하고 설정하는 방법과 흔하게 쓰이는 옵션 네가지(SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR 그리고 TCP_NODELAY)를 알아보자.
소켓의 옵션은 사용하는 프로토콜에 따라 달라질 수 있다. TCP 소켓에 사용할 수 있는 옵션은 3 개의 레벨에 존재하는데 이는 아래와 같다.
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
성공하면 0 실패하면 -1을 반환하는 함수. optval 포인터가 가리키는 메모리에 옵션 확인 결과 값이 들어가고 optlen은 optval 포인터가 가리키는 버퍼의 크기를 나타낸다. 함수 호출이 성공적인 경우, 확인한 옵션 정보의 크기가 optlen에 담긴다. optval 인자가 void 포인터이기에 무엇이 들어가든 상관은 없겠으나 일반적으로 int 배열을 버퍼로 사용한다.
int setsockopt(int sock, int level, int optname, const void *optval, sockeln_t optlen
);
여기에서 optval은 옵션 값을 저장한 버퍼의 주소 값을 나타낸다.
소켓을 통해 통신할 때, 운영체제는 입출력버퍼를 생성하여 이를 사용한다. 매번 write혹은 read를 시도할 때 마다 통신하는 건 비효율적이기 때문이다. 소켓을 생성하면 운영체제가 적절한 크기로 생성해주지만 사용자가 희망 사항을 명시할수도 있다. SO_SNDBUF와 SO_RCVBUF는 각각 출력 버퍼와 입력 버퍼의 크기를 변경하는 옵션이다. 주의해야할 점은 이 옵션을 통해 사용자가 희망하는 버퍼의 크기를 명시하는 것일뿐 희망한 크기로 버퍼가 만들어진다는 보장은 없다는 것이다.
SO_REUSEADDR은 기존에 닫은 소켓에 할당됐던 주소와 포트를 새로운 소켓에 바로 할당할 수 있도록 돕는 옵션이다. 이를 설명하기 전에 Time-wait이 무엇인지 알아보자.
TCP는 연결지향형 프로토콜이다. 즉 데이터를 송수신하기 전에 연결을 생성하고 데이터의 통신이 끝나면 연결을 종료한다. 연결의 종료는 4way handshake라는 과정을 거쳐서 이뤄지는데 아래와 같다.
Time-wait 상태란 소켓을 닫은 이후에, 정해진 시간동안 닫은 소켓의 주소와 포트를 새로운 소켓에 할당하지 못하는 상태를 말한다. 이러한 상태가 존재하는 이유는 존재하지 않을 때를 생각해보면 이해할 수 있다. Time-wait 상태가 존재하지 않는 시스템을 생각해보자. 이 시스템이 소켓을 닫았다고 가정하자. 이 시스템은 ACK 플래그를 세운 빈 메시지를 상대에게 보낸 뒤 연결을 종료할 것이다. 이는 위의 네번째 단계에 해당된다. 이 때 이 ACK 메시지가 상대에게 도달하지 못한다면 상대는 FIN 메시지가 보내지지 않았다는 판단하에 계속해서 재전송할 것이다. 이처럼 연결이 정상적으로 종료가 안되는 경우가 발생할 수 있다. 하지만 Time-wait 상태에 있는 소켓이었다면 ACK 메시지가 상대에게 도달하지 못했을 때 재전송하여 연결을 정상적으로 종료할 수 있을 것이다.
하지만 Time-wait 상태가 존재하는 것도 무조건 좋은 것만은 아니다. 서버 프로그램을 재시작한 경우, 재시작한 시점에 연결된 모든 클라이언트에 재연결할 수 없게된다. Time-wait 상태에 빠지지않도록 만들기 위해서 SO_REUSEADDR 옵션을 사용할 수 있다.
네이글 알고리즘을 적용하거나 해제하는 옵션. 네이글 알고리즘은 이미 보낸 데이터의 수신을 확인하고나서 다음 데이터를 송신하도록 강요한다. 만약 출력 버퍼에 일정한 간격을 두고 데이터를 작성하는 상황을 가정하자. 네이글 알고리즘을 적용하지 않은 상황에서 이 간격이 충분히 길다면, 데이터를 작성할 때마다 상대에게 데이터를 송신할 것이다. 하지만 네이글 알고리즘이 켜져있는 상황이라면 첫 번째 데이터의 수신을 확인한 뒤에 다음 데이터를 송신할 수 있기 때문에 운영체제는 버퍼에 데이터를 충분히 쌓은 후에 송신할 것이다.