1. Global IP Internet (upper case)
(1) TCP/IP protocol family를 기반으로 함
- IP (Internet Protocol) : basic naming scheme을 제공, host 간의 패킷 (datagram)의 unreliable delivery capability
-> host들 간의 데이터를 전송할 때 datagram을 잃어버리거나, 똑같은 datagram을 재전송하여 같은 datagram이 네트워크 상에서 여러 개 존재할 수 있음(duplicated packet)
- UDP (Unreliable Datagram Protocol) : IP의 확장버전
: 프로세스 간의 unreliable한 datagram 전송을 제공하기 위해 IP를 사용
- TCP (Transmission Control Protocol) : IP를 사용하여 connection을 통해 프로세스 간의 reliable byte stream을 제공
**reliable : 데이터 손실, duplicated packet X
(2) Socket interface : Unix file I/O와 함수들의 혼합을 통해 접근, 호스트들 사이의 communication을 제공
(3) Hardware and Software Organization of an Internet Application

- Socket interface (system calls) : TCP/IP 네트워크 서비스를 application이 API 형태로 제공 받아서 프로그램을 작성하도록 함
- Hardware interface (interrupts) : 네트워크에서 패킷을 받으면 interrupt 발생을 통해 OS에 패킷을 받았음을 알림
(4) 프로그래머 관점에서의 인터넷
- 호스트들은 32비트의 IP address의 집합으로 mapping돼 있음
- IP address의 집합은 Internet domain names라고 불리는 식별자의 집합으로 맵핑됨
(1 : n , n : 1 , n : n 가능)
- 인터넷 호스트에서의 프로세스는 connection을 통해 다른 인터넷 호스트의 프로세스와 통신
(5) IPv4 , IPv6
- 32비트 address의 original Internet Protocol은 Internet Protocol Version 4 (IPv4)
- 128비트 address인 Internet Protocol Version 6 (IPv6)
2. IP Addresses
(1) 32비트 IP address는 IP address struct 안에 저장돼 있음
- IP address는 항상 메모리 안에 network byte order 형식으로 저장됨 (big-endian byte order)
(호스트에 저장시 little-endian byte order)
- 하나의 시스템에서 다른 시스템으로 패킷 헤더에서 전송된 정수형 데이터에 대해 적용됨
(port number는 인터넷 connection을 식별하기 위해 사용)
/* Internet address structure */
struct in_addr {
uint32_t s_addr; /* network byte order (big-endian) */
};
- host byte order와 network byte order가 다르므로 IP address를 호환해주는 서비스가 필요
: Converting b/w Network and Host byte Order
#include <arpa/inet.h>
unit32_t hton1(unit32_t hostlong);
unit16_t hton1(unit16_t hostshort);
Returns : value in network byte order
// 32, 16비트의 IP address를 받아서 network byte order 방식으로 변경
unit32_t ntoh1(unit32_t netlong);
unit16_t ntoh1(unit16_t netshort);
Returns : value in host byte order
// 32, 16비트의 IP address를 받아서 host byte order 방식으로 변경
(2) Dotted Decimal Notation
- convention에 의해 32비트 IP address의 각 바이트는 decimal value로 표현될 수 있으며 '.'으로 구분됨
ex. 128.2.194.242 (IP address)
32bit -> 0x80 02 c2 f2 / f2 c2 02 80
- getaddrinfo와 getnameinfo 함수를 사용하여 IP address와 dotted decimal format을 변경
3. Internet Domain Name
(1) 인터켓 클라이언트와 서버는 서로 통신할 때 IP address를 사용 -> 도메인 이름들의 집합을 IP주소 집합으로 매핑
(2) 도메인 이름의 집합은 계층구조를 형성, 각 도메인 이름은 자신의 위치를 인코드

DNS (Domain Name Service): Distributed Worldwide Database를 통해 IP address와 Domain name을 맵핑
- First-level domain names : non-profile organization에 의해 정의
- Second-level 이후로는 서브 도메인 네임을 알아서 만들어줌
(3) DNS (Domain Name System)
- 인터넷은 DNS라고 불리는 거대한 worldwide distributed database에서의 IP 주소와 도메인 네임 사이의 맵핑을 유지
- 프로그래머는 DNS 데이터베이스를 많은 host entry들의 집합으로 볼 수 있음
(host entry - 각 호스트마다 IP 주소와 도메인 네임의 집합을 가짐)
: 각 호스트 entry는 도메인 네임과 IP 주소의 집합 사이의 맵핑을 정의
: 각 호스트 entry는 도메인 네임과 IP 주소들의 동등한 class
(4) Properties of DNS Mapping의 특징
- nslookup을 이용하여 DNS Mapping의 properties를 확인할 수 있음
(nslookup - 도메인 네임을 인자로 받아서 IP 주소를 리턴)
- 각 호스트는 항상 loopback address인 127.0.0.1을 매핑하는 도메인 네임인 localhost를 가짐

