Post Lists

2018년 6월 30일 토요일

Networking - IP Addresses, structs, and Data Munging

http://beej.us/guide/bgnet/html/multi/ipstructsdata.html

3. IP Addresses, structs, and Data Munging
여기가 변화를 위해 코드를 말하게 될 게임 부분이다.

그러나 처음에, 코딩 하지 않고 말해보자. 처음에 나는 IP 주소와 포트에 대해 조금 말하고 싶다. 그래서 우리는 그것을 분류한다. 그러고나서 우리는 소켓 API가 IP주소와 다른 데이터를 어떻게 저장하고 조작하는지에 말할 것이다.

3.1 IP Addresses, version 4 and 6
Ben Kenobi가 여전히 Obi Wan Kenobi라고 불리던 옛날 좋은 시절에, Internet Protocol Version 4, 소위 IPv4라고 불려지는 멋진 네트워크 라우팅 시스템이 있었다. 그것은 4 바이트로 구성된 (일명 네 개의 "octets"), 주소를 가졌고 흔히 점과 숫자 형태로 쓰여졌다. 이렇게: 192.0.2.111.

너는 아마 이것을 봤을 것이다.

사실 이 글에 대해서, 가상적으로 인터넷에 있는 모든 사이트는 IPv4를 사용한다.

Obi Wan을 포함해서 모든 사람이 행복해 했다. 상황은 훌륭했다. Vint Cerf라는 이름의 몇몇 반대론자가 IPv4 주소들이 곧 부족해질 거라는 경고를 모든 사람에게 할 때 까지는!

(완전히 암울한 다가오는 IPv4 아포칼립스를 모든 사람에게 경고하는 것 외에도, Vint Cerf는 또한 인터넷의 아버지로 또한 매우 유ㅇ명하다. 그래서 나는 그의 판단을 비판할 위치에 있지 않다.)

주소가 부족하다고? 이것이 어떻게 그럴 수 있나? 내 말은, 32-bit IPv4 주소에서 수십억개의 IP 주소가 있다는 것이다. 우리는 정말 수십억개의 컴퓨터를 가졌는가?

그렇다.

또한 며 개의 컴퓨터밖에 없고 모든사람들이 생각하기에  수십억은 불가능하게도 매우 큰 숫자라고 생각한 초기 시절에, 큰 조직들은 관대하게 그들 자신 사용을 위해 수백만 개의 IP 주소를 할당받았다. (Xerox, MIT, Ford HP, IBM, GE, AT&T, 그리고 Apple이라고 불려지는 몇 작은 회사, 등)

사실, 만약 몇 가지 임시방편 조치가 없다면, 우리는 오래전에 다 써버렸을 것이다.

그러나 지금, 우리는 우리 IP 주소, 모든 컴퓨터, 모든 계산기, 모든 폰, 모든 주차 미터기, 모든 애완 동물 또한 가지고 말하는 시대에 있다.

그래서 IPv6가 태어났다. Vint Cerf는 아마도 불사이기 때문에, 어느 누구도 그가 다시 말하는 것들 듣고 싶지않다 " 내가 너에게 말했었잖아"라고. 만약 우리가 Internet Protocol의 다음 버전에서 충분한 주소들을 가지지 않는다면.

이것이 너에게 무엇을 암시하는가?

우리는 좀 더 많은 주소들을 필요하다는 것이다.  두 배 이상의 많은 주소가 아니라, 수십억배의 수천억배, 가능한 많은 주소들 중에 79 백만 십억 조.....

너는 말할 것이다 "사실이야? 나는 그리 큰 숫자들을 믿을 이유가 없어." 음, 32bits와 128bits사이의 차이는 많은 것처롬 보일지 않지만, 96개의 더 많은 비트들이 있는 것이다. 그렇지? 그러나 기억해라, 우리는 여기에서 지수에 대해서 말하고 있다고, 32비트들은 40억개의 수를 나타낸다 (2^32), 반면에 128비트들은 340 조x조x조의 숫자들을 나타낸다. (2^128). 그것은 우주의 모든 별에 대한 수백만의 IPv4 인터넷들과 같다.

이 점들과 숫자로 된 IPv4 에 대해 잊어라 또한; 이제 우리는 16진수 표현법을 갖는다, colon으로 분리된 각 두 바이트와 함께, 이것처럼: 2001:0db8:c9d2:aee5:73e3:934a:a5ae:9551.

