데이터 송수신 (1)
인터넷 프로토콜 5장
제 5장 데이터의 송수신
5.1 정수 인코딩
5.2 메시지 생성, 프레이밍, 그리고 파싱
5.3 마무리
들어가기 전
TCP/IP는 사용자의 데이터를 검사하거나 변경하지 않고 그대로 전송
응용 프로토콜은 연속적인 필드로 구성된 메시지 형태로 정의
인코딩(encoding)/디코딩(decoding) 또는 파싱(parsing)
네트워크 응용 프로그램 개발 방법사용자가 모든 것을 새로 정의
이미 존재하는 프로토콜 표준을 따르면서 남은 부분 구현
5.1 정수 인코딩
정수의 크기
보내려는 정수의 크기를 미리 결정 바이트 순서화
1 바이트가 넘는 값을 인코딩하는 경우 어떤 순서로 보낼 것인지(big-endian/little-endian) 상호 결정 부호화와 부호 확장
보내는 값에 부호가 있는지(signed) 또는 없는지(unsigned) 결정정수의 크기 (1)
C 언어의 정수형 타입들
int
char
short
long
C 언어의 표준
크기에 대한 정의는 없으면서 단지 char형이 short보다 클 수 없고, short는 int보다 클 수 없고, int는 long보다 클 수 없다고만 기술
반드시 개발 플랫폼에서 sizeof 연산자를 사용하여 크기를 확인해야 함
이때 sozeof 연산자 결과는 sizeof(char)를 1로 정의
정수의 크기 (2)
C99언어 표준
Option 형태로 자료형에 비트 단위 크기를 나타냄int8_t, int16_t, int32_t, int64_t (uint8_t)
추가적으로 long long 타입도 있음
TestSizes.c바이트 순서화
Big-endian과 Little-endian
Big-endian(high order)
Little-endian(low order)
인터넷의 바이트 순서 : Big-endian
network bytes order
호스트의 바이트 순서 : 플랫폼에 따라 다를 수 있음
native bytes order 또는 host bytes order
C 언어 플랫폼에서 제공하는 함수들
htons(), ntohs() : 16비트 정수
htonl(), ntohl() : 32비트 정수
부호화
signed 와 unsigned 차이
부호 확장(sign extension)
int8_t가 int16t로 확장되는 과정 이해0100 1110 (78) -> 0000 0000 0100 1110 (78)
1110 0010 (-30) -> 1111 1111 1110 0010 (-30)
int8_t가 uint16t로 확장되는 과정 이해0100 1110 (78) -> 0000 0000 0100 1110 (78)
1110 0010 (-30) -> 1111 1111 1110 0010 (65506)
연산과정의 확장
char + char는 char이 아니다!정수 인코딩을 직접 해보자
BruteForceCoding.c
byte ordering
signedness과제
본문 TestSizes.c 실행하여 확인
본문 BruteForceCoding.c 확인 및 정리
특히 비트 연산자 활용 부분에 주의!TCP소켓을 스트림으로 포장하기
TCP 소켓에 복수 바이트 정수값을 인코딩하는 다른 방법파일 스트림 사용
fdopen()을 호출하여 파일 스트림과 소켓식별자를 연관시킨 후 사용
FILE *fdopen( ) int fclose( ) int fflush( ) size_t fwrite( ) size_t fread( )
권장하지는 않음 !구조체 오버레이 : 정렬과 채우기
실제로 구조체가 어떻게 구현되는지 이해 필요
alignment를 위해필요한 padding 이해
구조체와 메모리 할당 이해
최대한 정렬
2바이트 이상인 경우 시작주소는 항상 2로 나누어져야 한다
struct addressInfo {
uint16_t streetAddress;
int16_t aptNumber;
uint32_t postalCode;
} addrInfo;
streetAddress
aptNumber
postalCode
struct integerMessage { uint8_t oneByte;
uint16_t twoBytes;
uint32_t fourBytes;
uint64_t eightBytes;
};
struct integerMessage2 { uint8_t oneByte;
uint8_t padding;
uint16_t twoBytes;
문자열과 텍스트
old-fashioned text
ASCII
C언어는 ASCII의 축소판인 기본 문자셋(basic character set) 명시 (C99 – ISO646)
“internationalizable” code
C99 extensions
wchar_t (wide character) 지원
size_t wcstombs( ) (wide character string to multibyte string)
size_t mbstowcs( )
C99에서도 인코딩 방식에 대한 명시적 제어권이 제공되지 않음
플랫폼에서 정의한 locale에 따라 정의된 하나의 고정된 문자셋을 이용한다고 가정 (실시간에 locale이 변경되는 경우 결과를 예측할 수 없음!)
서로 다른 문자셋을 혼용하여 이용할 방법이 없음!
관련 명령 / 함수(라이브러리)들 (조사하여 정리할 것!)
locale
wcslen( ), wcslen_l( ), wcscpy( ), …
iconv
비트 조작 : 참, 거짓 값의 인코딩
비트맵(bitmaps)
참, 거짓 정보를 인코딩하는 가장 간단한 방법
파일의 접근권한
마스크(mask)
하나 혹은 그 이상의 특정 비트가 1로 설정되어 있고, 나머지는 0으로 설정되어 있는 정수값
& 연산으로 특정 비트가 1로 설정되어 있는지 여부 판단
| 연산으로 특정 비트를 1로 설정
특정 비트를 해제하고자 하는 경우 마스크에 ~연산(비트-보수(bitwise complement)) 한 후 &
C 언어의 bitwise 연산자 이해 필요
<<
>>
|
&
~
응용 과제 1
전체 전원스위치 1개, 전등 스위치 5개를 감시 또는 제어하는 프로그램 작성
비트 단위로 처리
필요한 기능전원 스위치 on/off
n 번째 전등 스위치 on/off
현재 스위치 상태 출력
현재의 전등 상태 출력
전원 스위치와 전등 스위치를 같이 고려하여 상태 표시
주 #5 #4 #3 #2 #1
전송 데이터의 자료형 (1)
문자열(String) 전송: 가변 길이 전송
장점
사람이 읽기 쉬움
메시지의 확장이 용이하며 무제한
단점
전송량 대비 전송 내용 비효율, 수신 루틴 비효율, 연산 비효율
상호 협의 할 내용
문자 코드 페이지
ASCII, Unicode, UTF
메시지 경계 구분 (프레이밍: framing)
길이 명시 방식: 전송할 문자열의 크기를 고정크기의 자료형에 담아서 전송.
수신자는 크기를 미리 파악하고 정확한 문자열만큼 수신
구분자 방식: 널 문자 혹은 임의의 문자를 메시지의 경계에 삽입. 수신자는 바이트 단위로 읽다가 구분자가 나오면 메시지의 끝으로 확인
전송 데이터의 자료형 (2)
문자열(String) 전송
숫자 전송의 예
문자 전송의 예49 55 57 57 56 55 48 10 ‘1’ ‘7’ ‘9’ ‘9’ ‘8’ ‘7’ ‘0’ \n
M o m \n
3 77 111 109
0 77 0 111 0 109 0 10
char string[strBuffSize];
send(sock, string, strBuffSize, 0)
문자열 전송의 예(TCP)
주의점 : 버퍼의 크기
TCP는 운영체제에 의존적인 TCP 버퍼가 있으며 이 보다 작은 크기로 send()를호출해야 한다.
전송 데이터의 자료형 (3)
정수형(Integer)의 전송
기본 자료형의 단위로 전송
2바이트, 4바이트 단위의 전송
주의 사항
2바이트 이상의 데이터 전송간에는 항상 네트워크 바이트 순서로 전송해야 함
1바이트 교환은 의미가 없음
Network byte order (Big-Endian)
다중 바이트의 메시지 교환에 필수
호스트 바이트-네트워크 바이트 변환 함수들
htonl(), htons(), ntohl(), ntohs()
0 0 92 246
23,798 Little-Endian
int data;
send(sock, &data, sizeof(data), 0)