Ch. 11. Socket & Buffer option

 

getsockopt & setsockopt

#include <sys/socket.h> 

int getsockopt(int sock, int level, int optname, void *optval, 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로 전달된 옵션정보의 바이트 단위 크기 전달

getsockopt 예제

"소켓의 타입은 소켓 생성시 한번 결정되면 변경이 불가능하다."

#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);
}

SO_SNDBUF & SO_RCVBUF

소켓이 생성되면 입력 버퍼와 출력 버퍼가 생성된다.

SO_SNDBUF, SO_RCVBUF를 통해 버퍼의 크기 참조, 변경 가능하다.

버퍼 사이즈 출력

#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);
}

버퍼 사이즈 변경

#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 
*/


Time-wait

호스트 A(Server)의 연결 해체는 Four-way handshaking 이후에 소켓이 바로 소멸되지 않고 Time-wait 상태라는 것을 일정시간 거친다.

 

해당 소켓의 PORT번호가 사용중인 상태이기 때문dp bind 함수의 호출과정에서 오류가 발생한다.

 

클라이언트 소켓의 PORT번호는 서버와 달리 프로그램이 실행될 때마다 유동적으로 할당되기 때문에 Time-wait 상태에 대해 고려하지 않아도 된다 .

 

 

서버가 시스템 문제로 갑작스럽게 종료된 경우, 재빨리 서버를 재가동시켜 서비스를 이어가야 하는데 Time-wait 때문에 기다릴 수밖에 없다면 이는 문제가 될 수 있다 .

 

SO_REUSEADDR의 디폴트 값은 O(FALSE) 인데 , 이는 Time-wait 상태에 있는 소켓의 PORT변호는 할당이 불가능함을 의미한다.

 

변경 >> 

optlen=sizeof(option);

option=TRUE ;

setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen)

Nagle

"앞서 전송한 데이터의 ACK 메시지를 받아야만, 다음 데이터를 전송하는 알고리즘"

TPC는 기본적으로 Nagle 알고리즘을 적용

ACK가 수신될때까지 최대한 버퍼링 후 전송

 

Nagle 알고리즘의 중단

 

Nagle 알고리즘을 고집할 필요는 없이 필요하다면 Nagle 알고리즘을 중단시켜야 한다.

 

TCP _NODELA을 1(TRUE)로 변경 >>

int opt_val=1;

setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,(void*)&opt_val, sizeof(opt_val));

 

댓글

공지사항
업데이트
인기 글
최근댓글
태그
윈도우 timespecs 오류 C2011 'timespec': 'struct' 형식 재정의 윈도우 db socket programming 빅엔디안 window mysql if(false) 스트림 버퍼 버퍼란 M1 dock 리턴 0 이유 mariadb 재설치 A2449 fgets( ) 개행('\0')과 NULL 처리 if 가독성 MariaDB Connector/C++ 고정 소수점 listen() connect() M1 독 바로 보기 우분투 qt 표준 입출력 스트림 리틀 엔디안과 빅 엔디안 C++ connector 네이버 페이 결제 stream buffer db 방화벽 c언어 스트림 2진수와 Byte 몬트레이 한영 전환 스트림과 버퍼 c# 클래스 실제 인터넷 속도 실제 저장 용량 포인터와 참조 맥북 독 반응 Visual Studio에서 inet_ntoa( ) 경고 #define HAVE_STRUCT_TIMESPEC m1 매직 키보드 m1 Shift space m1 윈도우 단축키 네이버 맴버쉽 계산 C# 메서드 우분투 독 에러 네이버 제휴 통장 적립 윤성우의 열렬 TCP/IP 소켓 프로그래밍 puts( ) m1 페러렐즈 단축키 mysql 방화벽 C2027 정의되지 않은 형식 'timespec' MK293KH/A fputc( ) mysql 외부 Ip if 코드 구조 네이버 적립 ubuntu mariaDB 외부 접속 Magic Keyboard with Touch ID littem endian 소켓 네이버 포인트 적립 계산 MariaDB Connector Apple Silicon Mac용 터치아이디 탑재형 매직 키보드 - 미국 영어 (MK293KE/A) socket 2진수 음수 표현 socket networking mariadb 삭제 2진수 실수 표현 네이버 맴버쉽 적립 if(0) fputs( ) M1 dock speed c 알고리즘 알고리즘이란 몬트레이 Shift Space mariadb 외부접속 MK293KE/A 네이퍼 적립 계산 이진수 실수표현 C networking 효과적인 if 코드 c언어 버퍼 인터넷 속도 단위 return 0 성공 이유 MariaDB 방화벽 네이버 제휴 카드 적립 이진수 음수표현 M1 Parallels Ubuntu QT 우분투 디스코드 pointer reference 2진법과 서수 m1 페러렐즈 윈도우 맥 단축키 io stream 독 속도 조절 db 외부접속 How to show/hide the macOS Dock instantly M1 Parallels Ubuntu QT install 2진법과 기수 우분투 독 비활성화 맥 독 반응 속도
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31