그게 다가 아니다! 여러번, 너는 그것에 0이 많은 IP 주소들을 가질 것이고, 그리고 너는 그것들을 두 개의 colon사이에 넣을 것이다. 그래서 너는 각 바이트 쌍에 대해 맨 앞의 0을 덜어낼 수 있다. 예를들어, 주소들의 이러한 쌍들의 각각은 같다:

2001:0db8:c9d2:0012:0000:0000:0000:0051
2001:db8:c9d2:12::51

2001:0db8:ab00:0000:0000:0000:0000:0000
2001:db8:ab00::

0000:0000:0000:0000:0000:0000:0000:0001
::1

그 주소 ::1은 loopback 주소이다. 그것은 "내가 지금 이 기계에서 작동되고 있어"라는 의미이다. IPv4에서, loopback 주소는 127.0.0.1 이다.

마지막으로, 너가 우연히 만나게 될, IPv6 주소에 대한 IPv4-호환성 모드가 있다. 예를들어, 만약 너가 IPv4주소 192.0.2.33의 주소를 IPv6의 주소로 표현하고 싶다면, 너는 다음의 표기법을 사용할 것이다:

"::ffff:192.9.2.33".

우리는 심각하고 재미있는 것에 대해 이야기하는 중이다.

사실 이것은 IPv6의 창조자들이 꽤 호탕하게 보유된 사용을 위해 많은 주소들을 없애 버린 것은, serious fun한 것이다. 그러나 우리는 솔직히 너무 많이 가지고 있다, 은하에서 모든 행성에있는 모든 남자, 여자, 아이, 강아지 주차미터를 위해 남은 많은 것들이 있다. 그리고 나를 믿어라, 은하의 모든 행성들이 주차미터가 있다고. 너도 그것이 사실이라는 것을 알것이다.

3.1.1. Subnets
구성에 대한 이유로, "이 IP주소의 이 비트로 시작하여 첫 번째 부분은 IP주소의 network portion이고, 나머지는 host portion이다."라고 선언하는 것은 가끔씩 편리하다.

예를들어, IPv4로, 너는 192.0.2.12,를 가질지도 모르고, 우리는 그 처음 세 바이트들을 네트워크이고, 나머지 바이트들을 호스트라고 말할 수 있다. 또는, 다른 방식으로 표현하여, 우리는 network 192.0.2.0 네트워크에서 host 12에 대해서 말하고 있다고 표현할 수 있다. (우리가 호스트의 바이트들을 어떻게 zero out(0으로) 만들었는지 보아라)

그리고 이제, 좀 더 구시대적인 정보에 대해서 알아보자. 준비 됐냐? 고대 시절에, subnet들의 "classes"가 있었는데, 거기에서 그 주소의 처음의 첫 번째, 두  번 째, 세 번째 바이트는 네트워크 부분이였다. 만약 너가 그 네트워크에 대해 한 바이트를 가질 수 있을 만큼 충분히 운이 좋았고, 세 개가 호스트를 위한 거라면, 너는 너의 네트워크에서 24bit가치의 호스트를 가질 수 있었다. 그것이 "Class A" Network이다. "Class C"는 반대편에 있었다. 네트워크엔 세 바이트를 가지고, 호스트에는 한 바이트를 가지고. (256개의 호스트, 보유된 두개를 빼고.)

그래서 너도 볼 수 있듯이, 몇 개의 Class A가있었고, 매우 많은 class C가 있었다. 그리고 몇 몇의 Class B들은 중간에 있었다.

