소켓의 다양한 옵션 -------------------------------------------------------------------------------------------------


소켓어 적용할수 있는 다양한 옵션들을 정리해봤다.



GET은 함수를 통해서 이 인자값을 가져올수 있는지에 대한 표이며, SET은 함수를 통해서 이 옵션이 변경 가능한 것인지를 나타낸다. 

즉 에러와 소켓 타입은 변경이 불가능하다. TCP소켓을 UDP소켓으로 변경하는건 함수를 통해서는 안된다는 것이다.

(다른 방법이 있을수도 있으니 확언은 안한다. 아예 기계어 수준에서 제어해버린다던가 항상 방법은 존재하는 법이니까.)


옵션의 확인 함수 -------------------------------------------------------------------------------------------------


sock: 설정 상태를 확인해 보고 싶은 소켓의 파일 디스크립터를 인자로 전달한다.

level: 확인할 옵션의 프로토콜 레벨(Protocol Level)을 인자로 전달한다.

optname: 확인할 옵션의 이름을 전달한다.

oprval: 확인 결과를 저장할 버퍼를 가리키는 포인터를 전달한다.

optlen: optval 포인터가 가리키는 버퍼의 크기를 전달한다. 함수 호출이 완료되면, 전달된 포인터가 가리키는 변수에는 버퍼에 저장된 확인 결과의 길이가 바이트 단위로 저장된다.

 

옵션의 변경 -------------------------------------------------------------------------------------------------



sock: 설정 상태를 변경하고자 하는 소켓의 파일 드스크립터를 인자로 전달한다.

level: 변경할 옵션의 프로토콜 레벨을 인자로 전달한다.

optname: 변경할 옵션의 이름을 전달한다.

optval: 변경할 옵션의 값을 저장한 버퍼의 포인터를 전달한다.

optlen: 전달하는 옵션의 바이트 단위 길이를 전달한다.


중요한 인자값들 -------------------------------------------------------------------------------------------------

SO_SNDBUF & SO_RCVBUF

소켓이 생성되면 기본적으로 입력버퍼와 출력버퍼가 생성된다. 이를 제어할수 소켓의 옵션이다.


SO_REUSEADDR

Time_wait상태에 대한 이해가 필요한 옵션이다.


Time_wait란?

TCP연결을 종료하기 위해서는 FIN패킷 교환이 이루어진다. 이때 우아한 종료가 이루어지기 위해서는 총 4번의 패킷교환이 필요하다.


우아한 종료라는 것은 연결된 호스트 양쪽이 모두 연결이 종료되었음을 알게 되는 상태다. 만약 FIN 패킷을 보냈는데, 상대 호스트에서 ACK 패킷을 보내지 않고 종료해버리는 경우 FIN을 보낸측은 우아한 종료를 위해서 일정시간 ACK를 기다리게 된다. 리눅스의 경우 대략 90초 정도를 기다린다. netstat(1)로 확인해 보면 TIME_WAIT인 상태로 나타난다.


TIME_WAIT상태일 경우 해당 포트를 계속 점유하는데, 연결이 빈번한 네트워크 서비스일 경우 연결거부와 관련된 문제가 발생할 수 있다.

호스트 A와 호스트B가 있다고 했을때 호스트 B가 FIN메세지를 보냈다. FIN메세지를 보낸후 호스트 A가 그에 대한 ACK 메세지를 보내줘야 한다. 그런데 그전에 호스트A가 메세지를 전송하자마자 소켓을 바로 소멸시킨다면? 그럼 마지막 메세지는 전달되지 못하고 소멸된다. 그럼 호스트 B는 호스트 A에게 메세지를 다시 보내달라고 또 FIN메세지를 전송할 것이다. 하지만 이제 호스트A가 없다? 영원히 ACK메세지를 받지 못하는 상태에 놓이게 되는 것이다. 그러나 호스트 A가 TIME_WAIT일때는 마지막 메세지를 보낼때까지 말그대로 시간을 기다리게 된다.

이로서 호스트 B는 정상적으로 종료가 가능하게 된다.


이런면으로 보면 TIME_WAIT상태는 매우 바람직한 동작으로 된다. 마땅히 보내야할 메세지를 보내고 소켓을 종료하는 것이니 말이다. 하지만 이는 반대로 말하자면 TIME_WAIT상태가 끝날때 까지는 소켓이 포트번호를 점유하고 있다는 것을 의미한다. 만약 통신회선이 좋지 못하다면 얼마까지 TIME_WAIT 상태를 기다려야 할지 알수가 없는 것이다.


이를 해결하기 위해서 필요한 것이. SO_REUSEADDR상태를 변경하는 것이다. 


SO_REUSEADDR의 인자값은 0(FALSE)인데 이는 TIME_WAIT상태에서 PORT번호가 할당 불가능 하다는 것을 의미한다.

이 값을 1로 변경해주면 해제가 된다.


TCP_NODELAY

Nagle 알고리즘의 사용여부를 설정하는 옵션이다.

Nagle 알고리즘이란 네트워크 상에서 돌아다니는 패킷들이 흘러넘치는 것을 막기 위한 알고리즘다.

"Nagle 알고리즘이란 앞서 전송한 데이터에 대한 ACK 메세지를 받아야만 다음 데이터를 전송하는 알고리즘이다."

즉 기본적으로 사용하고 있는 알고리즘이다. 쓰리 웨이 핸드 쉐이킹이 기본적으로 이 알고리즘을 쓰기 때문이다.

하지만 이는 짧은 데이터를 연속적으로 보낼때는 신뢰성을 높여주는 알고리즘 이지만. 한번한번의 메세지를 보내는 처리 또한 연산이며 패킷이므로 이 옵션을 끄면 데이터 송수신의 속력이 올라가게 된다.

대표적인 경우는 대용량 파일입출력으로 거의 항상 출력버퍼를 가득채워넣기 때문에 이 옵션을 켰을 경우 상당한 연산을 하게 된다. 

필요한 경우 이 옵션을 변경해 주는것으로 성능향상을 기대할 수 있다.


윈도우용 함수들 -------------------------------------------------------------------------------------------------


int setsockopt(

  _In_  SOCKET s,  ->옵션 확인을 위한 소켓의 핸들 전달.

  _In_  int level, -> 확인할 옵션의 프로토콜 레벨설정

  _In_  int optname, -> 확인할 옵션의 이름 전달.

  _In_  const char *optval, -> 확인결과의 저장을 위한 버퍼의 주소 값 전달.

  _In_  int optlen -> 네번째 매개변수로 전달된 버퍼크기를 담고 있는 변수의 주소 값 전달. 함수 호출이 완료되면 네번째 인자값의 반환된 옵션정보의 크기가 바이트 단위로 계산되어 저장된다.

);


int getsockopt(
  _In_     SOCKET s, -> 옵션 확인을 위한 소켓의 핸들 저장
  _In_     int level, -> 변경할 옵션의 프로토콜 레벨 설정
  _In_     int optname, -> 확인할 옵션의 이름 전달.
  _Out_    char *optval, -> 변경할 옵션 정보를 저장할 버퍼의 주소 값 전달.
  _Inout_  int *optlen -> 네번째 매개변수 optval로 전달될 옵션 정보의 바이트 크기 전달.
);


Posted by JJOREG