- hostname을 사용하여 local host의 실제 도메인 네임을 결정

- 도메인 네임과 IP 주소 사이의 1대1 맵핑

- 도메인 네임은 다르지만 IP주소가 같음

- 여러 개의 도메인 네임은 여러 개의 IP 주소로 맵핑

- 몇몇 유효한 도메인 네임은 IP 주소로 맵핑되지 않음

4. Internet Connections
(1) 클라이언트와 서버들은 connection을 통해 바이트 스트림을 보내면서 communicate
각 connection은
- point-to-point : process의 쌍을 연결
- Full-duplex : 데이터는 동시에 양방향으로 흐를 수 있음
- Reliable : 소스에 의해 보내진 바이트 스트림은 보낸 순서대로 목적지에 저장됨
(2) 소켓은 connection의 endpoint
- 소켓 주소는 IPaddress : port pair
(3) port는 프로세스를 식별하는 16비트 정수형
- Ephemeral port : 클라이언트가 connection 요청을 받을 때 클라이언트 커널에 의해 자동적으로 할당됨
- Well-known port : 서버에 의해 제공된 몇몇 서비스를 가짐
(port 80 - Web server , 25 - email server)
(4) Well-known port and Service names
- 유명한 서비스들은 영구적으로 well-known port로 할당돼있음
: echo server : 7/echo
: ssh servers : 22/ssh
: email server : 25/smtp
: Web servers : 80/http
- well-known port와 service name 사이의 맵핑들은 각 리눅스 시스템에서 /etc/services 파일 안에 저장
(5) Anatomy of a Connection
- connection은 두 개의 endpoint들(socket pair)의 소켓 주소(IP주소, port num)로 의해 식별됨
**cliport : 클라이언트 포트, servaddr : 서버의 IP 주소, servport : 서버의 포트

51213: 커널이 할당한 ephemeral 포트
80 : 웹 서비스와 연관된 well-known port
클라이언트와 서버의 소켓 주소가 주어졌다면, 클라이언트와 서버 사이의 connection은 소켓 쌍에 의해 식별됨
(6) 포트를 사용하여 서비스를 식별

5. Socket Interface
(1) system-level 함수의 집합은 네트워크 어플리케이션을 구축하기 위한 Unix I/O와 함께 사용됨
(2) Socket : 데이터 송수신
- 커널에서 소켓은 communication의 endpoint
- 어플리케이션에서 소켓은 어플리케이션이 네트워크로부터 읽거나 네트워크로 쓰도록 하는 file descriptor
(네트워크를 포함하여 모든 Unix I/O 장치들은 파일들로 사용됨)
- 클라이언트와 서버는 소켓 descriptor로 쓰거나 읽는 것으로 서로를 communicate

- regular file I/O와 socket I/O 간의 주된 차이는 어플리케이션이 socket descriptor를 open하는 방식
(3) Socket Address Structures
- 일반적인 소켓 주소 : connect, bind, accept하기 위한 주소 인자
: 소켓 인터페이스가 설계되었을 때 C에선 (void *)와 같은 일반적인 포인터를 갖고 있지 않기 때문에 필요
- 스티븐 convention
typedef struct sockaddr SA;
struct sockaddr {
uint16_t sa_family; /* Protocol family */
char sa_data[14]; /* Address data. */
};
- 인터넷의 특정한 소켓 주소 : 소켓 주소 인자를 받는 함수의 경우, struct sockaddr_in * -> struct sockaddr * 로 변경
struct sockaddr_in {
uint16_t sin_family; /* Protocol family (always AF_INET) */
uint16_t sin_port; /* Port num in network byte order */
struct in_addr sin_addr; /* IP addr in network byte order */
unsigned char sin_zero[8]; /* Pad to sizeof(struct sockaddr) */
};

sin_port는 포트 넘버로 2바이트 할당하여 저장
sin_addr는 network byte order로 IP 주소를 가지며 4 바이트 할당하여 저장

