본문 바로가기

programming/WIN API

소켓의 다양한 설정

 

<소켓 옵션들> 

Protocol Level

Option Name

Get

Set

SOL_SOCKET

SO_SNDBUF

SO_RCVBUF

SO_RESUEADDR

SO_KEEPALIVE

SO_BROADCAST

SO_DONTROUTE

SO_OOBINLINE

SO_ERROR


SO_TYPE


IPPROTO_IP

IP_TOS

IP_TTL

IP_MULTICAST_TTL

IP_MULTICAST_LOOP

IP_MULTICAST_IF

IPPROTO_TCP

TCP_KEEPALIVE

TCP_NODELAY

TCP_MAXSEG

 SOL_SOCKET : 이 레벨에서 처리할 수 있는 내용은 송신버퍼와 수신 버퍼의 크기조절, 브로드캐스팅 허용, 연결 여부 확인 등을 처리 할 수 있다.

 OPPROTO_IP, PPROTO_TCP : 이 레벨에서 처리할 수 있는 내용은 IP헤더 포함 여부 결정, IP패킷의 TTL값 변경, Nagle알고리즘 작동 정지 등 프로토콜 종속적인 성격을 갖는 하위레벨에서의 소켓 제어이다.

 SO_SNDBUF: 소켓 생성 시 제공되는 출력버퍼의 크기와 관련된 옵션이고, 소켓의 송신 버퍼와 수신 버퍼 크기를 변경 할 수 있다.

 SO_RCVBUF: 소켓 생성 시 제공되는 입력버퍼의 크기와 관련된 옵션이고,소켓의 송신 버퍼와 수신 버퍼 크기를 변경 할 수 있다.

 SO_REUSEADDR: 이미 사용중인 IP 주소와 포트 번호를 재사용 할 수 있고 이미 사용중인 IP주소와 포트 번호로 bind() 함수를 호출 할 수 있다.
서버 종료 후 재실행시 bind() 함수에서 오류가 발생 하는 것을 방지하고 두 개 이상의 IP주소를 가진 호스트에서 각 IP주소별로 서버를 따로 운용할 수 있도록 한다.

 SO_KEEPALIVE:  TCP 프로토콜 수준에서 연결 여부를 확인 하기 위한 옵션으로 TCP에 약 2시간 간격으로 TCP패킷을 보낸다. 이때 상대 TCP의 반응에 따라 두 가지 경우로 나눌 수 있다. 첫 번째 경우는 상대 TCP가 정해진 시간 이내에 응답을 하는 경우는 TCP 연결에 문제가 없는 경우 이므로 애플리케이션은 이를 알아차리지 못한다. 상대 TCP가 정해진 시간 이내에 응답을 하지 않거나 RSP(reset) 패킷으로 응답할 경우TCP 연결에 문제가 있는 경우 이므로 자동으로 소켓을 닫는다. 이 경우 애플리케이션이 해당 소켓으로 데이터 통신을 하려고 하면 오류가 발생한다.

  SO_KEEPALIVE 옵션을 사용하는 이유는 TCP 연결은 물리적인 연결이 아닌 양쪽에서 상태 정보를 유지하는 가상적인 연결이다. 따라서 데이터 교환이 없다면 상대 호스트가 다운되거나 전원이 나간 경우를 감지 하지 못한다.이때 SO_KEEPALIVE 옵션을 설정해두면 TCP 프로토콜 수준에서 주기적으로 끊어진 연결을 감지하여 불필요하게 열린 소켓을 닫을 수 있게 된다. 
  SO_KEEPALIVE 옵션은 TCP 소켓에만 사용할 수 있다.  UDP는 프로토콜 수준에서 SO_KEEKALIVE에 대응하는 기능을 제공하지 않기 때문이다.
 TCP 소켓에 사용할 때 일반적으로 TCP 서버의 연결 대기 소켓 (listening socket)에 대해 설정하며, 이 경우 accept() 함수가 리턴하는 소켓도 자동으로 이 옵션 이 설정된다.

 SO_BROADCAST: 해당 소켓을 이용하여 브로드 캐스트 데이터를 보낼 수 있다. 프로토콜 특성상 TCP 소켓에는 사용할 수 없고, UDP 소켓에만 사용할 수 있다.

 SO_DONTROUTE: TCP/IP 애플리케이션이 보내는 데이터는 라우팅 테이블 (routing table 또는 route table)이라 부르는 정보를 참조하여 하부의 IP 프로토콜이 보내게 된다.
  - SO_DONTROUTE 옵션을 설정하면 데이터 전송 시 라우팅 테이블 참조를 생략하고, 곧바로 bind() 함수로 설정한 네트워크 인터페이스로 모든 데이터를 보내게 된다.
  - SO_DONTROUTE 옵션은 TCP와 UDP소켓에 모두 사용할 수 있으며, 특히 TCP 서버의 연결 대기 소켓(listening socket)에 대해 이 옵션을 설정해두면accept() 함수가 생성하는 새로운 소켓도 자동으로 동일한 옵션이 설정된다. 
 
 SO_OOBINLINE: 옵션을 설정하면 OOB 데이터는 수신 함수의 스트림에 섞여서 리턴 된다. 따라서 SO_OOBLINE 옵션을 설정하여 수신한 경우에는 ioctlsocket 함수를 SIOCATMARK 옵션으로 호출하여 어떤 바이트가 OOB 데이터인지 구별해야 한다.

 SO_ERROR: 오류 상태를 반환하고 지운다.

<현재 설정 상태 정보를 가져오는 함수> 

int getsockopt(int sock, int level, int optname, int void *optval,
                 socklen_t  *optlen);

