[week07] Tiny 웹서버 선수학습

컴퓨터시스템 11장에서 네트워크에 대한 기본 개념을 공부하며, 인터넷 검색과 책을 바탕으로 정리해본 포스팅입니다.

  • 외부 블로그의 정보는 링크로 출처를 표기했습니다. 그 외의 정보는 컴퓨터시스템 책을 바탕으로 작성되었습니다.
  • 공부하며 쓴 포스팅으로, 잘못된 내용이 있을 수 있습니다.

1. 클라이언트-서버 프로그래밍 모델

선수학습

네트워크 바이트 오더: 빅엔디안

리틀엔디안 & 빅엔디안


빅엔디안: 사람이 숫자를 읽는 순서와 같음. 디버깅이 편하다. 네트워크 바이트 오더링
리틀엔디안: 인텔포멧

[출처]https://genesis8.tistory.com/37 [리틀엔디안 & 빅엔디안]


서버? 클라이언트?

[출처] https://blog.naver.com/myca11/221369799273
출처에서 서버와 클라이언트는 호스트라고 이야기했지만, 책에서는 서버와 클라이언트는 호스트가 아닌 프로세스이며, 같은 호스트 안에서 클라이언트-서버 트랜잭션이 있을 수 있다고 정의한다.

호스트 : Host

네트워크를 이용하기 위해 네트워크에 연결된(= 네트워크 주소가 할당된) 컴퓨터 혹은 그 외의 장치(Device)(= 노드)

노드 : Node

네트워크 공간 상에 있는 모든 장치

따라서 모든 호스트는 노드이지만, 호스트가 아닌 노드는 존재한다. (ex 모뎀, 허브, 스위치등 중간자 역할을 하는 노드들)

서버 : Server

네트워크 상에서 요청에 응답할 수 있는 프로세스

클라이언트 : Client

네트워크 상에서 요청하는 프로세스

  • 한 호스트가 요청을 받았느냐 했느냐에 따라 서버가 되거나 클라이언트가 될 수 있다.
  • 한 호스트는 서로 다른 많은 클라이언트와 서버를 동시에 실행할 수 있다.
    모든 네트워크 응용프로그램은 클라이언트-서버 모델에 기초한다.
    이 모델은 한 개의 서버 프로세스와 한 개 이상의 클라이언트 프로세스로 구성된다.

클라이언트 - 서버 트랜잭션

트랜잭션
  1. 클라이언트가 한 개의 요청(request)을 서버로 보낸다.
    ex) 웹 브라우저가 파일을 필요로 할 때, 웹 서버로 요청을 보낸다.
  1. 서버가 요청을 받고, 해석하고, 자신의 데이터를 본다.
    ex) 웹 서버가 브라우저에게 받은 요청을 바탕으로 디스크 파일을 읽는다.
디스크 파일
  1. 서버는 응답(response)를 클라이언트로 보내고, 다음 요청을 기다린다.
    ex) 웹 서버가 파일을 클라이언트로 보낸다.
  2. 클라이언트는 응답을 받고 받은 결과물을 바탕으로 처리한다.
    ex) 웹 브라우저가 서버로부터 받은 페이지를 스크린에 띄운다.

같은 호스트 안에서도 클라이언트-서버 트랜잭션이 있을 수 있다.

※클라이언트-서버 모델은 클라이언트와 서버의 호스트로의 매핑에 관계없이 동일하다??
[출처] https://m.blog.naver.com/myca11/221389847130

2. 네트워크

별도의 호스트에서 돌아가는 서버와 클라이언트의 트랜잭션을 전제함

선수학습

LAN [이더넷 세그먼트:허브, 브릿지, 라우터]

네트워크 I/O


호스트에게 네트워크는 다른 I/O디바이스와 같다.
네트워크에서 수신한 데이터는 I/O와 메모리 버스를 거쳐 어댑터에서 메모리로, 대개 DMA 전송으로 복사된다. 마찬가지로 메모리에서 네트워크로 복사될 수도 있다.

네트워크의 계층 구조

물리층 : LAN [이더넷 : Ethernet]

이더넷은 가장 대중적인 LAN 기술이다. 이더넷 세그먼트는 몇개의 전선들과 허브로 구성된다. 대개 방이나 빌딩의 한 층 정도의 규모에 설치된다.

이더넷 세그먼트