*서버
getaddrinfo를 통해 IP 주소와 포트 넘버를 받아와서 socket을 생성한다.
bind 함수를 통해 커널한테 소켓의 IP 주소와 포트 넘버를 사용하겠다는 관계성을 알려준다.
listen 함수를 통해 connection이 오는 걸 봄 // open_listenfd
accept 함수를 통해 connection이 establish 허용을 결정한다.
서버는 데이터 요청이 올 때까지 기다림
* 클라이언트
getaddrinfo를 통해 IP 주소와 포트 넘버를 받아와서 socket을 생성한다.
connect 함수를 통해 클라이언트 소켓 주소와 서버의 소켓 주소 pair를 생성하여 서버로 connection을 요청한다.
connection establish가 허용되면
클라이언트가 rio_writen 함수를 통해 데이터를 쓰고 이 메세지를 서버로 전송
서버는 이 메세지를 읽고 다시 쓴다.
쓴 메세지를 서버 본인이 읽으며 자신이 보낸 메세지를 받을 때까지 기다림
클라이언트로 보내서 읽고 쓰면서 자신이 보낸 메세지를 받으면 읽고 출력하는 과정을 반복
EOF를 받으면 connection을 끊음
이때 다른 클라이언트의 connection 요청을 받으면 이 요청은 기다림
(4) Host and Service Conversion : getaddrinfo
- getaddrinfo : hostname, host addresses, ports, service names의 문자열을 소켓 주소 구조체로 변경
: gethostbyname, getsetvbyname을 대체
- 장점 : Reentrant (threaded program에서 안전하세 사용)
: portable protocol-independent code를 작성할 수 있음 (IPv4, IPv6)
- 단점 : 복잡, 다행히도 소수의 사용 패턴으로도 충분
int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result);
//호스트 네임이나 주소, 포트나 서비스의 이름, 힌트 입력 파라미터, 출력 연결리스트를 인자로 받음
void freeaddrinfo(struct addrinfo *result); /* Free linked list */
const char *gai_strerror(int errcode); /* Return error msg */
주어진 호스트와 서비스에 대해, getaddrinfo는 result를 리턴하는데,
이때 result는 addrinfo 구조체의 연결 리스트를 가리키며, 이들은 각각 일치하는 소켓 주소 구조체를 가리킨다.
또한 소켓 인터페이서 함수에 대한 인자들을 포함한다.
freeaddrinfo : 연결리스트 전체를 free
gai_strerror : 에러 코드를 에러 메세지로 변환
- getaddrinfo(도메인 네임으로 해당하는 IP 주소를 꺼냄)에 의해 리턴되는 연결리스트

ai_canonname : 도메인 네임
ai_addr : 소켓 주소 포인터로 소켓 주소 구조체를 가리킴
ai_next : 다음 addrinfo 구조체를 가리킴
클라이언트 : socket과 connect에 대한 호출을 성공할 때까지 각 소켓 주소를 차례로 시도
서버 : socket과 bind에 대한 호출을 성공할 때까지 리스트를 확인
- addrinfo Struct
struct addrinfo {
int ai_flags; /* Hints argument flags */
int ai_family; /* First arg to socket function */
int ai_socktype; /* Second arg to socket function */
int ai_protocol; /* Third arg to socket function */
char *ai_canonname; /* Canonical host name */
size_t ai_addrlen; /* Size of ai_addr struct */
struct sockaddr *ai_addr; /* Ptr to socket address structure */
struct addrinfo *ai_next; /* Ptr to next item in linked list */
};
getaddrinfo에 의해 리턴된 각 addrinfo 구조체는 소켓 함수로 직접적으로 이동되는 인자를 포함
connect와 bind 함수로 바로 이동하는 소켓 주소 구조체를 가리킴
(5) Host and Service Conversion : getnameinfo
- 소켓 주소를 해당하는 호스트와 서비스로 변경하는 getaddrinfo의 역
: gethostbyaddr, getservbyport를 대체
: Reentrant, protocol independent함
int getnameinfo(const SA *sa, socklen_t salen, /* In: socket addr */
char *host, size_t hostlen, /* Out: host */
char *serv, size_t servlen, /* Out: service */
int flags); /* optional flags */
ex. conversion 예시
#include "csapp.h"
int main(int argc, char **argv)
{
struct addrinfo *p, *listp, hints;
char buf[MAXLINE];
int rc, flags;
/* Get a list of addrinfo records */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; /* IPv4 only */
hints.ai_socktype = SOCK_STREAM; /* Connections only */
if ((rc = getaddrinfo(argv[1], NULL, &hints, &listp)) != 0) {
//argv[1]은 도메인 네임, hint는 유저가 제공,
//&listp는 함수의 리턴 값으로 들어옴, 도메인 네임에 맵핑이 되어있는 IP 주소를 꺼낼 수 있는
//addrinfo의 연결리스트
fprintf(stderr,
"getaddrinfo error: %s\n", gai_strerror(rc));
exit(1);
}
/* Walk the list and display each IP address */
flags = NI_NUMERICHOST; /* Display address instead of name */
for (p = listp; p; p = p->ai_next) {
Getnameinfo(p->ai_addr, p->ai_addrlen,
buf, MAXLINE, NULL, 0, flags); //버퍼가 IP 주소를 받음
printf("%s\n", buf);
}
/* Clean up */
Freeaddrinfo(listp);
exit(0);
}
hostinfo 수행 : IP 주소 출력

'SP' 카테고리의 다른 글
| [sp] Concurrent Programming(1) (0) | 2022.04.11 |
|---|---|
| [sp] Network Programming (3) (0) | 2022.04.06 |
| [sp] Network Programming (1) (0) | 2022.04.05 |
| [sp] i/o (2) (0) | 2022.04.05 |
| [sp] i/o (1) (0) | 2022.03.30 |