VIII : 소켓 옵션
TCP/IP 윈도우 소켓 프로그래밍 을 읽고 정리한 문서입니다 ;)
소켓 옵션의 종류와 관련 함수
소켓 프로그래밍은 소켓을 통해 TCP/IP, IrDA, Bluetooth와 같은 통신 프로토콜의 기능을 이용하는 응용 프로그램을 작성하는 일이다.
따라서 같은 소켓 함수를 호출하더라도 소켓 코드나 프로토콜 구현 코드의 동작이 달라질 필요가 있다. 이를 위해 소켓 옵션을 사용하면 소켓 함수의 기본 동작을 변경하고 제어할 수 있다.
소켓 옵션은 처리 주체에 따라 크게 두 종류로 구분할 수 있다.
- 소켓 코드가 처리하는 옵션
- 옵션을 설정하면 소켓 코드에서 해석하고 처리한다.
- 프로토콜 독립적인 성격이 있다.
- 프로토콜 구현 코드가 처리하는 옵션
- 옵션을 설정하면 프로토콜 구현 코드에서 해석하고 처리한다.
- 프로토콜에 의존적인 성격이 있다.
소켓 옵션을 설정할 때에는 setsockopt()
함수를 사용한다.
int setsockopt(
SOCKET s,
int level,
int opename,
const char *optval,
int optlen
);
int level
: 소켓 코드가 처리하면SOL_SOCKET
, IPv4 프로토콜 코드가 처리하면IPPROTO_IP
, IPv6 프로토콜 코드가 처리하면IPPROTO_IPV6
, TCP 프로토콜 코드가 처리하면IPPROTO_TCP
현재 설정된 소켓 옵션 값을 얻을 때에느느 getsockopt()
함수를 사용한다.
SOL_SOCKET 레벨 옵션
SOL_SOCKET
레벨 옵션은 소켓 코드에서 해석해 처리하므로 프로토콜에 독립적인 성격을 띄지만, 여기에 속한 옵션을 모든 프로토콜에 공통으로 적용할 수는 없다.
SO_BROADCAST
옵션
이 옵션을 설정하면 해당 소켓으로 브로드캐스트 데이터를 보낼 수 있으며, 이는 UDP 소켓에만 사용할 수 있다.
SO_KEEPALIVE
옵션
이 옵션을 설정하면 TCP 프로토콜 수준에서 연결 여부를 확인하려고 상대 TCP에 주기적으로 TCP 패킷을 보낸다.
만일 상대가 정해진 시간 안에 응답하지 않는다면, 몇번 더 시도하고 이후 자동으로 소켓을 닫고, 상대가 RST
패킷을 회신한다면 즉시 해당 소켓을 닫게 된다.
TCP는 상대와 나와의 논리적 연결이므로, 이후에 데이터 교환이 없다면 상대 호스트가 다운되거나 전원이 끊어진 경우를 감지하지 못한다는 특징이 있다. 따라서 이 옵션을 통하면 연결이 끊어진 소켓을 그때그때 닫아 불필요한 시스템 자원 소모를 막을 수 있게 된다.
TCP 소켓에 사용할 때에는 일반적으로 TCP서버의 연결 대기 소켓에 적용하여, accept()
를 통해 생성되는 모든 소켓에 동일한 옵션으로 적용되도록 한다.
SO_LINGER
옵션
이를 이용하면 소켓 송신 버퍼에 미전송 데이터가 있을 때 closesocket()
함수의 리턴 지연 시간을 제어할 수 있다.
TCP 소켓을 사용하는 경우 closesocket()
함수는 두 가지 기능을 한다. 첫째로 소켓을 닫고 할당된 운영체제 자원을 반환한다. 또한, TCP 프로토콜 수준에서 연결 종료 절차 (FIN) 을 시작한다.
하지만 closesocket()
함수 호출 시에 송신 버퍼가 아직 대기중이라면 어떻게 될까?
closesocket()
함수는 곧바로 리턴하되, 송신 버퍼의 데이터를 백그라운드로 모두 보내고 TCP 연결을 종료시킨다.l_onoff
가0
인 경우
closesocket()
함수는 곧바로 리턴하되 송신 버퍼의 데이터를 삭제하고 TCP 연결을 강제 종료한다.l_onoff
가1
,l_linger
가0
인 경우
- 송신 버퍼의 데이터를 모두 보내고 TCP 연결 정상 종료 후에
closesocket()
함수를 리턴시키고, 타임아웃에 도달하면 강제 종료 후 리턴시킨다.l_onoff
가1
,l_linger
가 양수값인 경우
SO_LINGER
옵션을 사용하면 이 세 가지를 선택하여 사용할 수 있다.
struct linger {
u_short l_onoff;
u_short l_linger;
};
typedef struct linger LINGER;
u_short l_onoff
: 값이 0이면closesocket()
함수는 곧바로 리턴하고, 1이라면l_linger
로 설정된 시간동안 대기한다.u_short l_linger
:closesocket()
함수가 리턴하지 않고 대기할 시간을 초 단위로 지정한다.0
또는 양수값이 될 수 있다.
**shutdown()**
함수를 사용하면 TCP의 정상 종료 작업만 처리하도록 할 수 있다. 이 함수는 소켓으르 닫고 운영체제에 자원을 반환까지 하는 closesocket()
과 차이가 있다.
따라서 만일 데이터를 송신한 측에서 send()
이후 shutdown()
함수를 호출하면, 상대방은 recv()
함수의 리턴 값이 0
이 되므로 데이터를 모두 받았다고 확신할 수 있게 된다. 이 때 closesocket()
함수는 소켓을 닫고 운영체제에 자원을 반환하는 기능만 하게 된다.
SO_SNDBUF
, SO_RCVBUF
옵션
이를 이용하면 운영체제가 소켓에 할당하는 송신 버퍼와 수신 버퍼의 크기를 변경할 수 있다.
UDP 소켓은 소켓 버퍼 크기를 언제든 변경해도 되지만, TCP 소켓은 connect()
를 통해 연결이 이루어지기 전에 설정하는 것이 좋다.
SO_SNDTIMEO
, SO_RCVTIMEO
옵션
socket()
함수로 간단히 만드는 소켓은 블로킹 소켓이므로, 데이터 송수신 시 조건이 만족되지 않는다면 무한정 블록되어 교착 상태가 발생할 수 있다.
이를 위해 소켓이 사용할 기본 타임아웃을 설정할 수 있는데, 이는 데이터 송수신 함수가 작업 완료와 상관없이 일정 시간 이후에 리턴하게 할 수 있다.
SO_REUSEADDR
옵션
이 옵션을 설정하면 현재 사용 중인 IP 주소와 포트 번호를 재사용할 수 있다. 현재 사용 중인 IP 주소와 포트 번호를 이용해 bind()
하더라도 오류가 나지 않고 성공할 수 있는 것이다.
- TCP 서버 종료 후 재실행 시
bind()
오류 발생을 방지할 수 있다.- 멀티프로세스 환경에서 TCP 서버에 문제가 발생해 강제 종료되더라도 자식 프로세스가 해당 포트 번호를 사용하려고 할 때 문제가 생길 수 있다.
- 윈도우같은 멀티스레드 환경에서는 이러한 문제가 발생하지는 않지만, 코드 이식성을 고려해
SO_REUSEADDR
을 설정하는 것이 좋다.
- 여러 IP 주소를 보유한 호스트에서 같은 기능의 서버를 IP 주소별로 따로 운용할 수 있다.
- 유닉스/리눅스 운영체제에서는 서버 실행 시 IP 주소가 달라도 포트 번호가 같다면 바인딩 오류가 발생한다. 단, 윈도우에서는 이 경우 문제가 생기지 않는다.
- 멀티캐스팅 응용 프로그램이 같인 포트 번호를 사용할 수 있게 한다.
- UDP 서버에 한정하여 여러 응용프로그램에서 포트를 같이 사용할 수 있다.
IPPROTO_IP, IPPROTO_IPV6 레벨 옵션
IPPROTO_IP
, IPPROTO_IPV6
옵션은 각각 IPv4, IPv6 프로토콜 코드에서 해석하고 처리한다.
멀티캐스팅
멀티캐스팅은 TCP 소켓에서는 사용할 수 없고 UDP 소켓에만 적용할 수 있는 기능이다.
멀티캐스팅용 IP 주소는 224.0.0.0 ~ 239.255.255.255
이고, 고정된 상위 비트를 제외한 나머지 부분을 그룹 ID라고 부른다.
응용프로그램은 멀티캐스트 데이터를 수신하기 위해 멀티캐스트 그룹에 자유롭게 가입하고 탈퇴할 수 있다.
그룹 가입과 탈퇴가 자유롭고 그룹 구성원 모두가 평등하고, 멀티캐스트 데이터를 받으려면 반드시 해당 그룹에 가입해야 하지만, 이 그룹에 데이터를 보내기 위해서 그룹에 가입할 필요는 없다.
IP_MULTICAST_IF
, IPV6_MULTICAST_IF
옵션을 사용하면 IP주소를 둘 이상 보유한 호스트에서 멀티캐스트 데이터를 보낼 네트워크 인터페이스를 선택할 수 있게 된다.
IP_MULTICAST_TTL
, IPV6_MULTICAST_HOPS
옵션을 사용하면 멀티캐스트 패킷의 기본 TTL인 0을 원하는 값으로 변경시켜서 라우터를 넘어갈 수 있게끔 해준다.
IP_MULTICAST_LOOP
, IPV6_MULTICAST_LOOP
옵션은 그룹에 가입한 응용 프로그램이 해당 그룹에 멀티캐스팅 메시지 송신 시 자신이 받을지 여부를 설정할 수 있다.
이러한 그룹은 IP*_ADD_MEMBERSHIP
, IP*_DROP_MEMBERSHIP
옵션을 통해 가입하고 탈퇴할 수 있다.
IPPROTO_TCP 레벨 옵션
IPPROTO_TCP
레벨 옵션은 TCP 프로토콜 코드에서 해석하고 처리한다. 따라서 TCP 소켓에만 적용할 수 있다.
**TCP_NODELAY
옵션은 Nagle 알고리즘 작동을 중지하는 역할을 한다.**
Nagle 알고리즘은 작은 패킷이 불필요하게 많이 생성되는 일을 방지해 네트워크 트래픽을 감소시키는 알고리즘으로서, 동작 방식을 다음 두 가지로 요약할 수 있다.
- 보낼 데이터가 MSS로 정의된 크기보다 크다면 상대편에 무조건 보낸다. 이 경우 슬라이딩 윈도우 방식으로 데이터를 계속 보낼 수 있다.
- 보낼 데이터가 MSS보다 작다면 이전에 보낸 데이터에 대한 ACK가 오기를 기다린다. ACK가 도착하면 MSS보다 작더라도 데이터를 보낸다.
이러한 동작 방식은 네트워크 트래픽을 감소시킬 수 있지만, 응용프로그램이 네트워크로부터의 반응 시간을 손해보게 된다.
요약
- 소켓 옵션 관련 함수
- 소켓 옵션을 설정할 때에는
setsockopt()
함수를 사용한다. - 소켓 옵션을 읽을 때에는
getsockopt()
함수를 사용한다.
- 소켓 옵션을 설정할 때에는
- SOL_SOCKOPT 레벨 소켓 옵션
SO_BROADCAST
: 브로드캐스팅 데이터 전송 허용 여부SO_KEEPALIVE
: 주기적으로 연결 상태 확인 여부SO_LINGER
: 소켓 송신 버퍼에 데이터 있을 때closesocket()
의 동작 방식 설정SO_SNDBUF
,SO_RCVBUF
: 소켓 송수신 버퍼 크기 설정SO_SNDTIMEO
,SO_RCVTIMEO
: 소켓 데이터 송수신 함수 기본 타임아웃 설정SO_REUSEADDR
: 지역 주소 재사용 허용 여부
- IPPROTO_IP 레벨 소켓 옵션
IP_TTL
: IP 패킷의 TTL 설정IP_MULTICAST_IF
: 멀티캐스트 패킷을 보낼 인터페이스 선택IP_MULTICAST_TTL
: 멀티캐스트 패킷의 TTL 설정IP_MULTICAST_LOOP
: 멀티캐스트 패킷의 루프백 여부IP_ADD_MEMBERSHIP
,IP_DROP_MEMBERSHIP
: 멀티캐스트 그룹 가입과 탈퇴
- IPPROTO_TCP 레벨 소켓 옵션
TCP_NODELAY
: Nagle 알고리즘 작동 여부
'공부한 이야기 > 윈도우 소켓 프로그래밍' 카테고리의 다른 글
X : 소켓 입출력 모델 I (0) | 2023.04.29 |
---|---|
IX : GUI 소켓 응용 프로그램 (0) | 2023.04.29 |
VII : UDP 서버-클라이언트 (0) | 2023.04.29 |
VI : 멀티스레드 (0) | 2023.04.29 |
V : 데이터 전송하기 (0) | 2023.04.29 |