본문 바로가기
programing/Networks

주소 체계와 데이터 정렬

by RedWiz 2015. 5. 12.

- 인터넷 주소

> IPv4(Internet Protocol version 4) : 4바이트 주소체계

> IPv6(Internet Protocol version 6) : 16바이트 주소체계

 

- IPv4 = 네트워크ID + 호스트ID

 

https://ko.wikipedia.org/wiki/IPv4

 

- 네트워크 주소 : 네트워크 구분을 위한 IP 주소 일부

데이터 전송은 먼저 IP주소중 네트워크 주소만 참조해서 해당 네트워크에 전송한 다음 네트워크를 구성하는 라우터를 거쳐 남은 호스트 주소를 참조하여 해당 IP 주소의 컴퓨터로 전송됨

 

cf. 라우터와 스위치

외부로부터 수신된 데이터를 호스트에 전달하고 호스트가 전달하는 데이터를 외부로 송신해주는 물리적 장치. 라우터보다 기능적으로 작은 것을 스위치라 함

 

- 첫 번째 바이트로 네트워크 주소가 몇 바이트인지(네트워크 ID 바이트 크기 -> 클래스) 판단 가능

클래스 A : 0~127    클래스 B : 128~191    클래스 C : 192~223

=> 클래스 A 첫 번째 비트 : 0    클래스 B 첫 번째 비트  : 10    클래스 C의 첫 번째 비트 : 110

 

- PORT 번호

> IP는 컴퓨터 구분 목적

> IP는 NIC(Network Interface Card)를 통해 컴퓨터 내부로 전송

 

> 컴퓨터 내부에서 OS가 PORT 번호를 활용하여 소켓을 적절히 분배함.

> PORT 번호는 OS 내에서 소켓을 구분하는 목적 => 한 OS 내에서 같은 PORT번호 중복 불가

> 16비트 => 0~65535, 0부터 1023까지는 Well-known Port라 해서 특정 프로그램에 이미 할당됨

> PORT 번호는 중복이 불가능 하지만

TCP소켓과 UDP소켓은 PORT번호를 공유하지 않기 때문에 중복이 가능

 

- SOCKADDR_IN 구조체 : bind 함수 주소 정보 전달 용도

 

typedef struct sockaddr_in

{

sa_family_t        sin_family;     // 주소체계

uint16_t             sin_port;       // 16비트 TCP/UDP PORT 번호

struct in_addr    sin_addr;       // 32비트 IP주소

char                 sin_zero[8];  // 사용안함

} SOCKADDR_IN;

 

typedef stuct in_addr

{

in_addr_t            s_addr;        // 32비트 IPv4 인터넷 주소

} IN_ADDR;

 

cf.

sa_family_t       주소 체계

socklen_t         길이 정보

in_addr_t          IP 주소 정보, uint32_t

in_port_t           PORT번호정보, uint16_t

 

> 멤버 sin_familty

AF_INET        IPv4 인터넷 프로토콜에 적용하는 주소체계

AF_INET6       IPv6 인터넷 프로토콜에 적용하는 주소체계

AF_LOCAL    로컬 통신을 위한 유닉스 프로토콜의 주소체계

> 멤버 sin_port

16 비트 PORT 번호, 네트워크 바이트 순서(빅 엔디안)로 저장

htons() 함수 이용 (host to network short)

> 멤버 sin_addr

32 비트 IP주소 정보, 네트워크 바이트 순서(빅 엔디안)로 저장

htonl() 함수 이용 (host to network long)

> 멤버 sin_zero

의미 없음, sockaddr_in의 크기를 sockaddr과 일치 시키기 위한 멤버

 

- sockaddr 구조체를 사용하기엔 불편하게 되어있고 요구사항이 까다로워서 sockaddr_in을 사용하고

형변환을 함.

typedef struct sockaddr

{

sa_family_t    sin_family;        // 주소 체계 (Address Family)

char             sa_data[14];    // 주소 정보

} SOCKADDR;

 

 

 

- 엔디안

> 빅 엔디안 : 낮은 번지 부터 높은 자리 순 (Network Byte Order) ex) 0x12345678 -> 0x12345678

> 리들 엔디안 : 낮은 번지 부터 낮은 자리 순 (Host Byte Order) ex) 0x12345678 -> 0x78563412

 

> 바이트 순서 변환 함수

unsigned short htons(unsigned short);

