Coding Memo

Socket Option - (get/set)sockopt() 본문

Game Server (C++)

Socket Option - (get/set)sockopt()

minttea25 2022. 11. 7. 18:35

본 포스팅은 인프런에 등록되어 있는 Rockiss 님의 강의를 보고 간단하게 정리한 글입니다.


socket을 만들고 이 소켓에 대한 여러가지 세팅을 해줄 수 있다.

 

다음의 함수를 이용한다. 

setsockopt()

int setsockopt(
  [in] SOCKET     s,
  [in] int        level,
  [in] int        optname,
  [in] const char *optval,
  [in] int        optlen
);
SOCKET s 설정을 할 타켓 소켓
int level 옵션이 정의될 레벨 (SOL_SOCKET 이용)
int optname 설정할 옵션 이름
const char* optival 설정할 옵션의 값
int optlen 설정할 옵션의 값의 크기

char*로 옵션의 값을 받는 이유는 옵션에 대한 값을 여러가지 타입으로 받기 위해서이다. (따라서 길이도 필요하다.)

 

 

자세한 내용은 다음의 문서에 나와있다.

https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt

 

setsockopt function (winsock.h) - Win32 apps

The setsockopt function (winsock.h) sets a socket option.

learn.microsoft.com

 

참고로 set 목적이 아닌 단순 get 목적인 경우에는 getsockopt()라는 함수도 있다.

int getsockopt(
  [in]      SOCKET s,
  [in]      int    level,
  [in]      int    optname,
  [out]     char   *optval,
  [in, out] int    *optlen
);
SOCKET s 설정을 확인할 소켓
int level 옵션이 정의된 레벨
int optname 확인할 옵션이름
char [out] optival 확인할 옵션의 값 할당
int [out] optlen 확인할 옵션의 값의 크기 할당

 

level은 옵션을 해석하고 처리할 주체로

소켓 코드 : SOL_SOCKET

IPv4 : IPPROTO_IP

TCP Protocol: IPPTORO_TCP

등을 사용할 수 있다.

 

setsockopt, getsockopt 두 함수 모두 에러 없이 처리가 되었다면 0을 반환한다.


문서를 보면 여러가지 옵션들이 나와있는데 그 중 몇 개만 알아보자.

 

1. SO_KEEPALIVE

 

TCP 연결에서 주기적으로 연결 상태를 확인할지를 결정하는 옵션이다.

만약 상대방이 갑작스럽게 연결을 끊을 수도 있는 상황이 발생할 수도 있기 때문에, 이 옵션으로 주기적으로 TCP 프로토콜 연결 상태를 확인하여 끊어진 연결을 감지해 낼 수 있다. (SOL_SOCKET)

 

값: 0 or 1 [bool]

bool enable = true;
::setsockopt(serverSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&enable, sizeof(enable));

 

 

2. SO_LINGER

 

socket이 closed 되었을 때, 송신 버퍼에 남아있는 데이터를 보낼 것인지 아니면 버릴 것인지를 결정하는 옵션이다.

send를 호출 한 직후에 바로 closesocket으로 소켓을 바로 닫아버렸을 때, socket은 닫힌 상태이므로 send가 되지 못한다. 이를 방지하기 위해서 송신 버퍼에 남아있는 데이터를 보낼 수 있도록 지연 시간을 지정해줄 수 있다.

l_linger 값만큼 지연하여 l_linger 초 만큼 대기 후 (데이터를 보낼 시간을 주고) 소켓을 닫게 된다. (SOL_SOCKET)

(l_linger 기본값은 0이다.)

 

값: LINGER (l_onoff: 사용 여부, l_linger: 대기 시간)

struct  linger {
        u_short l_onoff;                /* option on/off */
        u_short l_linger;               /* linger time */
};
LINGER linger;
	linger.l_onoff = 1; // true
	linger.l_linger = 5; // 대기 시간
	::setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger));

 

참고: shutdown 함수로 socket을 완전히 닫지 않고 send/recv를 각각 허용하거나 닫을 수 있다.

closesocket을 바로 하지 말고 상대방이 계속 데이터를 보낼 수도 있으니 이 함수를 이용하는 것도 linger를 사용하는 방법과 비슷하다.

더보기

SD_SEND: send만 막음

SD_RECIEVE: recv만 막음

SD_BOTH: 둘 다 막음

::shutdown(serverSocket, SD_SEND);

 

3. SO_SNDBUF / SO_RCVBUF

 

소켓의 SendBuffer의 크기와 ReceiveBuffer의 크기를 지정할 수 있다. 

또한, getsockopt로 기본 설정되어 있는 크기를 출력해 보면 둘다 65536 bytes (64Kb)인 것을 알 수 있다. (SOL_SOCKET)

 

값: int

int sendBufferSize;
int optionLen = sizeof(sendBufferSize);
::getsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufferSize, &optionLen);
// default: 65536 bytes (64KB)

int recvBufferSize;
optionLen = sizeof(recvBufferSize);
::getsockopt(serverSocket, SOL_SOCKET, SO_RCVBUF, (char*)&recvBufferSize, &optionLen);
// default: 65536 bytes (64KB)

 

 

4. SO_REUSEADDR

 

IP 주소와 port를 재사용 할 수 있도록 하는 옵션이다.

어떤 프로그램이 종료된 후에 그 프로그램에서 bind 되어있는 소켓의 포트의 점유가 바로 풀리는 것이 아닌 잠시동안 계속 점유하고 있을 때가 있는데, 이 상황에서 그 포트를 사용하고 싶다면 이 옵션을 이용하면 된다.

(만약 이미 bind 되어 있는 포트로 다시 bind를 하려고하면 에러가 날 것이다.) 

사용하는 것이 편하다! (SOL_SOCKET)

 

값: 0/1 [bool]

bool enable = true;
::setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&enable, sizeof(enable));

 

5. TCP_NODELAY

 

Nagle 알고리즘 작동 여부에 관한 옵션이다.

TCP_NODELAY

데이터가 충분히 크면 보내고, 그렇지 않으면 데이터가 충분히 쌓일때 까지 대기 후, 쌓인 후에 패킷을 보내는 알고리즘이다.

작은 패킷이 불필요하게 많이 생성되고 전송되는 일을 막을 수 있지만, 바로바로 전송되지 않기 때문에 반응 시간에 손해가 있다. (따라서 반응시간이 중요한 게임에서는 일반적으로 잘 사용되지 않는다.)

 

* level 지정 시 IPPROTO_TCP로 해야한다.

 

값: 0/1 [bool] 

bool enable = true;
::setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY, (char*)enable, sizeof(enable));

 

6. SO_RCVTIMEO / SO_SNDTIMEO

 

send 한거나 recv할 시 blocking 되는 시간을 지정 할 수있다. (단위: milliseconds)

지정된 시간이 지나면 send나 recv함수는 -1를 반환한다.

 

값: DWORD (window에서 unsinged long)

unsigned long t = 10000;
::setsockopt(serverSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&t, sizeof(t));


unsigned long tt;
int tts = sizeof(tt);
getsockopt(serverSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&tt, &tts);
cout << tt << " " << tts << endl;

 

'Game Server (C++)' 카테고리의 다른 글

Socket IO - Select  (0) 2022.11.18
Non-blocking Socket  (0) 2022.11.18
Socket Programming - UDP  (0) 2022.11.03
Socket Programming - TCP  (0) 2022.10.31
Socket Programming Basic  (0) 2022.10.18