IP주소의 네트워크 부분은 netmask라고 불려지는 어떤 것으료 묘사되었다. 그리고 너는 그것에서 network 숫자를 얻기위해 IP 주소에, bitwise-AND 연산을한다. netmask는 보통 255.255.255.0.같이 생겼다. (예를들어, 그 netmask로 너의 IP가 192.0.2.12 라면, 그러면 너의 네트워크는 192.0.2.12 AND 255.255.255.0.을 하면 이것은 192.0.2.0을 준다.

불행하개도, 이것은 인터넷의 실제적 필요에 충분히 좋지 않은 것로 판명이 됐다; 우리는 꽤 빠르게 Class C 네트워크들을 소진하고 있었고, 우리는 대개 명백히 Class A가 아니였다. 그래서 심지어 묻기도 성가셨다. 이것을 고치려고, ////....

그러나, 255.192.0.0 같은 긴 숫자의 스트링을 netmask로 사용하는 것은 조금 다루기에 쉽지 않다. 첫 째로, 사람들은 그것이 얼마나 많은 비트인지에 대한 직관적인 생각을 갖지 못하고, 둘 째로 그것은 간단하지 않다. 그래서 새로운 스타일이 따라 나오게 되었따, 그래서 그것은 더욱 좋게 되었다. 너는 그냥 IP 주소 이후에 slash를 넣고, 그러고나서 10진수의 네트워크 비트의 수에 따라간다. 이렇게: 192.0.12/30.

또는 IPv6에 대해서는 이렇게: 2001:db8::/32 or 2001:db8:5413:4028::9db9/64.

3.1.2. Port Numbers
 너가 친절하게도 기억한다면, 나는 일찍이 너에게 Layered Network Model을 알려주었었다. 그 계층 네트워크 모델은 IP(Internet Layer)를 가졌고, 그것은 Host-to-Host Transport Layer로 나눠진다. (TCP and UDP).

IP 주소 외에도 (IP layer에 이해 사용되는), TCP (stream socket)에 의해 사용되고 동시에 UDP(datagram sockets)에 의해 사용되는 다른 주소가 있다. 그것이 port number이다. 그것은 연결을 위한 local address 같은 16비트의 숫자이다.

IP 주소를 한 호텔의 street address라고 생각하고, port number를 room number라고 생각해라. 이것은 꽤 멋진 비유이다; 아마도 나중에, 나는 자동차 산업과 관련된 것을 생각해 낼 것이다.

너가 들어오는 메일과 웹 서비스를 다루는 컴퓨터를 가지고 싶다고 가정하자. - 어떻게 너는 하나의 IP 주소가 있는 컴퓨터에서 두 개 사이를 구분할 것인가?

인터넷에서의 다른 서비스들은 다른 알려진 포트 번호를 갖는다. 너는 Big IANA Port List에서 그것들 모두를 볼 수 있따. 또는 만약 너가 Unix box에 있다면, 너의 /etc/sservices file에서 볼 수 있을 것이다. HTTP(웹)은 port 80이고, telnet은 port 23, SMTP는 port 25, 게임 DOOM은 port 666을 사용했었다 등등. 1024 이하의 포트들은 특별하다고 종종 고려되고, 보통 사용한 특별한 OS 특권을 요구한다.

그리고 이게 포트 번호에 대한 것이다.

3.2. Byte Order
두 가지 바이트 순서가 있다.

요점은, 인터넷 세계에 있는 사람들은 모두 동의한다. 만약 너가 2-byte 16진수를 표현하다면 ,예를들어 b34f, 너는 그것을 두 순차적 바이트들로 저장한다는 것이다. b3 다음에 4f로.
이것은 말이 된다. 이것은 big end가 먼저 저장되어서,Big-Endian이라고 불려진다.

불행하게도, 여기저기 세계에 있는 컴퓨터들은, Intel 또는 Intel-compatible processor가 있는 것들은 바이트들을 역순으로 저장한다. 그래서 b34f는 메모리에 순차적 바이트들 4f 다음에 b3이 저장될 것이다. 이 저장방법은 Little-Endian이라고 불려진다.

그러나 기다려라, 난 아직 용어에 대한 게 끝난 것이 아니다. 좀 더 괜찮은 Big Endian은 또한 Network Byte Order라고 불려진다. 왜냐하면 그것이 네트워크가 입력되는 순서이기 때문이다.

너의 컴퓨터는 숫자들을 Host Byte Order로 저장한다. 만약 그것이 Intel 80x86이라면, Host Byte Order는 Little-Endian이다. 만약 Motorola 68k라면, Host Byte Order는 Big Endian이다. 만약 그것이 PowerPC라면, Host Byte Order는... 음, 그것이 그 때 그 때 다르다.

너가 패킷을 구성하거나 자료구조를 채우는 여러 번 마다, 너는 너의 2- 그리고 4-바이트 숫자들인 Network Byte Order인지 확인 할 필요가 있을 것이다. 그러나 너가 native Host Byte Order를 모른다면 너는 어떻게 이것을 할 수 있는가?

좋은 소식이다! 너는 그냥 Host Byte Order가 옳지 않다고 가정하고, 너는 Network Byte Order를 설정하는 한 함수를 통해서 그 값을 측정한다. 그 함수는 magic conversion을 할 것이다. 그것이 그래야 한다면, 그리고 이러한 방식으로 너의 코드는 다른 endianness의 머신들에 대해 portable 할 것이다.

너가 변환할 수 있는 두 가지 유형의 숫자들이 있다: short (two bytes) 그리고 long (four bytes). 이러한 함수들은 또한 unsigned 변형에 대해서도 작동한다. 가령 너가 Host Byte Order의 short를 Network Byte Order로 변환하고 싶다고 해보자. "host"의 h, 그리고 "to"가 붙고, "network"의 n 그리고 "short"의 s를 붙여 : h-to-n-s, 또는 htons() (read: "Host to Network Short").

이것은 엄청 쉽다.

너는 너가 원하는 "n", "h", "s", "l"의 모든 조합을 사용할 수 있다. 예를들어, stolh()는 없다(Short to Long Host") function. 그러나 이러한 것들이 있다:

  htons() host to network short
  htonl()  host to network long
  ntohs() network to host short
  ntohl()  network to host long

기본적으로, 숫자들이 wire에 가기전에, Network Byte Order로 바꾸길 원할 것이고, 그것들이 wire로 들어올 때, Host Byte Order로 바꾸고시을 것이다.

나는 64-bit variant를 모른다. 미안. 그리고 만약 너가 소수점에 대해 하고 싶다면, Serialization의 부분을 보아라.

이 문서에서 숫자들은 Host Byte order라고 가정해라. 만약 내가 말을 하지 않는다면.

3.3 structs
음, 마침내 여기에 왔다. 프로그래밍에 대해 말할 시간이다. 이 부분에서, 나는 socket 인터페이스에의해 사용되는 다양한 데이터 타입을 다룰 것이다. 그것들의 몇몇은 이해해야할 중요한 것이기 때문에.

처음은 쉬운것이다: socket descriptor. socket descriptor는 다음의 형태이다:

int

그냥 보통 int이다.

여기에서 좀 이상한데, 그래서 참고 읽어보아라.

나의 첫번째 Struct는 struct addrinfo이다. 이 구조는 최근에 만들어진 것이고, 나중 사용을 위한 소켓 주소 구조를 준비시키기위해 사용된다. 그것은 또한 host name lookup에서도 사용되고, service name look up에서도 사용된다. 우리가 실제로 사용할 때, 좀 더 어떤 의미인지 알게 될 것이지만, 그냥 지금은, 그것이 너가 호출할 것 중 하나라고 알아라. 연결을 할 때.

struct addrinfo
{
  int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc..
  int ai_family; // AF_INET, AF_INET6, AF_UNSEPC
  int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
  int ai_protocol; // use 0 for "any"
  size_t ai_addrlen; // size of ai_addr in bytes
  struct sockaddr *ai_addr; // struct sockaddr _in or _in6
  char *ai_canonname; // full canonical hostname

  struct addrinfo *ai_next; // linked list, next node
};

너는 이 구조체를 불러오고, 그러고나서 getaddrin()를 호출할 것이다. 그것은 너가 필요한 모든 것들로 채워진 이러한 자료구조의 새로운 링크드 리스트에 대한 포인터를 반환할 것이다.

너는 그것이 ai_family 필드에서 IPv4 또는 IPv^를 사용하도록 할 수 있고, 그것이 무엇이든 사용하도록 AF_UNSPEC으로 남겨둘 수 있다. 이것은 너의 코드가 IP 버전에 상관없이 사용되도록 할 수 있기 때문에 좋다.

너는 struct addrinfo에서 ai_addr 필드가 struct sockaddr에 대한 포인터라는 것을 볼 것이다. 이것은 우리가 IP 주소 구조의 내부에 있는 핵심 세부사항에 들어가는 곳이다.

너는 보통 이러한 구조에 대해 쓰기를 원치 않을지도 모른다; 종종, 너를 위해 struct addrinfo를 채울 getaddrinfo에 대한 호출이 너가 필요한 모든 것이다. 그러나 너는 그 값들을 얻어내기 위해, 이러한 구조체의 내부를 유심히 볼 필요가 있을 것이다. 그래서 나는 그것을 여기에서 보여줄 것이다.

(또한, struct addrinfo가 만들어지기전에 쓰여진 모든 코드들에 대해, 우리는 모든 이러한 것들을 일일히 채웠고, 그래서 너는 야생에 있는 IPv4 코드를 많이 볼 것이다. 정확히 같은 것을 하는. 이 가이드의 오래된 버전 그리고 등등에서.)

어떤 구조체들은 IPv4이고 어떤 것은 IPv6이고, 어떤것은 둘 다이다. 나는 어떤 것이 무엇인지 표기할 것이다.

어쨋든, struct sockaddr는 많은 유형의 소켓들을 위해 소켓 주소 정보를 가진다.

struct sockaddr
{
  unsigned short ss_family; // address family, AF_xxx
  char sa_data[14]; // 14 bytes of protocol address
};

sa_family는 다양한 것이 될 수 있지만, 그것은 이 문서에서 우리가 하는 모든 것에 대해 AF_INET(IPv4) 또는 AF_INET6 (IPv6)일 것이다. sa_data는 그 소켓에 대한 목적지 주소와 포트 번호를 포함한다. 이것은 오히려 이용하기에 쉽지 않다. 왜냐하면 너는 지루하게 sa_data에서 직접 주소를 채우길 원치 않기 때문이다.

struct sockaddr을 다루기 위해, 프로그래머들은 평행항 구조를 만들었다: struct sockaddr_in ("in" for "Internet") IPv4와 함께 사용될.

그리고 이것은 조금 중요한 것이다: struct sockaddr_in에 대한 포인터는 struct sockaddr에 대한 포인터로 캐스팅될 수 있고, 역으로도 가능하다. 그래서 connect()가 struct sockaddr*를 원할지라도, 너는 여전히 struct sockaddr_in을 사용할 수 있고, 그것을 마지막에 캐스팅할 수 있다.

// (IPv4 only-- see struct sockaddr_in6 for IPv6)

struct sockaddr_in
{
  short int sin_family; // Address family, AF_INET
  unsigned short int sin_port; // Port number
  struct in_addr sin_addr; // Internet address
  unsigned char sin_zero[8]; // Same size as struct sockaddr
};

이 구조는 소켓 주소의 원소들을 참조하는데 편하게 해준다. sin_zero (struct sockaddr의 길이에 대해 구조를 덧붙이기 위해 포함된)는 memset() 함수로 모든 0으로 설정되어야 한다는 것을 주목해라. 또한, sin_family는 struct sockaddr에서 sa_family와 일치하고, AF_INET으로 설정되어야 한다는 것에 주목해라. 마지막으로 SIN_PORT는 Network Byte Order이여야만 한다. (htons()를 사용하여!)

좀 더 깊게 가보자! 너는 sin_addr필드가, struct in_addr이라는 것을 볼 것이다. 그것은 무엇인가? 꽤 드라마틱하지 않지만, 그것은 항상 가장 무서운 union중의 하나이다:

// (IPv4 only -- see struct in6_addr for IPv6)

// Internet address (a structure for historical reasons)
struct in_addr
{
  uint32_t s_addr; // that's a 32-bit int (4 bytes)
};

그것은 union이였었지만, 지금은 사라진 것처럼 버린다. 좋은 제거이다. 그래서 만약 너가 struct sockaddr_in의 타입으로 int를 선언한다면, ina.sin_addr.s_addr은 4-byte IP 주소를 참조한다 (Network Byte Order로). 비록 너의 시스템은 여전히 struct in_addr에대해 무서운 union을 사용할지라도, 너는 여전히 내가 위에서 했던 정확히 같은 방식대로 4-byte IP 주소를 참조할 수 있다. (이것은 #define 때문이다.)

IPv6는 어떤가? 유사한 구조체들이 그것을 위해 또한 존재한다:

// (IPv6 only -- see struct sockaddr_in and struct in_addr for IPv4)

struct sockaddr_in6
{
  u_int16_t sin6_family; // address family, AF_INET6
  u_int16_t sin6_port; // port number, Network Byte Order
  u_int32_t sin6_flowinfo; // IPv6 flow information
  struct in6_addr; // Ipv6 address
  u_int32_t sin6_scope_id; // Scope ID
};

struct in6_addr
{
  unsigned char sa_addr[16]; // IPv6 address
};

IPv6는 IPv6 주소와 포트 번호를 갖는 다는 것을 주목해라. IPv4가 IPv4 주소와 포트번호를 가지는 것처럼.

또한 내가 지금은 IPv6 flow 정보 또는 Scope ID 필드에 대해 말하지 않았다는 것을 주목해라... 이것은 초심자 가이드이다.

마지막이지만 똑같이 중요하게도, 여기에 다른 간단한 구조가 있다, struct sockaddr_storage인데 이것은 IPv4와 IPv6 구조 둘 다를 가지기에 충분히 크도록 설계되었다. (몇몇 호출에 대해, 그것이 너의 struct sockaddr을 IPv4 또는 IPv6로 채울지 모른다면 보게 될 것이다.) 그래서 너는 이 parallet structure에 넘긴다, struct sockaddr에 유사한. 그리고 너가 필요한 타입으로 캐스팅한다:

struct sockaddr storage
{
  sa_family_t  sa_faily;  // address family

  // all this is padding, implementation specific, ignore it;
  char __ss_pad[_SS_PAD1SIZE];
  int64_t __ss_align;
  char __ss_pad2[_SS_PAD2SIZE];
};

중요한 것은 너는 여기에서 ss_family에 있는 address family를 볼 수 있다는것이다. - 그것이 AF_INET 또는 AF_INET6 (IPv4 또는 IPv6에 대한) 인지를 보기위해 이것을 체크한다. 그러고나서 너는 원하면 그것을 struct sockaddr_in 또는 struct sockaddr_in6으로 캐스팅할 수 있다.

3.4 IP Addresses, Part Deux
너에게 운좋게도, 너가 IP 주소를 다루게 해주는 많은 함수들이 있다. 그것들을 일일이 다 알 필요는 없고, 그것들을 << 연산자로 long으로 그것들을 채울 필요가없다.

처음에, 너가 struct sockaddr_in ina를 가졌다고 해보자, 그리고 너는 IP주소 "10.12.110.57" 또는 "2001:db8:63b3:1::3490"을 가지고 있다. 너가 그것을 sockaddr_in에 저장하고 싶어하는. 너가 사용하길 원하는 함수인 inet_pton()은 numbers-and-dots 표기법을 된 IP 주소를 struct in_addr 또는 struct in6_addr 둘 중 하나로 변경한다. 너가 AF_INET 또는AF_INET6 명시한지에 따라서. ("pton"은 "presentation to network"를 말한다 - 너는 기억하기 쉽다면, "printable to network"로 부를 수 있다.) 그 변환은 다음과 같이 만들어질 수 있다:

struct sockaddr_in sa; // IPv4
struct sockaddr_in6 sa6; // IPv6

inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); // IPv4
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6

(Quick note: 이것을 하는 옛날 방식은 inet_addr()이라고 불리는 함수 또는 inet_aton()이라 불리는 다른 함수를 사용했었다; 이러한 것들은 이제 옛날 것이고, IPv6에는 작동하지 않는다.)

이제, 위의 코드는 매우 튼튼하지 않다. 왜냐하면 어떠한 에러 체킹이 없기 때문이다. inet_pton()이 에러시에는 -1을 반환하고 주소가 잘못되었다면 0을 반환한다. 그래서 사용하기 전에 그 결과가 항상 0보다 더 큰지 확인하도록 하자.

이제 너는 문자열 IP 주소를 그것들의 이진 표현으로 바꿀 수 있다. 다른 방법은 어떤가? 너가 struct in_addr을 가지고 있고, 너가 그것을 numbers-and-dots notation으로 프린트하고 싶다면 어떨까? (또는 struct in6_addr이고, hex-and-colons notation으로) 이 경우에, 너는 inet_ntop() 함수를 사용하길 원할 것이다. ("ntop"은 "network to presentation"을의미한다. - 너는 기억하기 더 쉽다면 "network to printable"로 부를 수 있다.) 이것 처럼:

// IPv4:

char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
struct sockaddr_in sa; // pretend this is loaded with something

inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);
printf("The IPv4 address is: %s\n", ip4);

// IPv6:

char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
strut sockaddr_in6 sa6; // pretend this is loaded with something

inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);