unsigned short ntohs(unsigned short);

unsigned long htonl(unsigned long);

unsigned long htonl(usigned long);

 

> intel, AMD는 리틀 엔디안 이라서 변환 함

> 빅 엔디안일 경우 함수를 사용해도 변환 안함

 

- IP 주소 함수

in_addr_t inet_addr(const char* string);    // 성공 : 빅 엔디안으로 변환된 32비트 값, 실패 : INADDR_NONE

: IP주소 문자열을 네트웨크 바이트 순서로 32비트 정수형으로 동시에 변환

* error C4996 오류남

=>

#include <Ws2tcpip.h>

#define InetPton inet_pton

INT inet_pton(INT Family,       // AF_INET : IPv4, AF_INET6 : IPv6

PCSTR pszAddrString,    // Dotted-Decimal Notation 주소 문자열 주소

PVOID pAddrBuf             // IPv4는 IN_ADDR, IPv6는 IN6_ADDR (변환된 주소 저장됨)

); // 비스타 이상부터 호환 

: IPv4와 IPv6 모두 지원(맨 앞 Family로 구분)

 

#include <arpa/inet.h> // 리눅스

int inet_aton(const char* string, struct in_addr* addr);    // 성공 : 1(true), 실패 : 0(false)

: inet_addr() 과 역할은 같으며 구조체 변수 in_addr을 이용함

 

#include <arpa/inet.h> // 리눅스

char* inet_ntoa(struct in_addr adr);    // 성공 : 변환된 문자열 주소, 실패 : -1

: 네트워크 바이트 순서로 정렬된 정수형 IP주소 정보를 보기 쉬운 문자열로 변환함

 

cf. INADDR_ANY : 동작하는 컴퓨터의 IP주소

> 컴퓨터 내에 두 개 이상의 IP를 할당 받아서 사용할 경우(Multi-homed, 라우터가 해당)

할당 받은 IP 중 어떤 주소를 통해서 데이터가 들어오더라도 PORT 번호만 일치하면 수신할 수 있음

> 서버 프로그래밍에는 선호

> 클라 프로그래밍에서는 서버 기능이 포함 되지 않는 이상 잘 사용 안함

 

- 소켓에 인터넷 주소 할당하기

int bind(

SOCKET s,                          // 주소 정보(IP, PORT)를 할당할 핸들

struct sockaddr* myaddr,     // 할당하고자 하는 주소 정보를 지니는 구조체 변수 주소 값

socklen_t addrlen                // 두 번째 인자의 길이

);    // 성공 : 0, 실패 : SOCKET_ERROR

 

 

ex)

SOCKET servSock;

SOCKADDR_IN serv_addr;

char* serv_port = "9190"

 

// 서버 소켓 (리스팅 소켓) 생성

servSock = socket(PF_INET, SOCK_STREAM, 0);

 

// 주소 정보 초기화

memset(&serv_addr, 0, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;    // inet_addr(), inet_aton() 사용 가능

serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

serv_addr.sin_port = htons(atoi(serv_port));

 

// 주소 정보 할당

bind(servSock, (SOCKADDR*) &serv_addr, sizeof(serv_addr));

 

cf. winsock2의 다양한 프로토콜 적용 가능한 변환 함수

 

INT WSAStringToAddress(

LPSTR AddressString,                             // IP와 PORT번호 담고있는 문자열

INT AddressFamily,                                 // 주소 체계

LPWSAPROTOCOL_INFO lpProtocolInfo,    // 프로토콜 Provider 설정, 일반적으로 NULL

LPSOCKADDR lpAddress,                        // 주소정보 담을 구조체 변수 주소

LPINT lpAddressLength                           // 네번째 인자 크기

);    // 성공 : 0, 실패 : SOCKET_ERROR

 

INT WSAAddressToString(

LPSOCKADDR lpsaAddress,                    // 문자열로 변환할 주소정보 지닌 구조체 변수 주소

DWORD dwAddressLength,                      // 첫번째 인자 크기

LPWSAPROTOCOL_INFO lpProtocolInfo,    // 프로토콜 Provider 설정, 일반적으로 NULL

LPTSTR lpszAddressString,                     // 문자열로 변환된 결과를 저장할 배열의 주소

LPDWORD lpdwAddressStringLength         // 네번째 인자 배열 크기를 담는 변수 주소

);    // 성공 : 0, 실패 : SOCKET_ERROR