5. Network Byte Order, 빅 엔디안

Network Byte Order (네트워크 바이트 순서)

1. 네트워크 통신은 바이트 단위로 이루어진다.
2. 네트워크 통신은 빅 엔디안 방식을 사용한다.
3. n 은 Network을 뜻하며, 바이트 단위, 빅 엔디안 방식을 의미한다.
4. a 는 Address를 뜻하며, 문자열 단위, 리틀 엔디안 방식을 의미한다.
5. h 는 Host를 뜻하며, 인텔 그리고 AMD 계열의 CPU를 사용하는 사용자의 PC를 의미한다.

리틀 엔디언 & 빅 엔디언 개념 정리 링크

빅 엔디안(Big Endian)

상위 바이트의 값을 작은 번지수에 저장하는 방식

 

 

리틀 엔디안(Little Endian)

상위 바이트의 값을 큰 번지수에 저장하는 방식

 

네트워크 바이트 순서(빅 엔디안 시스템)에서 0x12 , 0x34 의 조합으로 만들어지는 값은, 리틀 엔디안 시스템에서 0x34 , 0x12의 조합으로 만들어지는 값과 같다. 즉, 전송되어온 데이터의 해석 순서가 바뀌어야 동일한 값으로 인식된다.

Endian Conversions (바이트 순서의 변환)

unsigned short htons(unsigned short);  //  host-to-network 바이트 변환
unsigned short ntohs(unsigned short);  //  network-to-host 바이트 변환
unsigned long htonl(unsigned long);    //  host-to-network 바이트 변환
unsigned long ntohl(unsigned long);    //  network-to-host 바이트 변환

// h는 호스트 (host) 바이트 순서
// n은 네트워크 (network) 바이트 순서
// S는 short
// l은 long

// 뒤에 s가 붙는 함수는 s가 2 바이트 short를 의미하므로 PORT번호의 변환에 사용
// 뒤에 l 이 붙는 함수는 l 이 4 바이트를 의미하므로 IP주소의 변환에 사용

Endian Test

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	unsigned short host_port=0x1234;
	unsigned short network_port;
	network_port=htons(host_port);
    
	unsigned long host_addr=0x12345678;
	unsigned long network_addr;
	network_addr=htonl(host_addr);
	
	printf("Host ordered port: %#x \n", host_port);            // 0x1234
	printf("Network ordered port: %#x \n", network_port);      // 0x3412 빅 엔디안
	printf("Host ordered address: %#lx \n", host_addr);        // 0x12345678
	printf("Network ordered address: %#lx \n", network_addr);  // 0x78563412 빅 엔디안
      								   // 16진수 2개는 1바이트다.
    
	return 0;
}

리틀 엔디 안 기준으로 정렬하는 CPU에 서의 실행결과이다.

만약 빅 엔디안 CPU에서 실행을 했다면 변환 후에도 값은 달라지지 않는다.

문자열 IP 주소를 네트워크 바이트 순서(빅 엔디안)로 변환

inet_addr( ) vs inet_aton( ) 사용

sockaddr _in

struct sockaddr_in
{
    sa_family_t        sin_family;  // 주소체계(Address Family)
    uint16_t           sin_port;    // 16 비트 Port 번호
    struct in_addr     sin_addr;    // 32 비트 IP주소, 빅 엔디안
    char               sin_zero[8]; // 사용되지 않음
}

IP주소 211.214.107.99와 같은 ‘십진수 표현방식(Dotted­ Decimal Notation)'을 네트워크 바이트 순서의 IP가 변환한다.

방법 1) inet_addr( )

#include <arpa/inet.h>

in_addr_t inet_addr(const char * string);

//성공시 빅 엔디안으로 변환된 32 비트 정수 값, 실패시 IN ADDR_NONE 반환
#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	char *addr1="127.212.124.78";
	char *addr2="127.212.124.256";

	unsigned long conv_addr=inet_addr(addr1);
	if(conv_addr==INADDR_NONE)
		printf("Error occured! \n");
	else
		printf("Network ordered integer addr: %#lx \n", conv_addr);  // 0x4030201
	
	conv_addr=inet_addr(addr2);
	if(conv_addr==INADDR_NONE)
		printf("Error occureded \n");
	else
		printf("Network ordered integer addr: %#lx \n\n", conv_addr);
	return 0;
}