printf("The addres is: %s\n", ip6);

너가 그것을 호출할 때, 너는 주소 타입(IPv4 또는IPv6), 주소, 결과를 가질 string에 대한 포인터,그리고 그 스트링의 maximum length를 넘긴다.  (두 매크로가 편리하게 너가 가장 큰 IPv4 또는 IPv6 주소를 보유할 스트링의 크리를 가지고 있다: INET_ADDRSTRLEN, INET6_ADDRSTRLEN.)

(다시 한번 이것들을 하는 옛날 방식을 언급하는 또 다른 quick note: 이 변환을 하는 역사적인 함수는 inet_ntoa()라고 불려진다. 그것은 또한 옛날 것이고, IPv6와 작동안할 것이다.)

마지막으로, 이러한함수들은 오직 숫자로 된 IP 주소에만 작동한다 - 그것들은 hostname에서 "www.example.com"같은 nameserver DNS lookup은 하지 않을 것이다. 너는 나중에 볼 것이지만, 그것을 하기 위해 getaddrinfo()를 사용할 것이다.

3.4.1 Private(Or Disconnected) Networks
많은 장소들이 보호를 위해서 세계의 나머지로부터 네트워크를 숨기는 방화벽을 가진다. 그리고 종종, 방화벽은 "internal" IP 주소를 "external" (세계에서 모든 사람이 아는) IP 주소로 변환한다. Network Address Translation 또는 NAT라고 불리는 프로세스를 사용하여.

