100208바이트오더와소켓옵션

Download Report

Transcript 100208바이트오더와소켓옵션

Byte Order, Domain, Socket Options
차례




TCP 프로그램의 흐름(REVIEW)
Byte Order
Domain
Socket Option
Socket Programming On Unix
TCP 서버의 기본적인 함수 호출 순서
Byte Order


Endian이라고도 불리며, 각 컴퓨터에서
데이터를 메모리 상에 맵핑하기 위한 정렬
방식
주로 Big-endian, Little-endian이 사용
Byte Order(계속)



Big-endian : 높은 자리의 데이터가 상위
바이트 주소에 위치하는 정렬 방식, 인텔
포맷이라고도 부름.
Little-endian : 높은 자리의 데이터가 하
위 바이트 주소에 위치하는 정렬 방식
서로 다른 규격의 장치 간 연동이 있을 수
있으므로 항상 Byte Order를 규정해 놓고
사용해야 함. 대부분의 네트워크 프로토콜
에서는 Big-endian을 사용
Byte Order(계속)
Byte Order(계속)

Example writing integer value
int main(){
int data = 123456789;
int fd;
fd = open("test_bin",O_CREAT|O_WRONLY);
write(fd,&data,sizeof(int));
close(fd);
return 0;
}
Byte Order(계속)
Run on linux
$ ./write
$ls
test_bin write write.c
$ od -x test_bin
0000000 cd15 075b
0000004

Byte Order(계속)
Run on Solaris
$ ./write
$ls
test_bin write write.c
$ od -x test_bin
0000000 5b07 15cd

Byte Order(계속)
Run on Solaris
$ ./write
$ls
test_bin write write.c
$ od -x test_bin
0000000 5b07 15cd

소켓 프로그래밍
네트워크 바이트 순서

그래서 CPU의 데이터 저장방식을 의미하는 ‘호스트 바이
트 순서(Host Byte Order)’는 CPU에 따라서 차이가 난다.
- 참고 : intel계열 CPU는 리틀 엔디언 방식으로 데이터 저장



호스트 바이트 순서가 다른 두 CPU가 데이터를 주고받을
때 발생할 때 문제가 생길 수 있기 때문에 네트워크를 통
해서 데이터를 전송할 때는 통일된 기준으로 데이터를 전
송하기로 약속했다.
이 약속을 ‘네트워크 바이트 순서(Network Byte Order)=
빅 엔디언 방식으로 통일!’라 한다.
이러한 이유로 모든 컴퓨터는 수신된 데이터가 네트워크
바이트 순서로 정렬되어 있음을 인식해야 하며, 리틀 엔디
안 시스템에서는 데이터를 전송하기에 앞서 빅 엔디안의
정렬방식으로 데이터를 재정렬해야 한다.
바이트 순서의 변환






Unsigned
Unsigned
Unsigned
Unsigned
short htons(unsigned short);
short ntohs(unsigned short);
long htons(unsigned long);
long ntohs(unsigned lond);
Hton에서 h는 호스트(host) 바이트 순서를 의미한다.
Ntoh에서 n은 네트워크(network) 바이트 순서를 의미한
다.
바이트 순서의 변환을 돕는 함수
< 여기서 들 수 있는 의문점>
Q. 내 시스템은 빅 엔디언으로 동작하므로 바이트 순서로
변환할 필요가 없겠네요?
A. 리틀 엔디안, 빅 엔디안에 상관없이 동일하게 동작하는
코드를 작성할 필요가 있다.
Q. 데이터 전송하기 전에 다 바꿔줘야 하나?
A. 다행히도 이러한 변환의 과정은 자동으로 이뤄진다.
때문에 우리는 직접 구조체 변수에 데이터를 채울 때
이외에는 바이트 순서를 신경 쓰지 않아도 된다.
인터넷 주소의 초기화와 할당

우리는 IP 주소를 표현 할 때 “211.214.107.99”와 같이 ‘
점이 찍힌 십진수 표현방식 에는 익숙하지만 하나의 정수
로 표현하는 데는 익숙하지 않다. (정수 표현이 아닌 문자
열 형식)

