소켓프로그래밍-소켓의 옵션(sockopt)
우리가 특정 소켓을 생성한 후, 해당 소켓의 특성을 조회하거나 설정할 수 있는데 바로 옵션변경을 통해 가능하다.
옵션의 종류
소켓의 옵션은 계층별로 분류되며,
-
ip 계층에 관련된
IPPROTO_IP 레벨
-
tcp계층에 관련된
IPPROTO_TCP 레벨
-
가장 일반적인 설정에 관련된
SOL_SOCKET 레벨
이렇게 세 가지 계층으로 나뉜다.
프로토콜 레벨 | 옵션명 | getsockopt | setsockopt |
---|---|---|---|
SOL_SOCKET | SO_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_IP | IP_TOS IP_TTL IP_MULTICAST_TTL IP_MULTICAST_LOOP IP_MULTICAST_IF | O O O O O | O O O O O |
IPPROTO_TCP | TCP_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 상태의 포트를 다른 소켓에 재할당 할 수 있게 된다.
Author And Source
이 문제에 관하여(소켓프로그래밍-소켓의 옵션(sockopt)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@minji/소켓프로그래밍-소켓의-옵션sockopt저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)