아직 긴장되냐? "그가 이 이상한 말로 어디로 갈까?"

음, 긴장을 풀고, 너에게 무알콜 음료를 사줘라. 초심자로서 너는 심지어 NAT에 대해 걱정할 필요가 없으니까. 그것은 너를 위해 투명히 될 것이다. 그러나 나는 너가 보고있는 네트워크 숫자들에 혼란되기 시작한 경우에서 방화벽 뒤의 네트워크에 대해 말하고 싶다.

예를들어, 나는 집에 방화벽을 가지고 있다. 나는 DSL 회사에 의해 나에게 할당된 두 개의 static IPv4 주소를 가지고 있다. 그러나, 나는 그 네트워크에 7대의 컴퓨터를 가지고 있다. 어떻게 이것이 가능한가? 두 개의 컴퓨터들은 같은 IP 주소를 공유할 수 없다, 또는 그 데이터는 어디로 갈지 모를 것이다.

답은: 그들은 같은 IP 주소를 공유하지 않는다. 그것들은 그것에 할당된 2400만 개의 IP주소가 있는 private network에 있다. 그것들은 모두 나를 위한 것이다. 여기에 무슨일이 일어나는지에 대한게 있다.

만약 내가 원격 컴퓨터에 접속한다면, 그것은 내가 192.0.2.33으로부터 접속했다고 말한다. 이것은 나의 ISP가 나에게 제공해준 공공 IP 주소이다. 그러나 내가 만약 나의 local computer에게 그것의 IP주소가 무엇인지 묻는다면, 그것은 10.0.0.5라고 말한다. 누가 IP주소를 다른 것으로 바꾸는 것인가? 맞아. 방화벽이다! 그것이 NAT를 하고있다.