이러한 문자열로 표현된 IP 주소를 32비트 정수형으로 변
환해 주는 함수가 있다. 뿐만 아니라, 이 함수는 변환과정
에서 네트워크 바이트 순서로의 변환도 동시에 진행한다.
#include <arpa/inet.h>
In_addr_t inet_addr(const char * string);
-> 성공 시 빅 엔디안으로 변환된 32비트 정수 값,
실패 시 INADDR_NONE 반환
인터넷 주소의 초기화와 할당
예) 사용법
Char *addr1=“1.2.3.4”;
Unsigned long conv_addr=inet_addr(addr1);
If(conv_addr==INADDR_NONE)
printf(“Error occurred! \n”);
인터넷 주소의 초기화와 할당
Int inet_aton(const char * string, struct in_addr * addr);
-> 성공 시 1(true), 실패 시 0(false) 반환
Char * inet_ntoa(struct in_addr adr);
-> 성공 시 변환된 문자열의 주소 값, 실패시 -1 반환
78p
IP주소와 도메인 이름 사이의 변환
★도메인 주소로 IP 주소를 가져오는 함수
Struct hostent * gethostbyname(const char * hostname);
-> 성공 시 hostent 구조체 변수의 주소 값,
실패 시 NULL 포인터 반환
Struct hostent
{
char * h_name;
char ** h_aliases;
int h_addrtype;
int h_length;
char ** h)addr)list;
}
//<- 이 구조체를 모두 반환한다!
// official name
// alias list(별명)
// host address type
// address length
//address list
IP주소와 도메인 이름 사이의 변환
★IP 주소로 도메인 주소를 가져오는 함수
Struct hostent * gethostbyaddr(const char * addr,
socklen_t len, int family); -> 성공 시 hostent 구조체 변
수의 주소 값
실패 시 NULL 포인터 반환
(인자 정보)
Addr : IP 주소를 지니는 in_addr 구조체 변수의 포인터 전달,
IPv4 이외의 다양한 정보를 전달받을 수 있도록 일
반화
하기 위해서 매개변수를 char형 포인터로 선언
Len : 첫 번째 인자로 전달된 주소정보의 길이, IPv4의 경우
4,
IPv6의 경우 16 전달
지난 시간 예제 수정
에코 클라이언트
while(1)
{
fputs("Input message(Q to quit):",stdout);
fgets(message,BUF_SIZE,stdin);
if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
break;
write(sock,message,strlen(message));
str_len=read(sock,message,BUF_SIZE-1);
message[str_len]=0;
printf("Message from server: %s",message);
}
예제 수정(계속)
While(recv_len<str_len)
{
recv_cnt=read(sock,&message[recv_len],BUF_SIZE-1)
if(recv_cnt==-1)
error_handling(“rea() error!”);
recv_len+=recv_cnt;
}
message[recv_len]=0;
printf(“message from server:%s”,message);
과제 풀이
TCP 소켓의 버퍼
입출력
입출력
소켓을
소켓을
버퍼는
버퍼는
닫아도
닫으면
TCP 소켓 각각에 대해 별도로 존재
소켓생성시 자동 생성
출력버퍼에 남아있는 데이터는 계속해서 전송이 이루어짐
입력버퍼에 남아있는 데이터는 소멸
상대 소켓과의 연결
상대 소켓과의 데이터 송수신
Sliding Window Protocol
Nagle 알고리즘
N
a
N
g
ACK
l
agle
e
ACK
Nagle On
Nagle Off
상대 소켓과의 연결종료
Half-close
스트림의 일부를 종료하는 함수
int shutdown(int sock, int howto);
Howto: SHUT_RD 입력 스트림 종료
SHUT_WR 출력 스트림 종료
SHUT_RDWR 입출력 스트림 종료
파일 전송하는 서버는 단순히 파일 데이터를 연속해서 전송하면 되지만
클라이언트는 언제까지 데이터를 수신해야 할지 알 수 없기 때문이다.
출력 스트림을 종료하면 상대 호스트로 EOF가 전송.
입력 스트림은 종료되지 않기 때문에 상대편이 보내는 데이터의 수신 가능.
소켓의 다양한 옵션
Protocol Level
Option Name
Get
Set
SOL_SOCKET
SO_SNDBUF
SO_RCVBUF
SO_REUSEADDR
SO_KEEPALIVE
SO_BROADCAST
SO_DONTROUTE
SO_OOBINLINE
SO_ERROR
SO_TYPE
O
O
O
O
O
O
O
O
O
O
O
O
O
O
O
O
X
X
IPPROTO_IP
IP_TOS
IP_TTL
IP_MULTICAST_TTL
IP_MULTICAST_LOOP
IP_MULTICAST_IF
O
O
O
O
O
O
O
O
O
O
IPPROTO_TCP
TCP_KEEPALIVE
TCP_NODELAY
TCP_MAXSEG
O
O
O
O
O
O
소켓의 설정상태 참조
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *
Sock: 옵션 확인을 위한 소켓의 파일 디스크립터 전달.
Level: 확인할 옵션의 프로토콜 레벨 전달.
Optname: 확인할 옵션의 이름 전달.
Optval: 확인결과의 저장을 위한 버퍼의 주소 값 전달.
Optlen: 네 번째 매개변수 optval로 전달된 주소 값의 버퍼크기를 담고 있는
변수의 주소 값 전달.
소켓의 옵션 변경
int setsockopt(int sock,int level, int optname, const void *optval, socklen_
getsockopt와 인자의 정보는 같음.
Nagle 알고리즘의 중단
TCP_NODELAY를 1로 변경
int opt_val=1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&opt_val,sizeof(
File전송 프로그램
과제
위의 파일전송 프로그램은 특정파일 이름으로 고정.
이를 수정하여 프로그램 실행 시 입력한 파일이름의 파일을 전송하는
프로그램을 작성한다.