TCP&IP

TCP/IP 9장 소켓의 다양한 옵션

Barbarian developer 2024. 9. 5.

소켓의 옵션과 입출력 버퍼의 크기

소켓의 다양한 옵션

소켓의 특성을 변경시킬 때 사용하는 옵션정보들이다. 이러한 소켓의 옵션은 계층별로 분류된다. IPPROTO_IP 레벨의 옵션들은
IP 프로토콜에 관련된 사항들이며, IPPROTO_TCP 레벨의 옵션들은 TCP 프로토콜에 관련된 사항들이다. 그리고SOL_SOCKET 레벨의 옵션들은 소켓에 대한가장 일반적인 옵션들로 생각하면 된다.

 

옵션정보의 참조에 사용되는 함수

#include <sys/socket.h>

int getsockopt(int sock, int level, int optname, void *optaval, socklen_t *optlen);
	성공시 0, 실패시 -1 반환.

 

sock : 옵션확인을 위한 소켓의 파일 디스크립터 전달.

level : 확인할 옵션의 프로토콜 레벨 전달.

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

optval : 확인결과의 저장을 위한 버퍼의 주소 값 전달.

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

 

옵션정보의 설정에 사용되는 함수

#include <sys/socket.h>

int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
	성공시 0, 실패시 -1반환


sock : 옵션확인을 위한 소켓의 파일 디스크립터 전달.

level : 변경할 옵션의 프로토콜 레벨 전달.

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

optval : 변경할 옵션정보를 저장한 버퍼의 주소 값 전달.

optlen : 네 번째 매개변수  optval로 전달된 옵션정보의 바이트 단위 크기 전달.

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
void error_handling(char *message);

int main(int argc, char *argv[]) 
{
	int tcp_sock, udp_sock;
	int sock_type;
	socklen_t optlen;
	int state;
	
	optlen=sizeof(sock_type);
	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, (void*)&sock_type, &optlen);
	if(state)
		error_handling("getsockopt() error!");
	printf("Socket type one: %d \n", sock_type);
	
	state=getsockopt(udp_sock, SOL_SOCKET, SO_TYPE, (void*)&sock_type, &optlen);
	if(state)
		error_handling("getsockopt() error!");
	printf("Socket type two: %d \n", sock_type);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

15,16행 : TCP, UDP소켓을 각각 생성하고 있다.

17행 : TCP,UDP 소캣 생성시 인자로 전달하는 SOCK_STREAM, SOCK_DGRAM의 상수 값을 출력하고 있다.

20,25행 : 소켓의 타입정보를 얻고 있다. TCP소켓이라면 SOCK_STREAM의 상수 값인 1을 얻게 될 것이고, UDP 소켓이라면 SOCK_DGRAM의 상수 값인 2를 얻게 될 것이다.

 

실행결과

 

SO_SNDBUF & SO_RCVBUF

 

SO_RCVBUF입력버퍼의 크기와 관련된 옵션.

SO_SNDBUF출력버퍼의 크기와 관련된 옵션.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
void error_handling(char *message);

int main(int argc, char *argv[])
{
	int sock;  
	int snd_buf, rcv_buf, state;
	socklen_t len;
	
	sock=socket(PF_INET, SOCK_STREAM, 0);	
	len=sizeof(snd_buf);
	state=getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);
	if(state)
		error_handling("getsockopt() error");
	
	len=sizeof(rcv_buf);
	state=getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, &len);
	if(state)
		error_handling("getsockopt() error");
	
	printf("Input buffer size: %d \n", rcv_buf);
	printf("Outupt buffer size: %d \n", snd_buf);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

실행결과

T

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
void error_handling(char *message);

int main(int argc, char *argv[])
{
	int sock;
	int snd_buf=1024*3, rcv_buf=1024*3;
	int state;
	socklen_t len;
	
	sock=socket(PF_INET, SOCK_STREAM, 0);
	state=setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, sizeof(rcv_buf));
	if(state)
		error_handling("setsockopt() error!");
	
	state=setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, sizeof(snd_buf));
	if(state)
		error_handling("setsockopt() error!");
	
	len=sizeof(snd_buf);
	state=getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);
	if(state)
		error_handling("getsockopt() error!");
	
	len=sizeof(rcv_buf);
	state=getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, &len);
	if(state)
		error_handling("getsockopt() error!");
	
	printf("Input buffer size: %d \n", rcv_buf);
	printf("Output buffer size: %d \n", snd_buf);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
/*
root@com:/home/swyoon/tcpip# gcc get_buf.c -o getbuf
root@com:/home/swyoon/tcpip# gcc set_buf.c -o setbuf
root@com:/home/swyoon/tcpip# ./setbuf
Input buffer size: 2000 
Output buffer size: 2048 
*/

해설

12,16행 : 입력버퍼와 출력버퍼의 크기를 각각 3kbyte로 변경하고 있다.

21,26행 : 입출력 버퍼의 변경요청에 따른 결과를 확인하게 위해서 입출력 버퍼의 크기를 참조하고 있다.

 

실행결과

SO_REUSEADDR

주소할당 에러(Binding Error)발생

Time-wait의 이해

서버, 클라이언트에 상관없이 TCP 소켓에서 연결의 종료를 목적으로 Four-way handshaking의 첫 번째 메시지를 전달하는 호스트의 소켓은 Time-wait 상태를 거친다. Time-wait 상태 동안에는 해당 소켓이 소멸되지않아서 할당 받은 Port를 다른 소켓이 할당할 수 없다.

 

Time-wait의 존재이유

호스트 A의 마지막 ACK가 소멸되는 상황을 대비해서 Time-wait상태가 필요하다. 호스트 A의 마지막 ACK가 소멸되면, 호스트 B는 계속해서 FIN메시지를 호스트 A에 전달하게 된다.

 

주소의 재할당

Time-wait은 길어질 수 있다.

 

Time-wait은 필요하다. 그러나 실 서비스 중인 서버의 경이 Time-wait이 문제가 될 수 있다. 그러한 경우에는 Time-wait상태에 있는 Port의 할당이 가능하도록 코드를 수정해야한다.

optlen=sizeof(option);
option=TRUE;
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen);

 

TCP_NODELAY

Nagle 알고리즘

인터넷의 과도한 트래픽과 그로 인한 전송속도의 저하를 막기 위해서 디자인 된 알고리즘이 Nagle 알고리즘이다.

이러한 Nagle 알고리즘은 그 목적이 명확한 경우가 아니면 중단하지 말아야 하며, 소켓은 기본적으로 Nagle알고리즘을 적용해서 데이터를 송수신한다.

 

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

 

Nagle 알고리즘의 중단을 명령하는 코드

int opt_val=1;
setsocopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val, sizeof(opt_val));

 

Nagle 알고리즘의 설정상태 확인하는 코드

int opt_val;
socklen_t opt_len;
opt_len=siaeof(opt_val);
getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val, &opt_len);

 

댓글