프로그래밍의 기초/TCP | IP

socket의 옵션과 입출력 버퍼의 크기

Kim나현 2022. 1. 14. 11:05
반응형
  • socket의 다양한 옵션

- IPPROTO_IP: IP 프로토콜에 관련된 사항

- IPPROTP_TCP: TCP 프로트콜에 관련된 사항

- SOL_SOCKET: socket에 대한 가장 일반적인 옵션

(socket의 타입: SO_TYPE은 socket 생성 시 한번 결정되면 변경이 불가하다)

 

  • socket의 옵션 변경 방법

- getsockopt & setsockopt

int getsockopt(
  [in]      SOCKET s,         // 옵션확인을 위한 socket의 file descriptor 전달
  [in]      int    level,         // 확인할 옵션의 프로토콜 레벨 전달
  [in]      int    optname,   // 확인할 옵션의 이름 전달
  [out]     char   *optval,    // 확인 결과의 저장을 위한 버퍼의 주소값 전달
  [in, out] int    *optlen      // optval로 전달된 주소값의 버퍼크기를 담고 있는 변수의 주소값
);

→ 성공 시 0, 실패 시 -1 반환

int setsockopt(
  [in] SOCKET     s,           // 옵션변경을 위한 socket의 file descriptor
  [in] int        level,          // 변경할 옵션의 프로토콜 레벨 
  [in] int        optname,    // 변경할 옵션의 이름
  [in] const char *optval,    // 변경할 옵션정보를 저장한 버퍼의 주소값
  [in] int        optlen        // optval의 바이트 단위 크기
);

→ 성공 시 0, 실패 시 -1 반환

 

// check type of socket
int main()
{
	SOCKET tcp_sock, idp_sock;
	int sock_type;
	int sock_len;
	int state;
	WSADATA wsaData;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		err_handling("startup() error");
	
	sock_len = sizeof(sock_type);
	tcp_sock = socket(PF_INET, SOCK_STREAM, 0);
	idp_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, &sock_len);
	if (state == -1)
		err_handling("getsockopt() error");
	printf("tcp_sock: %d\n", sock_type);

	state = getsockopt(idp_sock, SOL_SOCKET, SO_TYPE, &sock_type, &sock_len);
	if (state == -1)
		err_handling("getsockopt() error");
	printf("idp_sock: %d\n", sock_type);

	WSACleanup();
	return 0;
}

// 실행 창

SOCK_STREAM: 1
SOCK_DGRAM: 2
tcp_sock: 1
idp_sock: 2

 

- SO_SNDBUF & SO_RCVBUF

: 입출력 버퍼 관련 (SO_RCVBUF: 입력버퍼의 크기와 관련, SO_SNDBUF: 출력버퍼의 크기와 관련)

// 입출력 버퍼의 크기 확인

int main()
{
	SOCKET sock;
	int send_buf, recv_buf;
	int len;
	int state;
	WSADATA wsaData;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		err_handling("startup() error");

	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET)
		err_handling("socket() error");

	// 출력버퍼의 크기
	len = sizeof(send_buf);
	state=getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &send_buf, &len);
	if (state == -1)
		err_handling("getsockopt() error");
	printf("send buff:%d\n", send_buf);

	len = sizeof(recv_buf);
	state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &recv_buf, &len);
	if (state == -1)
		err_handling("getsockopt() error");
	printf("receive buff:%d\n", recv_buf);
	WSACleanup();

	return 0;
}

// 실행 창

send buff:65536
receive buff:65536

// 입출력 버퍼의 크기 변경

// 입출력 크기 변경
int main()
{
	SOCKET sock;
	int sen_buf = 1024 * 3, rcv_buf = 1024 * 3;
	int len, state;
	WSADATA wsaData;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		err_handling("startup() error");

	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET)
		err_handling("socket() error");

	// 출력버퍼의 크기 변경
	len = sizeof(sen_buf);
	state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sen_buf, &len);
	if (state == -1)
		err_handling("setsockopt() error");

	// 입력버퍼의 크기 변경
	len = sizeof(rcv_buf);
	state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcv_buf, &len);
	if (state == -1)
		err_handling("setsockopt() error");

	len = sizeof(sen_buf);
	state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sen_buf, &len);
	if (state == -1)
		err_handling("getsockopt() error");

	len = sizeof(rcv_buf);
	state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcv_buf, &len);
	if (state == -1)
		err_handling("getsockopt() error");

	printf("sen_buf: %d\n", sen_buf);
	printf("rcv_buf: %d\n", rcv_buf);

	WSACleanup();
	return 0;
}

// 실행 창

sen_buf: 3072
rcv_buf: 3072

 

- SO_SNDBUF & SO_RCVBUF를 통해서 입출력 버퍼의 크기를 변경한다 할지라도 버퍼의 크기는 정확히 맞춰지지 않음

(흐름제어, 오류 발생시의 데이터 재전송 같은 일을 위해 최소한의 버퍼 필요)

 

반응형