본문 바로가기
TCP/IP

getsockopt() , setopt () 함수

by 상레알 2011. 5. 2.
출처 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Network_Programing/Documents/SocketAPI


네트워크 환경은 매우 다양하며, 예측하기 힘든 경우도 많이 발생한다. 떄문에 네트워크 프로그램의 종류에 따라서

소켓의 세부사항을 조절해야 하는 경우가 발생한다. 이러한 소켓 옵션 설정ㅇ르 위해서 소켓은 getsockopt() 와

setsockopt() 두개의 함수를 제공한다. 이름에서 알 수 있듯이 getsockopt는 현재 소켓옵션값을 가져오기 위해서

,setsockopt는 소켓옵션값을 변경하기 위해서 사용한다.

예를 들자면 동일한 네트워크 프로그램이라도 ATM망에서 작동하는 것과 인터넷망 PPP에서 작동하는 것은 환경에

있어서 차이가 생길 수 밖에 없을 것이다. 소켓 버퍼의 크기를 예로 들자면, 일반적으로 (대역폭 * 지연율) *2 의 공식에

따를 경우 최적의 효과를 보여준다고 한다.


#include <sys/types.h>
#include <sys/socket.h>
int getsockopt (int s, int level, int optname, void * optval, socklen_t *optlen);
int setsockopt (int s, int lelvel, int optname, const void * optval, socklen_t optlen);

s : 소켓지정번호
level : 소켓의 레벨로 어떤 레벨의 소켓정보를 가져오거나 변경할 것인지를 명시하며, SOL_SOCKET와 IPPROTP_TCP
         중 하나를 사용할 수 있다.
optname : 설정을 위한 소켓옵션의 번호
optval : 설정값을 저장하기 위한 버퍼의 포인터
optlen : optval 버퍼의 크기

SOL_SOCKET레벨에서 사용할 수 있는 옵션과 데이타 형은 다음과 같다.

옵션값

데이터형

설명

SO_BROADCAST

BOOL

브로드캐스트 메시지 전달이 가능하도록 한다.

SO_DEBUG

BOOL

디버깅 정보를 레코딩 한다.

SO_DONTLINGER

BOOL

소켓을 닫을때 보내지 않은 데이터를 보내기 위해서 블록되지 않도록 한다.

SO_DONTROUTE

BOOL

라우팅 하지 않고 직접 인터페이스로 보낸다.

SO_GROUP_PRIORITY

int

사용하지 않음

SO_KEEPALIVE

BOOL

Keepalives를 전달한다.

SO_LINGER

struct
LINGER

소켓을 닫을 때 전송되지 않은 데이터의 처리 규칙

SO_RCVBUF

int

데이터를 수신하기 위한 버퍼공간의 명시

SO_REUSEADDR

BOOL

이미 사용된 주소를 재사용(bind) 하도록 한다.

SO_SNDBUF

int

데이터 전송을 위한 버퍼 공간 명시


SO_REUSEADDR

소켓을 이용한 서버 프로그래을 운용하다 보면 강제종료되거나 비정상 정료되는 경우가 발생한다. 테스트 목적으로

할 경우에는 특히 강제종료 시켜야 하는 경우가 자주 발생한느데, 강제 종료 시키고 프로그램을 다시 실행 시킬 경우

다음 과 같은 메시지를 종종 보게 된다...

     bind error : address already in use

이는 기존 프로그램이 종료 되었지만, 비정상종료된 상태로 아직 커널이 bind 정보를 유지하고 있음으로 발생한는 문제
이다. 보통 1-2분 정도 지나면 커널이 알아서 정리를 하지만, 그 시간 동안 기다려야 한다는 것은 상당히 번거로운 일이
될 것이다. 이 경우 다음과 같은 코드를 삽입함으로써 문제를 해결 할 수 있다.

    int sock = socket(  . . .);
    setsockopt(sock, SOL_SOCKET,SO_REUSEADDR, (char *)&bf, (int) sizeof(bf));
이렇게 하면 커널은 기존에 bind로 할당된 소켓자원을 프로세스가 재 사용할 수 있도록 허락하게 된다.