여러 이더넷 세그먼트가 브릿지를 통해 연결되고,
모든 호스트는 모든 비트로 볼 수 있다.

3.소켓

네트워크 주소 : IP address

네트워크에서 위치를 찾아갈 수 있는 유일한 값

Dotted-demical address / Hex address

IP주소 표기법

ex) 128.2.194.242 : 80 | 2 | c2 | f2 : 0x8002c2f2
1. 데이터는 프로세스 레벨에서 주고 받는다.
2. 호스트에서는 여러 프로세스가 동시에 동작한다.
3. 따라서 데이터가 네트워크를 통해 호스트에 도달했을 때, 요청에 맞는 프로세스까지 전달되어야 한다.

포트 : Port

네트워크를 통해 데이터를 주고받는 프로세스를 식별하기 위해 호스트 내부적으로 프로세스가 할당받는 고유한 값

소켓 : Socket

프로세스가 네트워크를 통해서 데이터를 주고받기 위해 여는 창구

소켓 인터페이스

https://en.wikipedia.org/wiki/Berkeley_sockets 소켓인터페이스
https://blockdmask.tistory.com/212 socket은 system call이다.

getaddrinfo : host의 소켓주소를 받는다.

입력한 정보에 맞는 소켓 프로토타입의 주소를 받아서 그걸로 소켓을 만든다(뇌피셜)

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    
    int getaddrinfo(const char *node,     // e.g. "www.example.com" or IP
                    const char *service,  // e.g. "http" or port number
                    const struct addrinfo *hints,
                    struct addrinfo **res);


hints : IPv4 | IPv6, TCP | UDP 여부

다음 함수에 hostname을 인자로 넘기면 IP주소를 뱉는다.
(cmd > hostname 명령어로 hostname 확인가능)

memset 함수

  • malloc()이나, calloc()에서 할당 받은 메모리를 특정 값으로 초기화 하는 함수.
  • 보통 어떤 작업을 하기 전에 NULL로 초기화 할 때 많이 사용된다.
  • calloc은 malloc과 memset(void *ptr, 0, size_t size)의 기능이 합쳐진것이다. (0으로 초기화)
/*
** showip.c -- show IP addresses for a host given on the command line
*/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
    struct addrinfo hints, *res, *p;
    int status;
    char ipstr[INET6_ADDRSTRLEN];

    if (argc != 2) {
        fprintf(stderr,"usage: showip hostname\n");
        return 1;
    }

    memset(&hints, 0, sizeof hints);		// hint 구조체 초기화 
    hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
    hints.ai_socktype = SOCK_STREAM;		// TCP

    if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {	
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        return 2;
    }

    printf("IP addresses for %s:\n\n", argv[1]);

    for(p = res;p != NULL; p = p->ai_next) {
        void *addr;
        char *ipver;

        // get the pointer to the address itself,
        // different fields in IPv4 and IPv6:
        if (p->ai_family == AF_INET) { // IPv4
            struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
            addr = &(ipv4->sin_addr);
            ipver = "IPv4";
        } else { // IPv6
            struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
            addr = &(ipv6->sin6_addr);
            ipver = "IPv6";
        }

        // convert the IP to a string and print it:
        inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
        printf("  %s: %s\n", ipver, ipstr);
    }

    freeaddrinfo(res); // free the linked list

    return 0;
}

소켓 주소 구조체: socket address structure

socket() (둘 다)

  • system call
  • socket 식별자 생성.

getaddrinfo로 만든 res를 이용해 socket 생성

error 발생 시 -1 리턴

connect() (client)

bind() (server)

    #include <sys/types.h>
    #include <sys/socket.h>
    
    int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
  • sockfd : socket 파일 디스크립터
    파일 디스크립터(FD) : 파일이 open될 때 할당되는 정수값. 프로세스가 열려있는 파일에 system call을 이용해서 접근할 때, 이 값을 이용해서 파일을 지칭할 수 있다.
  • *my_addr : (서버)소켓 주소값
  • addrlen : 그 주소 길이

error 발생 시 -1 리턴

listen() (server)

    int listen(int sockfd, int backlog); 
  • sockfd : socket 파일 디스크립터
  • backlog : queue에 들어갈 수 있는 최대 요청 개수

error 발생 시 -1 리턴

accept() (server)

rio : 데이터를 저장하기 위한 안정적인 구조체

좋은 웹페이지 즐겨찾기