[네트워크] 소켓의 옵션(sockopt)

minji·2021년 8월 20일
0
post-thumbnail

우리가 특정 소켓을 생성한 후, 해당 소켓의 특성을 조회하거나 설정할 수 있는데 바로 옵션변경을 통해 가능하다.

옵션의 종류

소켓의 옵션은 계층별로 분류되며,

  • ip 계층에 관련된 IPPROTO_IP 레벨

  • tcp계층에 관련된 IPPROTO_TCP 레벨

  • 가장 일반적인 설정에 관련된 SOL_SOCKET 레벨

이렇게 세 가지 계층으로 나뉜다.

프로토콜 레벨옵션명getsockoptsetsockopt
SOL_SOCKETSO_SNDBUF
SO_RCVBUF
SO_REUSEADDR
SO_KEEPALIVE
SO_BROADCAST
SO_DONTROUTE
SO_OOBINLINE
SO_ERROR
SO_TYPE
O
O
O
O
O
O
O
O
O
O
O
O
O
O
O
O
X
X
IPPROTO_IPIP_TOS
IP_TTL
IP_MULTICAST_TTL
IP_MULTICAST_LOOP
IP_MULTICAST_IF
O
O
O
O
O
O
O
O
O
O
IPPROTO_TCPTCP_KEEPALIVE
TCP_NODELAY
TCP_MAXSEG
O
O
O
O
O
O

위의 표에 나열된 옵션들이 각 계층별로 조회(get)하거나 설정(set)할 수 있는 옵션들이다.
당연히 모든 옵션이 조회는 가능하며 몇가지 옵션을 빼고는 변경도 가능하다.

옵션의 조회 및 변경

1) 옵션의 조회

옵션의 조회는 getsockopt 함수를 이용한다.

#include <sys/socket.h>
//성공시 0, 실패시 -1을 반환한다.
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

sock : 소켓의 파일 디스크립터
level : 프로토콜 레벨
optname : 옵션명
optval : 조회결과를 저장할 버퍼의 주소값
optlen : optval에 전달된 버퍼의 크기를 가지고있는 변수의 주소값

예를 들어, SOL_SOCKET 레벨의 SO_TYPE 옵션을 통해 소켓의 타입정보를 확인 하려면 다음과 같이 작성할 수 있다.

{
,,,

int tcp_sock;
socklen_t optlen;
int result;
int so_type;				//조회결과를 담을 위치

optlen=sizeof(sock_type);	//so_type의 크기를 담은 변수
tcp_sock = socket(PF_INET, SOCK_STREAM,0);	//SOCK_STREAM이므로 tcp 소켓

result=getsockopt(tcp_sock, SOL_SOCKET, SO_TYPE, (void*)&so_type, &opt_len); //성공시 0, 실패시 -1

if(result) error!
printf("소켓의 타입 : %d",so_type);	//소켓의 타입 : 1

,,,
}

참고로 소켓의 타입인 SO_TYPE은 get만 가능하며 set은 불가능한 대표적인 옵션이다.
즉, 소켓의 타입은 소켓을 생성할 때 한번 결정되면 변경이 불가능하다.

2) 옵션의 변경

옵션을 변경할때는 setsockopt함수를 이용한다.

#include <sys/socket.h>
//성공시 0, 실패시 -1을 반환한다.
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t *optlen);

sock : 소켓의 파일 디스크립터
level : 프로토콜 레벨
optname : 옵션명
optval : 변경할 옵션정보를 저장한 버퍼의 주소값
optlen : optval로 전달된 옵션정보의 크기(byte)

예를들어 time-wait 상태에 있는 포트의 할당가능여부를 결정하는 옵션인 SO_REUSEADDR은 다음과 같이 설정할 수 있다.

{
,,,

int result;
int reuse_opt;
socklen_t optlen;

reuse_opt=TRUE;
optlen=sizeof(reuse_opt);

setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse_opt, optlen);	//SO_REUSEADDR 옵션을 true로 설정
if(result) error!

,,,
}

cf) time-wait 상태란?

우리가 서버/클라이언트 프로그램을 작동시킬 때, 서버쪽에서 먼저 연결을 끊은 상황을 가정해보자.
이 때, 바로 같은 포트번호로 소켓을 재할당하면 bind()오류가 발생하는 것을 확인할 수 있다. 반면, 조금의 시간을 두고 다시 할당해보면 정상적으로 작동하는 것을 확인할 수 있다.
그 이유는 바로 해당 포트의 소켓이 time-wait 상태에 있었기 때문이다.
즉, time-wait 상태란 연결 해제 요청을 한 쪽에서(서버이든 클라이언트이든) 마지막 ACK를 상대방에게 보낸 후 특정 시간만큼 기다리고 있는 상황을 말한다.
정확히는 2MSL의 시간(패킷이 네트워크 상의 존재할 수 있는 시간의 2배)만큼 기다리는데, 마지막으로 보낸 ACK가 상대에게 전달되지 못했을 상황을 대비하는 것이라고 이해할 수 있다.

다시 돌아와서, SO_REUSEADDR 옵션의 디폴트값은 false이다. 즉, 특정 포트가 time-wait 상태일 때는 재할당 할 수 없다.
이 때, setsockopt 함수를 이용해 해당 옵션을 true로 변경해줌으로써 time-wait 상태의 포트를 다른 소켓에 재할당 할 수 있게 된다.

profile
SW Engineer

0개의 댓글