sock     : 설정 상태를 확인해 보고 싶은 소켓의 파일 디스크립터를 인자로 전달한다.
level     : 확인할 옵션의 프로토콜 레벨을 인자로 전달한다.
Optname : 확인할 옵션의 이름을 전달한다.
optval    : 확인 결과를 저장할 버퍼를 가리키는 포인터를 전달한다.
optlen  : optval 포인터가 가리키는 버퍼의 크기를 전달한다.함수 호출이 완료되면, 전달된 포인터가 가리키는 변수에는 버퍼에 저장된 확인 결과의 길이가 바이트 단위로 저장된다.  

                                              <옵션을 변경하는 함수>
Int setsockopt(int sock, int level, int optname, const void *optval,
                         socklen_t  optlen);

sock     : 설정 상태를 변경하고자 하는 소켓의 파일 디스크립터를 인자로 전달한다.
level      :변경할 옵션의 프로토콜 레벨을 인자로 전달한다.
optname: 변경할 옵션의 이름을 전달한다.
optval    : 변경할 옵션의 값을 저장한 버퍼의 포인터를 전달한다.
optlen    :전달하는 옵션의 바이트 단위 길이를 전달한다.
 
프로토콜 레벨이 SOL_SOCKET이고 이름이 SO_TYPE인 옵션을 이용하면, 소켓의 타입 정보를 얻어 올 수 있다. 소켓을 생성하고 나서 타입 정보를 얻어오는 예제이다.
 #include <stdio.h>
#include <stdlib.h>
#include <unisrd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
void error_handling(char * message);
int main(int argc,char **argv){
   int tcp_sock, udp_sock;
   int sock_type=-1;
   socklen_t optlen;
    int state;
    optlen=sizeof(sock_ttype);
    tcp_sock=socket(PF_INET, SOCK_STREAM, 0);
    udp_sock=socket(PF_INET, SOCK_DGRAM, 0);
    printf(“SOCK_STREAM : %d \n”, SOCK_STREAM);
    printf(“SOCK_DGRAM : %d \n”, SOCK_DGRAM);
   state=getsockopt(tcp_sock , SOL_SOCKET , SO_TYPE , &sock_type ,  &optlen);
    if(state)
        error_handling(“getsockopt()  error!”);
    printf(“첫 번째 소켓의 타입은 %d \n”,sock_type);
    state=getsockopt(“udp_sock , SOL_SOCKET SO_TYPE, &sock_type, &optlen”);
    if(state)
         error_handling(“getsockopt() error!”);
    printf(“두 번째 소켓의 타입은 %d \n”, sock_type);
    return 0;
}
void error_handling(char * message)
{
     fputs(message , srderr);
     fputc(‘\n’, stderr);
     exit(1);
}

<TIME-WAIT 상태>

1. TIME-WAIT 상태란 ?

 - 연결 종료 시 마지막 패킷 전송 실패를 대비하기 위한 상태.


2. 서버의 연결 종료

 - 서버에서 먼저 종료 요청 후, 다시 서버를 가동 시키면 ?


3. TIME-WAIT 타어의 재시작

 - TIME - WAIT 상태는 우리의 생각보다 더 길어 질 수 있다.


4. SO_REUSEADDR

 - TIME-WAIT 상태에 있는 서버의 IP와 PORT를 재할당 하도록 옵션 설정.



<Nagle 알고리즘>

1. NAgle 알고리즘에 대한 이해.

 - 네트워크 상의 패킷 수를 줄이기 위해 제안된 알고리즘

 - ACK를 수신해야만 다음 전송을 진행하는 알고리즘


2. NAgle 알고리즘의 장점과 단점

 - 장점: 네트워크의 효율성이 높아진다 (적은 패킷의 양)

 - 단점: 전송 속도가 느리다 (ACK 수신 후 패킷 전송)

- 생각해 볼 문제: Nagle 알고리즘의 중단이 데이터 전소 속도를 무조건 향상 시켜주는 것은 아니다.

3. TCP_NODELAY

 - Nagle 알고리즘을 Disable 시키기 위한 옵션의 변경

 - TCP 소켓은 생성시 기본적으로 Nagle 알고리즘 적용


4. NAgle 알고리즘의 예

 #pragma comment(lib,"ws2_32")
#include <winsock2.h>
#include <stdio.h>

void main()
{
 WSADATA wsadata;
 WSAStartup(MAKEWORD(2,0),&wsadata);

 SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

 SOCKADDR_IN servaddr={0,};
 servaddr.sin_addr.s_addr = inet_addr("192.168.34.130");
 servaddr.sin_port = htons(1000);
 servaddr.sin_family = PF_INET;

 bind(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));

 listen(sock,5);

DWORD val=TRUE;
 int len = sizeof(val);
 setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char*)&val,len); //TCP_NODELAY가 TRUE이면 Nagle 알고리즘 적용 안 함,
  //TCP_NODELAY가 FALSE면 Nagle 알고리즘 적용
getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&val,&len);
 
 printf("%d",val);
 WSACleanup();
}



P.S 이글은 친구꺼 참고하여 (거의;;) 작성한 것입니다. 친구도 아마 책이나 어디서 보고 한 것같은데..출처를 모릅니다 ㅋㅋ;
출처아시는분 있으시면 덧글달아주세요 바로 출처 남기도록 하겠습니다.

'programming > WIN API' 카테고리의 다른 글

WSA 에러들  (0) 2011.02.24
WSAGetLastError  (0) 2011.02.23
서브 클래싱이란.?  (0) 2010.12.24
GDI 오브젝트 절차  (0) 2010.05.14
TreeView 연습  (0) 2010.02.17