10.x.x.x는 완전히 disconnected 네트워크 또는 방화벽뒤의 네트워크에서만 사용되는 몇개의 보유된 네트워크 중 하나이다. 어떤 private network numbers들이 너가 사용하도록 이용가능한지에 대한 세부사항은 RFC 1918에 있지만, 너가 볼 공통의 것들은 10.x.x.x 그리고 192.168.x.x 이다 여기에서 x는 0-255이다. 일반적으로. 덜 공통적인 것은 172.y.x.x, 이고 y는 16에서 31사이이다.

NATing firewall 뒤의 네트워크들은 이러한 보유된 네트워크중 하나일 필요가 없지만, 그것들은 공통적으로 그렇다

(재미있는 사실! 나의 외부 IP 주소는 192.0.33.이 아니다. 그 192.0.2.X 네트워크는 문서에 사용되기 위해 진짜 IP 주소처럼 믿게 만들어지기 위해 보유된 것이다)

IPv6는 private networks를 또한 가지고 있다. 그것들은 fdxx: 로 시작할 것ㅅ이다 (또는 아마도 미래에는 fcXX:) RFC4193. 그러나 NAT와 IPv6는 일반적으로 섞이지 않는다. (만약 너가 이 문서의 범위를 넘는 IPv4 gateway에 IPv6를하고 있지않다면) - 이론 상으로, 너는 너의 맘대로 매우 많은 주소를 가질 것이고, 너는 더이상 NAT를 사용할 필요가 없을 것이다. 그러나 만약 너가 밖으로 route하지 않을 네트워크에서 너를 위해 주소를 할당하고 싶다면 이것이 어떻게 하는지이다.

댓글 없음:

댓글 쓰기