방법 2) inet_aton( )

#include <arpa/inet.h>

int inet_aton(const char * string , struct in_addr *addr);

// 성공 시 1(true) , 실패 시 0(false) 반환
// string 변환할 IP삽 정렬 담고 있는 문자열의 주소 값 전달
// addr 변환된 정보를 저장할 in_addr 구조체 변수의 주소 값 전달
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
void error_handling(char *message);

int main(int argc, char *argv[])
{
	char *addr="127.232.124.79";
	struct sockaddr_in addr_inet;
	
	if(!inet_aton(addr, &addr_inet.sin_addr))
		error_handling("Conversion error");
	else
		printf("Network ordered integer addr: %#x \n", addr_inet.sin_addr.s_addr);
	return 0;
}

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

네트워크 바이트 순서(빅 엔디안)를 문자열 IP 주소로 변환

inet_ntoa( )

#include <arpa/inet.h>

char *inet_ntoa(struct in_addr adr);

// 성공시 변완된 문자열의 주소값, 실패시 -1 반환
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	struct sockaddr_in addr1, addr2;
	char *str_ptr;
	char str_arr[20];
   
	addr1.sin_addr.s_addr=htonl(0x1020304);
	addr2.sin_addr.s_addr=htonl(0x1010101);
	
	str_ptr=inet_ntoa(addr1.sin_addr);
	strcpy(str_arr, str_ptr);
	printf("Dotted-Decimal notation1: %s \n", str_ptr);
	
	inet_ntoa(addr2.sin_addr);
	printf("Dotted-Decimal notation2: %s \n", str_ptr);
	printf("Dotted-Decimal notation3: %s \n", str_arr);
	return 0;
}

/*
root@com:/home/swyoon/tcpip# gcc inet_ntoa.c -o ntoa
root@com:/home/swyoon/tcpip# ./ntoa
Dotted-Decimal notation1: 1.2.3.4 
Dotted-Decimal notation2: 1.1.1.1 
Dotted-Decimal notation3: 1.2.3.4 

*/
printf("Client %s:%d is connected..\n",inet_ntoa(clntAddr.sin_addr), ntohs(clntAddr.sin_port));
printf("Client(%d) : %s \n", ntohs(clntAddr.sin_port),rBuff);
printf("Client(%d): is disconnected\n", ntohs(clntAddr.sin_port));

문자열 주소 초기화 방법

struct sockaddr_in addr;

char *serv_ip="211.217.168.13";   // IP주소 문자열 선언
char *serv_port="9190";           // PORT 번호 문자열 선언

memset(&addr, 0, sizeof(addr)); // 구조체 변수 addr의 모든 멤버 8으로 초기화
addr.sin_family=AF_INET;          // 주소체계 지정
addr.sin_addr.s_addr=inet_addr(serv_ip); // 문자열 기반의 IP주소 초기화
addr.sin_port=htons(atoi(serv_port));      // 문자열 기반의 PORT 변호 초기화

서버의 sockaddr_in 구조체 변수에 IP 211. 217 .168 .13 , PORT 9190로 들어오는 요청을 받겠다.

 

INADDR ANY

struct sockaddr_ in addr;
char *serv_port= "9190";

memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(atoi(serv_port));

서버 프로그램의 구현에 많이 선호되는 방법으로 INADDR_ANY라는 이름의 상수를 통해서 IP주소를 자동 할당한다.

두 개 이상의 IP를 할당 받아서 사용하는 경우 PORT변호만 일치하면 수신할 수 있게 된다.

클라이언트는 서버의 기능을 포함하는 경우가 아니라면, 사용될 일이 별로 없다.

 

출처 & 참고

1. 윤성우 열혈 TCP IP 소켓 프로그래밍 Ch. 01

2. 네트워킹 강좌

댓글

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