다음은 소켓 버퍼의 크기를 가져오고 설정하는 완전한 코드다.

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main( int argc, char **argv)
{
int  sockfd;
int bufsize;
int rn;

if((sockfd = socket(AF_INET,SOCK_STREAM, 0)) < 0) {
   perror("ERROR");
   return 1;
}
rn = sizeof(int);
// 현재 RCVBUF 값을 얻어 온다.
if(getsockopt(sockfd,SOL_SOCKET, SO_RCVBUF ,&bufsize, (socklen_t *)&rn ) <0 ){
    perror("Set Error");
    return 1;
}
printf("Socket Rcv Buf Size is %d\n, bufsize);
// 버퍼의 크기를 100000 으로 만든다.
bufsize =100000 ;

if(setsockopt(sockfd,SOL_SOCKET, SO_RCVBUF, (void *)&bufsize, (socklen_t)rn) <0 ) {
   perror("Set Error");
   return 1;
}
return 0;
}

TCP_NODELAY

이 옵션을 이해하려면 Nagle 알고리즘에 대해서 이해를 해야된다. Nagle 알고리즘이 적용되면 , 운영체제는 패킷을
 
ACK가 오기를 기다렸다가 도착하면, 그동안 쌓여 있던 데이터를 한꺼번에 보내게 된다. 이러한 방식을 사용하게 되면,

대역폭이 낮은 WAN에서 빈번한 전송을 줄이게 됨으로 효과적인 대역폭 활용이 가능해 진다.

대부분의 경우에 있어서 Nagle 알고리즘은 효율적으로 작동하긴 하지만, 빈번한 응답이 중요한 서비스의 경우에는

적당하지 않은 경우가 발생한다. 예를 들어 X-Terminal을 이용할 경우 마우스 이벤트는 즉시 전달될 필요가 있는데,

Nagle알고리즘을 사용하면 아무래도 반응시간이 떨어지게 될 것이다. 실시간적인 반응이 중요한 온라인 게임 역시

Nagle 알고리즘을 제거하는게 좋을 것이다.

http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/2/setsockopt?action=download&value=nagle.png


SO_LINGER

SO_LINGER은 소켓이 close() 되었을때, 소켓 버퍼에 남아 있는 데이터를 어떻게 할 것인지를 결정하기 위해서

사용한다.다음은 SO_LINGER 옵션에 사용되는 데이터 구조체이다.

struct linger
{
int    l_onoff;
int    l_linger;
}
l_onoff : linger 옵션을 끌것인지 킬 것인지 결정
l_linger : 기다리는 시간의 결정

위의 두개의 멤버 변수의 값을 어떻게 하느냐에 따라 3가지 close 방식을 결정되어 진다.

1. l_onoff == 0 : 이 경우 l_linger의 영향을 받지 않는다. 소켓의 기본설정으로 소켓버퍼에 남아 있는 모든 데이터를
   보낸다.  이때 close()는 바로 리턴을 하게 되므로 백그라운드에서 이러한 일이 일어나게 된다. 
   우아한? 연결종료를 보장한다.

2. l_onoff >0 이고 l_linger == 0 : close()는 바로 리턴을 하며, 소켓버퍼에 아직 남아 있는 데이터는 버려 버린다. 
   TCP 연결상태일 경우에는 상대편 호스트에 리셋을 위한 RST 패킷을 보낸다. hard 혹은 abortive 종료라고 부른다.

3. l_onoff > 0 이고 l_linger > 0  : 버퍼에 남아 있는 데이터를 모두 보내는 우아한 연결 종료를 행한다.  이때 close()
   에서는 l_linger에 지정된 시간만큼 블럭상태에서 대기한다. 만약 지정된 시간내에 데이터를 모두 보냈다면 리턴이
   디고 , 시간이 초과되었다면 에러와 함께 리턴이 된다.

'TCP/IP' 카테고리의 다른 글

Nagle 알고리즘  (0) 2011.05.02
ioctl : 장치 제어 함수  (0) 2011.04.29
소켓 함수 및 헤더들  (0) 2011.02.07
sendto()  (0) 2010.03.28
SOCKADDR_IN 구조체  (0) 2010.03.28
SOCKET() 함수  (0) 2010.03.25
Linux: SOCK_PARCKET  (0) 2009.12.03
ICMP 프로토콜  (0) 2009.11.16
인터넷 소켓 활용  (0) 2009.08.31
TCP/IP 열혈 강의  (0) 2009.08.12