들어가며

이 글은 42seoul의 libasm 과제를 해결하기 위한 자료로 작성되었습니다.

참고문서(ryukim) https://www.notion.so/Libasm-3c94bbc7df234499b012f6ae82b84dc2

작동 환경 : masOS(Catalina) 10.15.5


목차

  1. nasm 설치

  2. Hello World 출력해보기

  3. Mendatory Part

  4. Bonus Part


  1. nasm 설치

    • MacOS 에는 기본적으로 nasm 이 설치되어 있지 않다. 따라서 우선 nasm 을 설치해줘야 한다.
    • MacOS에서 nasm의 설치는 nasm 공식 홈페이지에서 압축파일을 직접 다운받아 local에 설치하는 방법과 Homebrew를 이용하여 설치하는 방법 두 가지가 있다.

    1.1 공식 사이트에서 파일을 다운받아 설치하기

    • NASM(https://www.nasm.us/) 웹사이트에서 최신버전을 확인한다.
    • nasm-x.xx.xx-tar.gz 형태의 최신 버전을 받아서 압축을 해제한다.
    • nasm-x.xx.xx 폴더에서 ./configure 명령어를 입력한다. 해당 명령어는 Makefile을 이용하여 적절한 C 컴파일러를 찾아주는 명령어이다.
    • make 명령어를 입력하여 nasm을 build 해준다.
    • make install 명령어를 입력하여 nasm을 설치한 후, man page를 확인하여 설치된 것을 확인한다.

    1.2 Homebrew를 이용하여 설치하기

    • 우선 ruby -e "$(curl -fsSL [https://raw.githubusercontent.com/Homebrew/install/master/install](https://raw.githubusercontent.com/Homebrew/install/master/install))" < /dev/null 2> /dev/null 명령어로 Homebrew를 설치한다.
    • 그 다음 brew install nasm 으로 nasm을 설치한다.
      • permission 오류가 발생할 경우, chown 명령어로 해당 경로에 권한을 주어 설치될 수 있도록 한다. (참고)
    • nasm -ver 명령어를 이용하여 nasm의 버전을 확인할 수 있다.
  2. Hello World 출력해보기

    • hello_world.s 파일을 만들고 다음과 같이 입력한다.

        global    start
            section   .text
        start:
            mov       rax, 0x02000004
            mov       rdi, 1
            mov       rsi, message
            mov       rdx, 13
            syscall
            mov       rax, 0x02000001
            xor       rdi, rdi
            syscall 
            section   .data
        message:  
            db        "Hello, World", 10
    • nasm 을 이용하여 object 파일을 생성해준다.

        nasm -f macho64 hello_world.s
    • linker를 이용하여 실행할 수 있는 파일로 만들어준다.

        ld -macosx_version_min 10.7.0 -o hello_world hello_world.o

      -macosx_version_min flag를 넣어주는 이유

    • hello_world 를 실행해보자.

        ./hello_world

      https://s3-us-west-2.amazonaws.com/secure.notion-static.com/acb506fe-67eb-407f-b712-41279f96fa41/Untitled.png

    • global _main 변수로 linking할 경우 ld -lSystem flag를 사용해야 linking 가능하다.

  3. Mandatory Part

     int        ft_strlen(char const *str);
     int        ft_strcmp(char const *s1, char const *s2);
     char        *ft_strcpy(char *dst, char const *src);
     ssize_t        ft_write(int fd, void const *buf, size_t nbyte);
     ssize_t        ft_read(int fd, void *buf, size_t nbyte);
     char        *ft_strdup(char const *s1);
    • ft_strlen
      • 64bit macOS에서 parameter는 rdi, rsi, rdx, rcx, r8, r9 register를 통해서 전달되며, 그 이상의 parameter는 stack을 통해 전달된다. 따라서, char const *str은 rdi에 전달되어 있다. 관련 자료는 calling convention을 찾아보자. 참고자료
      • rax에 저장되어 있는 값은 함수가 끝났을 때 return하는 값이기 때문에 count index를 rax로 사용하였다.
      • strlen 함수는 문자열의 길이를 반환하는 함수이므로, str의 주소를 참조하여 해당 문자가 null인지 아닌지 판단하여 값을 반환하게 된다.
      • assembly에서 값을 비교할 때는 register의 크기에 주의해야 한다. 문자 하나의 data size는 1byte이기 때문에 null을 판단할 때에도 byte 만큼만 비교해야 한다.
    • ft_strcmp
      • assembly에서는 두 operand를 비교할 때, 둘 중 하나의 operand에만 추가 연산이 가능하다. 예를 들어, a와 b를 index 만큼 이동한 위치를 비교한다고 가정할 때, a + index, b + index 와 같은 연산이 불가능하다는 이야기이다.
      • 따라서 위와 같은 연산을 할 경우에는 다른 register에 값을 옮긴 후 옮겨진 값을 이용하여 연산해야 한다.
      • libft에서 고려하지 않았던 확장 아스키코드와의 비교도 가능하기 때문에 unsigned char의 범위 안에 있는 문자는 모두 비교할 수 있어야 한다.
      • 문자의 차이값을 구하는 과정에서 특정 register의 flag에 주의하여야 한다. overflow가 발생했을 경우에 어떻게 처리해야 할지 잘 생각해봐야 한다.
    • ft_strcpy
      • ft_strcmp와 마찬가지로 하나의 register를 temp로 사용하여 src에 있는 값을 복사한 후 복사된 값이 null인지를 체크하여 마지막에 *dest를 return 해주면 된다.
      • 이 함수를 작성하면서 왜 parameter에서 dest가 먼저 전달되는 지 알 수 있었다. rdi와 rsi의 관계가 dest와 src의 관계와 일치한다.
    • ft_write
      • syscall에 대해 이해하고 있다면 함수를 작성하는 것 자체는 어렵지 않다. 그러나, error처리에 대한 부분을 간과하기 쉽다.
      • syscall 후에 error가 발생했다면, 자동적으로 error number를 rax에 return해준다.
      • error가 발생했을 때, 적절한 return value와 errno를 반환해야 하기 때문에 먼저 ___error를 불러오는 방법부터 알아야 한다.
      • ___error 함수를 호출했을 때, return되는 값은 errno의 주소값이다.
      • errno가 제대로 설정되었는지 확인하려면 standard 함수에서의 errno와 비교해보면 된다. 다만 standard 함수에서 errno 출력 후, ft_write 함수를 불러오기 전에 errno를 다시 초기화 해주어야 하는 것을 잊지 말자.
      • https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master syscall 목록
    • ft_read
      • syscall 해야 하는 코드만 다를 뿐, ft_write와 거의 동일하다.
    • ft_strdup
      • ft_strlen함수로 strlen을 구한 후 + 1만큼을 malloc하여 ft_strcpy를 이용하여 복사해주면 쉽게 해결할 수 있다.
      • 다른 함수를 호출할 때, caller, callee calling convention에 유의해야 한다.
  4. Bonus Part

     typedef struct    s_list
     {
         void                    *data;
         struct s_list    *next;
     }                                t_list;
    
     int            ft_atoi_base(char const *str, char const *base);
     void        ft_list_push_front(t_list **begin_list, void *data);
     int            ft_list_size(t_list *begin_list);
     void        ft_list_sort(t_list **begin_list,int (*cmp)());
     void        ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), void (*free_fct)(void *));
    • ft_atoi_base
      • ft_atoi_base는 piscine때 했었던 함수와 동일하게 작성하면 된다.
      • str에 있는 숫자를 base에 맞는 진법으로 변환하여 출력하는 문제이다.
      • str에서 처리해야 할 문자 순서는 whitespace→sign→number순이다.
      • 나머지 규칙은 piscine의 subject를 보고 해당 규칙에 맞게 작성하면 된다.
    • ft_list_push_front
      • assembly에서 list를 구현하기 위해서는 우선 linked list가 어떠한 구조로 이루어져 있는지 이해할 필요가 있다.
      • 구조체에 선언된 data type의 size만큼 메모리를 차지하기 때문에 구조체의 메모리 주소로부터 + datasize만큼 이동한다면 해당 data의 주소를 얻을 수 있다.
      • linked list에서 list의 위치를 조작할 경우에 반드시 이전 list의 주소를 잃어버리지 않도록 기록해두어야 한다.
    • ft_list_size
      • ft_list_size함수는 ft_strlen에서 배열 대신에 list로 바뀌었을 뿐이다.
      • list→next 가 null 인지 확인한다.
    • ft_list_sort
      • ft_list_sort 함수는 piscine 때의 함수와 같은 함수를 assembly로 작성하는 것이다.
      • list를 정렬할 때, 맨 첫 부분, 중간 부분, 마지막 부분으로 나누어서 swap을 진행하였다.
      • swap algorithm은 bubble sort를 사용하였다.
      • 정 안되겠을 땐, C로 작성한 후에 옮겨보자.
    • ft_list_remove_if
      • ft_list_remove_if 함수는 list에서 data와 일치하는 값을 제거 하는 함수이다.
      • 값을 제거한 후 list를 다시 연결해주어야 하기 때문에 제거되는 위치를 고려해주어야 한다.
      • 비교할 datasize에 유의하기
  • threads 에 대하여 배우는 과제
  • mutex, semaphore

Mandatory Part


  • C로 짜야 하고, norm도 맞춰야 한다. 암튼 터지면 안됨

  • 테이블에 둘러앉은 철학자들은 3가지를 한다. 먹고, 생각하고, 자기

  • 먹는 동안은 생각하거나 잘 수 없고, 자는 동안엔 먹거나 생각할 수 없고, 생각하는 동안엔 먹거나 잘 수 없다.

  • 철학자들은 테이블에 원형으로 앉아있고, 가운데는 큰 스파게티가 있다.

  • 몇 개의 포크가 테이블에 있다.

  • 스파게티는 포크 하나로 못 먹기 때문에 철학자들은 반드시 한 손에 포크 하나씩 포크 두 개를 사용해야 한다.

  • 철학자는 굶어선 안된다.

  • 모든 철학자는 먹어야한다.

  • 철학자는 다른 철학자와 얘기하지 않는다.

  • 철학자는 다른 철학자가 언제 죽을지 모른다.

  • 철학자는 식사가 끝날 때 마다 포크를 놓고 잔다.

  • 철학자는 자고 일어나면 생각한다.

  • 철학자가 죽으면 시뮬레이션이 끝난다.

  • 각 프로그램은 같은 옵션을 써야 한다.

    number_of_philosophers : 철학자와 포크의 수

    time_to_die : 단위는 ms이며, 시뮬레이션이 시작하거나 마지막 식사 이후 'time_to_die' 안에 먹는 것을 시작하지 못하면 철학자는 죽는다.

    time_to_eat : 철학자가 먹는데 걸리는 시간이며, 먹는 동안에는 포크 2개를 유지한다.

    time_to_sleep : 철학자가 자는데 쓰는 시간

    number_of_times_each_philosopher_must_eat : 이 argument 는 선택사항이다. 시뮬레이션이 멈추기 위한 최소 식사 횟수 조건. 만약 정의되지 않으면 철학자가 죽을 때 시뮬레이션이 끝난다.

  • 각 철학자는 1부터 number_of_philosophers 까지 숫자가 주어진다.

  • 1번 철학자 옆에는 number_of_philosophers 숫자의 철학자가 있으며, N번째 철학자 옆에는 N-1과 N+1이 있다.

  • 철학자의 어떤 상태 변화든 아래 규칙을 따라 쓰여져야 한다. (X는 철학자 숫자)

    • timestamp_in_ms X has taken a fork
    • timestamp_in_ms X is eating
    • timestamp_in_ms X is sleeping
    • timestamp_in_ms X is thinking
    • timestamp_in_ms X died
  • 상태 출력할 때 다른 철학자랑 섞이게 하지 마라

  • 철학자의 죽음과 철학자가 죽은 것을 출력할 때 10ms 이상 넘기면 안된다.

  • 철학자를 죽이지 마라!

함수 정리

  • usleep()

      #include <unistd.h>
      int usleep(useconds_t useconds);
    
      microseconds 단위로 함수를 대기시키는 함수
      1ms = 1000us
  • gettimeofday()

      #include <sys/time.h>
      int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
    
      struct timeval start, end;
      double diff;
      gettimeofday(&start, NULL);
      usleep(1000)
      gettimeofday(&end, NULL);
      diff = (end.tv_sec - start.tv_sec) * 1000.0 + (end.tv_usec - start.tv_usec) / 1000.0
      printf("%f\n", diff);
    
  • pthread https://reakwon.tistory.com/56

    • pthread_create

        int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
      
        1. thread : 성공적으로 함수가 호출되면 이곳에 thread ID가 저장됩니다. 이 인자로 넘어온 값을 통해서 pthread_join과 같은 함수를 사용할 수 있습니다.
        2. attr : 스레드의 특성을 정의합니다. 기본적으로 NULL을 지정합니다. 만약 스레드의 속성을 지정하려고 한다면 pthread_attr_init등의 함수로 초기화해야합니다.
        3. start_routine : 어떤 로직을 할지 함수 포인터를 매개변수로 받습니다. 
        4. arg : start_routine에 전달될 인자를 말합니다. start_routine에서 이 인자를 변환하여 사용합니다.
    • pthread_join

        int pthread_join(pthread_t thread, void **retval)
      
        1. thread : 우리가 join하려고 하는 thread를 명시해줍니다. pthread_create에서 첫번째 인자가 있었죠? 그 스레드가 join하길 원한다면 이 인자로 넘겨주면 됩니다.
        2. retval : pthread_create에서 start_routine이 반환하는 반환값을 여기에 저장합니다.
    • pthread_detach

      때에 따라서는 스레드가 독립적으로 동작하길 원할 수도 있습니다. 단지 pthread_create 후에 pthread_join으로 기다리지 않구요. 나는 기다려주지 않으니 끝나면 알아서 끝내도록 하라는 방식입니다.

      독립적인 동작을 하는 대신에 스레드가 끝이나면 반드시 자원을 반환시켜야합니다. pthread_create만으로 스레드를 생성하면 루틴이 끝나서도 자원이 반환되지 않습니다. 그러한 문제점을 해결해주는 함수가 바로 pthread_detach입니다.

        int pthread_detach(pthread_t thread)
      
        thread는 우리가 detach 시킬 스레드입니다. 
        성공시 0을 반환하며 실패시 오류 넘버를 반환하지요.
        pthread_detach와 pthread_join을 동시에 사용할 수는 없습니다.
  • mutex https://reakwon.tistory.com/98

    • pthread_mutex_init

      1) 정적으로 할당된 뮤텍스를 초기화하려면 PTHREAD_MUTEX_INITIALIZER 상수를 이용해서 초기화합니다.

      이런 형식으로 사용합니다. : pthread_mutex_t lock = PTHREAD_MUTX_INITIALIZER;

      2) 동적으로 초기화하려면 pthread_mutex_init 함수를 사용하면 됩니다. mutex를 사용하기 전에 초기화를 시작해야합니다.

        int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
    • pthread_mutex_lock

      pthread_mutex_lock, pthread_mutex_unlock : 이 두 함수는 mutex를 이용하여 임계 구역을 진입할때 그 코드 구역을 잠그고 다시 임계 구역이 끝날때 다시 풀어 다음 스레드가 진입할 수 있도록 합니다.

        int pthread_mutex_lock(pthread_mutex_t *mutex);
    • pthread_mutex_unlock

        int pthread_mutex_unlock(pthread_mutex_t *mutex);
    • pthread_mutex_destroy

        int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • semaphore https://yechoi.tistory.com/55 https://noel-embedded.tistory.com/732

    • sem_open

        #include <fcntl.h>           /* For O_* constants */
        #include <sys/stat.h>        /* For mode constants */
        #include <semaphore.h>
      
        sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
      
        oflag = O_CREAT
        mode = 0644
        value = semaphore 수
    • sem_close

        int sem_close(sem_t *sem);
      
        close a named semaphore
    • sem_post

        int sem_post(sem_t *sem);
      
        unlock a semaphore
    • sem_wait

        int sem_wait(sem_t *sem);
      
        lock a semaphore
    • sem_unlink

        int sem_unlink(const char *name);
      
        remove a named semaphore
      
        Ctrl + C 등으로 빠져나왔을 때 name을 가진 semaphore가 그대로 남아있어서 remove 할 때 사용한다.

티스토리가 Markdown 문법을 제대로 지원을 안 해서 다 깨져버리니까 깃헙 링크로 대체합니다.

 

github.com/ceuity/42cursus/tree/main/ft_services

Introduction

  • This topic is intended to introduce you to system administration.
  • It will make you aware of the importance of using scripts to automate your tasks.
  • For that, you will discover the "docker" technology and use it to install a complete web server.
  • This server will run multiples services: Wordpress, phpmyadmin, and a SQL database.

General instructions

  • You must place all the necessary files for the configuration of your server in a folder called srcs.
  • Your Dockerfile file should be at the root of your repository. It will build your container. You can’t use docker-compose.
  • All the necessary files for your WordPress website should be in the folder srcs.

Mandatory Part

  • You must set up a web server with Nginx, in only one docker container. The container OS must be debian buster.
    • Your web server must be able to run several services at the same time. The services will be a WordPress website, phpmyadmin and MySQL. You will need to make sure your SQL database works with the WordPress and phpmyadmin.
    • Your server should be able to use the SSL protocol.
    • You will have to make sure that, depending on the url, your server redirects to the correct website.
    • You will also need to make sure your server is running with an autoindex that must be able to be disabled.

들어가며

이 글은 42seoul의 ft_server 과제를 해결하기 위한 자료로 작성되었습니다.

참고문서(kkang) https://github.com/Kkan9ma/42cursus/tree/master/02_ft_server_docs

작동 환경 : masOS(Catalina) 10.15.5 / Windows10 WSL2 Ubuntu


목차

  1. Docker 설치

  2. Container 생성

  3. nginx 설치

  4. SSL Protocol 사용

  5. php-fpm 설치

  6. MySQL과 phpmyadmin 설치

  7. Wordpress 설치

  8. Autoindex 적용


  1. Docker 설치

  2. Container 생성

    • Docker Container는 Docker image를 바탕으로 생성된다.

    • Docker image를 받은 후 docker run 명령어로 container를 생성할 수 있다.

    • Docker image를 받기 위해서는 docker pull 명령어를 사용하여 image를 다운로드 할 수 있다.

    • 2.1 debian image pull 하기*

    • Mandatory Part에서 container의 OS는 debian buster 여야 한다고 명시되어 있다. 따라서 debian buster image를 pull 하여 container를 생성한다.

    • debian buster는 debian OS의 하나의 버전으로 debian 10에 해당하는 버전 이름이다.

    • Docker에선 pull 명령어를 사용하여 image를 다운로드 할 수 있다.

    • 처음 docker images 명령어를 입력하면 아무것도 없는 것을 확인할 수 있다.

    • docker pull debian:buster 명령어를 입력하여 image를 다운로드 한다.

    • 2.2 image 확인 및 containner 생성하기*

    • image 확인

      • docker images 명령어로 잘 다운로드 되었는지 확인한다.

    • container 생성

      • docker run -it -p 80:80 -p 443:443 —name test debian:buster 명령어로 container를 생성한다.

          - docker run 명령어 형태
          - `$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]` (도커 홈페이지)
        
          [OPTIONS]
          -i : Keep STDIN open even if not attached (interactive의 약자로 docker 내부에서 표준입력으로 command를 입력받을 수 있도록 한다.)
          -t : Allocate a pseudo-TTY (가상의 터미널을 사용)
          --name : 컨테이너의 이름을 정하는 역할. 본 예시에선 test로 명명한다.
          -p : Publish a container's port(s) to the host (컨테이너와 호스트의 포트를 연결해준다)
      • http : 80번 port 사용

      • https : 443번 port 사용

    • container 확인

      • 다른 터미널 탭을 띄워 docker ps 명령어를 통해 현재 container 상태를 확인할 수 있다.

      • container 에 접속한 상태에서 exit 명령어를 통하여 container 를 종료할 수 있다. 종료했을 경우에 docker ps -a 명령어를 통해 종료된 것을 확인할 수 있다.

      • container를 종료했을 때, container에 다시 접속하고 싶다면 아래 명령어로 가능하다.

          (1)
           - docker start 'CONTAINER ID'
           - docker attach 'CONTAINER ID'
        
          (2)
           - docker start -i 'CONTAINER ID'
  3. nginx 설치

    • APT(Advanced Packaging Tool)을 이용하여 container 내부에서 과제를 해결하는데 필요한 프로그램들을 설치해준다.

    • apt-get update -y, apt-get upgrade -y 명령어를 통해 APT를 최신버전으로 업데이트 해준다.

    • 3.1 nginx 설치하기*

    • apt-get install nginx -y 명령어로 nginx 를 설치해준다.

    • 3.2 nginx 시작, 상태 조회하기*

    • nginx는 항상 background에서 작동하고 있어야 하는 프로그램이다.

    • etc/init.d 폴더에 daemon 형태로 프로그램을 저장해둔다.

    • daemon 형태로 저장된 프로그램을 조작하는 명령어는 service 이다.

        service nginx start // nginx 시작
        service nginx status // nginx 상태 조회
    • service 명령어를 이용하여 nginx 를 시작한 후, 브라우저에서 localhost 또는 localhost:80 으로 접속하여 상태를 확인한다.

    • 해당 페이지가 제대로 뜨지 않을 경우, https 로 접속하지 않았는지 확인

    • 만약 해당 방법으로도 조회가 되지 않을 경우, apt-get install curl 명령어를 이용하여 curl 설치하여 curl localhost 명령어를 사용하여 소스가 조회되는지 확인한다.

  4. SSL Protocol 사용

    4.1 SSL Protocol 이란?

    • 전송 계층 보안(Transport Layer Security, TLS, 과거 명칭: 보안 소켓 레이어/Secure Sockets Layer, SSL)은 컴퓨터 네트워크에 통신 보안을 제공하기 위해 설계된 암호 규약이다.

    • 자세한 내용은 링크 참조

    • 4.2 SSL 인증서 만들기*

    • 인증서는 공개키 기반 구조이므로, 개인키부터 만들어 진행해야 한다.

    • 인증서를 만드는 과정은 개인키 생성, CSR 만들기, 인증서 만들기 순서로 진행한다.

      • CSR은 Certificate Signing Request(인증서 서명 요청)이란 뜻으로, 인증서 발급을 위한 필요한 정보를 담고 있는 인증서 신청 형식 데이터이다. (출처)
      • CSR에 포함되는 내용으로는 개인키 생성 단계에서 만들어진 개인키(Private Key)와 공개키(Public Key)의 키쌍 중에서 공개키가 포함되며, 인증서가 적용되는 도메인에 대한 정보 등이 포함된다.
    • CSR(인증서 서명 요청 : Certificate Signing Request)을 만들기위해 openssl을 설치한다.

      apt-get install openssl -y

    • openssl 명령어 구조

      openssl req -out <CSR 파일> -keyout <개인키 파일> rsa:<키 비트 수>

        openssl req -newkey rsa:4096 -nodes -x509 -keyout localhost.dev.key -out localhost.dev.crt -days 365 -subj "/C=KR/ST=Seoul/L=Seoul/O=42Seoul/OU=Hyulee/CN=localhost"
    • openssl 옵션

      • req : 주로 PKCS#10(Public key Cryptography Standard 공개 키 암호 표준) 인증서 요청을 만들고 처리
      • newkey : 새로운 인증서 요청 + 새로운 private key 생성
        • cf) -new: openssl req -new -key <개인키> -out <CSR 파일>
      • RSA : 원하는 암호화 비트수 (일반적으로 2048 또는 4096)
      • nodes : no DES(대칭키 암호 알고리즘 Data Encryption Standard), 암호 사용하여 개인키를 보호하지 않음
      • X.509: 공개키 인증서와 인증 알고리즘을 사용하기 위한 PKI 표준
      • subj: 암호 입력시 들어갈 정보
        • subj를 옵션으로 기재하지 않으면, 커맨드 실행 시 위 정보를 입력하는 창이 나타난다.
      • keyout: .key 파일명을 지정
      • out: .crt 파일명을 지정
    • 4.3 Nginx에 SSL Protocol을 추가하기*

    • 우선 mv 명령어로 만든 키를 지정된 위치로 옮긴 후, 보안을 위해 권한 설정을 해준다.

        mv localhost.dev.crt etc/ssl/certs/
        mv localhost.dev.key etc/ssl/private/
        chmod 600 etc/ssl/certs/localhost.dev.crt etc/ssl/private/localhost.dev.key
    • 현재 http로는 접속 가능하나 https로의 접속은 불가능한 상태이다. 따라서 https로 접속을 가능하게 하기 위해 nginx 설정을 바꾸어준다.

      • nginx 설정 관련 폴더
        • sites-available
          • 설정을 저장하는 곳이다. 이곳에 저장한 설정은 실제로 nginx에 반영되지는 않는다.
          • 따라서 여기에 만든 설정을 sites-enabled에 복사 또는 심볼릭링크를 걸어서 반영한다.
        • sites-enabled
          • sites-available에 저장한 설정을 적용하기 위한 폴더.
    • /etc/nginx/sites-available/default 파일을 수정하여 SSL Protocol 설정 뿐만 아니라 http로 접속했을 때, https로 redirection 해주는 작업까지 필요로 한다.

        server {
            listen 80 default_server;
            listen [::]:80 default_server;
            server_name localhost;
            return 301 https://$server_name$request_uri;
      
            root /var/www/html;
      
            # Add index.php to the list if you are using PHP
            index index.html index.htm index.php;
      
            location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
            }
      
            # pass PHP scripts to FastCGI server
            #
            #location ~ \.php$ {
            #    include snippets/fastcgi-php.conf;
            #
            #    # With php-fpm (or other unix sockets):
            #    fastcgi_pass unix:/run/php/php7.3-fpm.sock;
            #    # With php-cgi (or other tcp sockets):
            #    fastcgi_pass 127.0.0.1:9000;
            #}
      
            # deny access to .htaccess files, if Apache's document root
            # concurs with nginx's one
            #
            #location ~ /\.ht {
            #    deny all;
            #}
        }
      
        server {
            # SSL configuration
      
            listen 443;
            listen [::]:443;
      
            ssl on;
            ssl_certificate /etc/ssl/certs/localhost.dev.crt;
            ssl_certificate_key /etc/ssl/private/localhost.dev.key;
      
            root /var/www/html;
      
            # Add index.php to the list if you are using PHP
            index index.html index.htm index.php;
      
            server_name _;
      
            location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
            }
      
            # pass PHP scripts to FastCGI server
            #
            # location ~ \.php$ {
            #    #    include snippets/fastcgi-php.conf;
            #    # With php-fpm (or other unix sockets):
            #    fastcgi_pass unix:/run/php/php7.3-fpm.sock;
            #    # With php-cgi (or other tcp sockets):
            #    fastcgi_pass 127.0.0.1:9000;
            }
      
            # deny access to .htaccess files, if Apache's document root
            # concurs with nginx's one
            #
            #location ~ /\.ht {
            #    deny all;
            #}
        }
    • 설정 후 service nginx reload 명령어를 통해 설정이 적용된 nginx를 다시 불러온다.

    • http로 접속해도 https로 접속되는 것을 확인할 수 있다.

    • 접속했을 때 경고가 뜨는 원인은 공인된 인증서가 아니기 때문이다.

  5. php-fpm 설치

    서버와 다른 프로그램간의 상호작용을 위해 먼저 php-fpm을 설치한다.

    5.1 PHP 란?

    • php는 프로그래밍 언어의 일종으로, 원래는 동적 웹 페이지를 만들기 위해 설계되었으며 이를 구현하기 위해 PHP로 작성된 코드를 HTML 소스 문서 안에 넣으면 PHP 처리 기능이 있는 웹 서버에서 해당 코드를 인식하여 작성자가 원하는 웹 페이지를 생성한다. 근래에는 PHP 코드와 HTML을 별도 파일로 분리하여 작성하는 경우가 일반적이며, PHP 또한 웹서버가 아닌 php-fpm(PHP FastCGI Process Manager)을 통해 실행하는 경우가 늘어나고 있다.

    • 5.1.1 php-fpm 이란?*

    • php-fpm( PHP FastCGI Process Manager)

    • php-fpm은 FastCGI다.

    • 요청할 때마다 새로운 프로세스 생성하는 CGI는 상대적으로 느리다.

    • 그래서 요청할 때마다 새로운 프로세스를 생성하는 것이 아니라 이미 생성한 프로세스를 재활용하는 방법을 사용하는 것이 고안되었다.

    • 즉, CGI보다 좀 더 빠른 버전이라고 할 수 있다.

    • 출처

    • php-fpm는 php를 FastCGI 방식으로 동작하도록 하는 솔루션인데, 주로 Nginx와 함께 사용된다.

    • 5.2 CGI 란?*

    • CGI(Common Gate Interface)란 서버와 외부 스크립트 또는 프로그램과 상호작용할 때 이루어지는 입출력을 정의한 표준이다.

    • 이 표준에 맞추어 만들어진 것이 CGI 스크립트 또는 CGI 프로그램으로, CGI 프로그램은 어떤 프로그래밍 언어로도 만들 수 있다.

    • 두 개 이상의 컴퓨터간의 자료들을 주고받는 프로그램 또는 주고받는 것 자체를 의미한다고 할 수 있다.

    • 웹페이지는 HTML언어에 의해서 기본적으로 만들어진다. 하지만 HTML만으로 모든 정보를 다 처리할 수는 없다. 왜냐하면 HTML언어는 서버로부터 HTML문서를 보여주는 역할만 할 뿐, 사용자의 동작을 바로 반영하여 업로드할 수는 없기 때문이다.

    • 따라서 홈페이지를 서버-클라이언트 모두 양방향으로 구성할 필요성이 있는 것이다.

    • 이를 해결한 여러 방법 중 하나가 외부 프로그램을 수행하여 그 결과를 HTML형태로 보여주는 방식인 CGI다.

    • 넓은 의미로는 CGI를 수행하는 프로그램을 CGI라고 하기도 한다.

    • 그 대표적인 예가 방명록, 게시판, 메모장 등이다.

    • 5.3 php-fpm 설치하기*

    • apt-get install php-fpm 명령어로 php-fpm을 설치한다.

    • 설치가 완료되었으면, nginx의 default 파일을 수정하여 php-fpm과 연동한다.

    • 5.4 nginx 에 적용하기*

    • apt-get install php-fpm 명령어로 php-fpm을 설치한다.

    • 설치가 완료되었으면, nginx의 default 파일을 수정하여 php-fpm과 연동한다.

    • fastcgi_pass 편집 시, 설치된 php-fpm의 버전과 맞게 기재해주어야 한다. 이번 케이스에선 설치된 php-fpm의 버전은 7.3이므로, php7.3-fpm.sock으로 설정하였다.

    • 또한 현재 상황은 redirection된 경우이기 때문에 https 설정인 listen 443이 있는 블록에 설정해주어야 한다.

    • 5.5 적용되었는지 확인하기*

    • service php7.3-fpm start 명령어로 php-fpm 을 실행시킨다.

    • phpinfo()는 PHP 정보와 설정을 표로 정리해서 보여주는 함수이다.

    • echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php 명령어를 통해 /var/www/htmlphpinfo.php 라는 파일을 만들어 내용을 작성한다.

    • service nginx reload 명령어로 nginx를 재시작 한다.

    • https://localhost/phpinfo.php 로 접속하여 잘 적용되었는지 확인한다.

  6. MySQL과 phpmyadmin 설치

    • SQL Database가 Wordpress와 phpmyadmin과 연동될 수 있도록 MySQL과 phpmyadmin을 설치한다.

    • 6.1 MySQL 이란?*

    • MySQL은 데이터베이스 관리 시스템이다.

    • 데이터베이스 관리 시스템(영어: database management system, DBMS)은 다수의 사용자들이 데이터베이스 내의 데이터를 접근할 수 있도록 해주는 소프트웨어 도구의 집합이다.

    • DBMS은 사용자 또는 다른 프로그램의 요구를 처리하고 적절히 응답하여 데이터를 사용할 수 있도록 해준다.

    • 6.2 phpmyadmin 이란?*

    • phpMyAdmin은 MySQL을 월드 와이드 웹 상에서 관리할 목적으로 PHP로 작성한 오픈 소스 도구이다.

    • 데이터베이스, 테이블, 필드, 열의 작성, 수정, 삭제, 또 SQL 상태 실행, 사용자 및 사용 권한 관리 등의 다양한 작업을 수행할 수 있다. 특히 웹 호스팅 서비스를 위한 가장 대중적인 MySQL 관리 도구 가운데 하나가 되었다.

    • 6.3 설치하기*

    • 6.3.1 MariaDB(MySQL) 설치*

    • Debian OS에서는 MySQL과 거의 동일한 프로그램인 MariaDB를 default로 사용하고 있다. 따라서 MariaDB를 설치한다.

    • apt-get install mariadb-server php-mysql 명령어로 MariaDB를 설치할 수 있다.

    • 6.3.2 phpmyadmin 설치*

    • phpmyadmin은 APT로 설치할 수 없다. 따라서 wget이라는 프로그램을 이용하여 URL로 부터 파일을 다운받아서 설치한다.

      apt-get install wget // 명령어로 wget을 설치한다.
      wget https://files.phpmyadmin.net/phpMyAdmin/5.0.2/phpMyAdmin-5.0.2-all-languages.tar.gz
      tar -xvf phpMyAdmin-5.0.2-all-languages.tar.gz // 명령어로 압축을 푼다.
    • tar 명렁어의 주요 옵션은 아래와 같다.

          - 기본 형식: tar [OPTION...] [FILE]...
          - 옵션
              -f     : 대상 tar 아카이브 지정. (기본 옵션)
              -c     : tar 아카이브 생성. 기존 아카이브 덮어 쓰기. (파일 묶을 때 사용)
              -x     : tar 아카이브에서 파일 추출. (파일 풀 때 사용)
              -v     : 처리되는 과정(파일 정보)을 자세하게 나열.
              -z     : gzip 압축 적용 옵션.
              -j     : bzip2 압축 적용 옵션.
              -t     : tar 아카이브에 포함된 내용 확인.
              -C     : 대상 디렉토리 경로 지정.
              -A     : 지정된 파일을 tar 아카이브에 추가.
              -d     : tar 아카이브와 파일 시스템 간 차이점 검색.
              -r     : tar 아카이브의 마지막에 파일들 추가.
              -u     : tar 아카이브의 마지막에 파일들 추가.
              -k     : tar 아카이브 추출 시, 기존 파일 유지.
              -U     : tar 아카이브 추출 전, 기존 파일 삭제.
              -w     : 모든 진행 과정에 대해 확인 요청. (interactive)
              -e     : 첫 번째 에러 발생 시 중지.
    • phpmyadmin을 설치할 때 파일의 이름은 전통적으로 phpmyadmin으로 지어졌다.

    • 출처

    • mv phpMyAdmin-5.0.2-all-languages /var/www/html/phpmyadmin 명령어로 phpmyadmin의 폴더명 변경과 폴더 이동을 해준다.

    • rm phpMyAdmin-5.0.2-all-languages.tar.gz 명령어로 불필요한 압축파일은 삭제해준다.

    • 6.4 phpmyadmin 설정*

    • phpmyadmin 내에 config.sample.inc.php 의 샘플 파일을 복사하여 config.inc.php 파일을 만든다.

    • 6.4.1 복사하기*

    • cp /var/www/html/phpmyadmin/config.sample.inc.php /var/www/html/phpmyadmin/config.inc.php

    • 6.4.2 편집하기*

    • vim /var/www/html/phpmyadmin/config.inc.php

    • 파일 내부의 내용 중, blowfish_secret(암호화 문자열) 부분에 대한 설정이 필요하다.

      • config.inc.php 파일 내 $cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */ 부분을 편집할 것이며, ''에 비밀번호를 넣으면 된다.

      • 암호화 문자열은 hash 방식으로 만들어진 password를 넣어야 하며, 링크 등을 통해 만들 수 있다.

    • 6.4.3 설정 적용하기*

    • 지금까지 한 설정을 적용하기 위해 필요한 service들을 reload 해준다.

      service nginx reload
      service php7.3-fpm restart
    • 6.5 데이터 테이블 만들기*

    • 이제 Datatable을 만들기 위해서 service mysql start 명령어로 MySQL을 작동시킨다.

    • 6.5.1 MySQL에 테이블 불러오기*

    • MySQL로 데이터를 관리하기 위해 mysql < var/www/html/phpmyadmin/sql/create_tables.sql -u root --skip-password 명령어로 테이블을 불러온다.

      • < 로 외부 .sql 파일에서 데이터를 불러올 수가 있다.
        • table을 새로 만들어주는 sql문이 이미 들어있기에 이를 사용한다.
        • 출처
      • -u 옵션으로 user는 root로 설정한다.
      • --skip-password
    • 6.5.2 MySQL 서버 관리하기*

    • mysqladmin -u root -p password 명령어로 MySQL 계정의 패스워드를 설정해준다.

      • mysqladmin - MySQL 서버를 관리하기 위한 클라이언트이다.
      • 주로 관리 연산을 수행하는 클라이언트로, 서버의 구성 및 현재의 상태를 체크하거나 데이터 베이스를 생성 및 제거하기 위해 사용한다.
      • u 옵션: 서버 접속 시 사용하는 mysql 사용자 이름
      • p 옵션: 서버 접속 시 사용하는 패스워드.
        • 설치 직후엔 root 사용자에 password가 없어 위처럼 사용 가능하다.
    • 기존 비밀번호는 없으니 enter로 넘어가고, new password와 confirm new password 창엔 원하는 비밀번호를 입력한다.

    • 입력하지 않는 경우엔 error 발생 가능.

    • (참고)단, 비밀번호 설정을 하지 않는 방법도 있다.

      • var/www/html/phpmyadmin/config.inc.php 내용 중, AllowNoPassword를 default인 false에서 true로 변경해주면 비밀번호 없이 접속이 가능하다.
    • 6.5.3 MySQL 접속하기*

    • command line에 mysql을 입력하여 MySQL에 접속한다. 단, 패스워드가 있을 경우, mysql -p${PASSWORD}로 접속할 수 있다.

      show databases; // database 조회
      CREATE DATABASE IF NOT EXISTS wordpress; // 워드프레스를 위한 DB 만들기
      Grant all privileges on *.* to ‘user’@‘%’ identified by ‘설정한비밀번호’ with grant option;
      flush privileges;
      show databases; // 변경되었는지 조회
      exit
    • MySQL 문법

      • GRANT 권한 ON 데이터베이스.테이블 TO '아이디'@'호스트' IDENTIFIED BY '비밀번호'
      • all: grant option을 제외한 모든 권한
      • privileges: 권한
      • ``를 사용하면 모든 데이터베이스, 테이블을 제어 대상으로 함 (*.*,class.*)
      • 아이디@호스트 중에서 호스트는 접속자가 사용하는 머신의 IP를 의미한다. IP를 특정하지 않으려면 ‘%’를 사용
      • dev@123.100.100.100 : IP 123.100.100.100인 머신에서 접속한 ID dev
      • dev@% : IP 관계없이 ID가 dev인 사용자
        • ip 관계없이 id가 user이고 비밀번호가 ~~인 사용자에게 권한을 부여한다.
      • flush privileges;
        • 보통은 INSERT, DELETE, UPDATE를 통해 사용자를 추가, 삭제, 권한 변경 등을 수행하였을 때 이 변경 사항을 반영하기 위하여 사용한다.
        • 이 때 FLUSH PRIVILEGES는 grant 테이블을 reload함으로서 변경 사항을 즉시 반영하도록 한다.
        • 출처
    • 6.5.4 phpmyadmin 작동 확인*

    • service nginx reload 명령어로 변경된 사항을 다시 적용한다.

    • localhost/phpmyadmin 에 접속하여 확인한다.

    • 아이디는 root, 비밀번호는 mysql에서 설정한 비밀번호이다.

  7. Wordpress 설치

    7.1 Wordpress 설치하기

    • Wordpress도 마찬가지로 wget을 이용하여 설치를 진행한다.

      wget https://wordpress.org/latest.tar.gz
      tar -xvf latest.tar.gz
      mv wordpress/ var/www/html/
      chown -R www-data:www-data /var/www/html/wordpress
    • chown: chown은 파일을 소유하는 유저와 그룹을 변경하기 위해서 사용한다. (출처)

      • 브라우저에서 wordpress 를 사용하기 위해 폴더에 접근권한을 바꾸어준다.
    • chown -R 관련 링크

    • 7.2 Wordpress 설정하기*

    • Wordpress도 마찬가지로 샘플 설정 파일이 주어지므로 수정하여 사용한다.

    • cp var/www/html/wordpress/wp-config-sample.php var/www/html/wordpress/wp-config.php

    • wp-config.php 파일을 본인의 password에 맞게 수정한다.

    • 7.3 Wordpress 작동 확인*

    • service nginx reload 명령어로 변경사항을 적용시켜준다.

    • localhost/wordpress 에 접속하면 다음과 같은 초기 설정 화면을 볼 수 있다.

    • 페이지를 만든 후 phpmyadmin에서 wordpress 데이터가 제대로 생성되었는지 확인한다.

  8. Autoindex 적용하기

    • 현재 localhost로 접속하면 다음과 같은 화면을 볼 수 있다.

    • autoindex란, 인덱스 페이지를 디렉토리 목록으로 나타내는 방법을 말한다.

    • /etc/nginx/sites-available/default 파일을 편집하여 autoindex 기능을 활성화시킬 수 있다.

    • /etc/nginx/sites-available/default 파일을 다음과 같이 수정해준다.

    • service nginx reload 명령어로 변경사항을 적용시켜준 후 localhost 에 접속하면 autoindex가 적용된 화면을 볼 수 있다.

서비스 하기 전에 도커 맛을 쬐끔만 봐라

netwhat

  1. IP 주소(IP Address)란 무엇인가?

    • IP 주소(IP Address)는 네트워크 계층의 기능을 수행하는 IP 프로토콜이 호스트를 구분하려고 사용하는 주소 체계다. 임의의 호스트를 인터넷에 연결하려면 반드시 IP 주소를 할당받아야 한다. IP 주소는 32비트의 이진 숫자로 구성되는데, 보통 8비트씩 네 부분으로 나누어 십진수로 표현한다.

    • IP 주소는 네트워크 부분과 호스트 부분으로 나뉜다. 네트워크 주소는 특정 네트워크의 주소이고 라우팅시 사용하며, 호스트 주소는 네트워크에 속한 호스트의 주소이다. 같은 네트워크에 있다면 라우터를 거치지 않고도 통신이 가능한데, 이러한 영역을 broadcast 영역이라고 한다.

    • IP 주소는 유일성을 보장하기 위해 국제 표준화 기구에서 전체 주소를 관리하고 할당해 중복 주소의 사용을 원천적으로 차단한다. IP 프로토콜이 처음 개발될 당시에는 현재처럼 폭넓게 활용되리라 예측하지 못했다. 따라서 IP 주소로 표현할 수 있는 최대 주소 공간의 크기를 32비트로 제한함으로써 확장성에 많은 문제점이 야기되고 있다. 이를 해결하려고 새로운 프로토콜 IPv6(Internet Protocol Version 6)에서는 주소 표현 공간을 128비트로 확장했다. 그리고 현재의 IP 프로토콜은 IPv6과 구분하기 위해 IPv4로 표현한다.

    • IPv4는 인터넷 프로토콜의 4번째 판이며, 전 세계적으로 사용된 첫 번째 인터넷 프로토콜이다. IPv4의 주소체계는 총 12자리이며 네 부분으로 나뉜다. 각 부분은 0~255까지 3자리의 수로 표현된다. IPv4 주소는 32비트로 구성되어 있으며, 현재 인터넷 사용자의 증가로 인해 주소공간의 고갈에 대한 우려가 높아지고 있다. 이에 따라 대안으로 128비트 주소체계를 갖는 IPv6가 등장하였다.

    • IPv6(Internet Protocol version 6)는 인터넷 프로토콜 스택 중 네트워크 계층의 프로토콜로서 버전 6 인터넷 프로토콜로 제정된 차세대 인터넷 프로토콜을 말한다. IPv6와 기존 IPv4 사이의 가장 큰 차이점은 바로 IP 주소의 길이가 128비트로 늘어났다는 점이다.

  1. 넷마스크(Netmask)란 무엇인가?

    • 넷마스크란 IP 주소의 네트워크 부분을 가리거나 걸러서 호스트 컴퓨터의 주소 부분만이 남도록 하기 위해 0과 1이 조합되어 있는 문자열이다.

    • IP 주소와 넷마스크를 AND연산하면 네트워크 주소를 얻을 수 있다.

  1. subnet이란 무엇인가?

    • 서브넷은 라우터를 통하지 않고 내부적으로 통신을 할 수 있는 영역이 하나의 서브넷이다. 서브넷 간에는 라우터를 이용하여 통신을 해야 하며, 이때 IP 주소의 어떤 영역시 서브넷을 가리키는지 나타내기 위하여 서브넷 마스크를 사용한다.
    • ex) 12.34.56.78 이라는 IP 주소가 있을 때, 서브넷 마스크를 255.255.255.0 으로 했다면, 앞의 12.34.56까지는 서브넷을 나타내고, 뒤의 78은 호스트를 나타낸다.
    • 이전에는 넷마스크와 서브넷 마스크를 구분해서 사용하였지만, CIDR 이후(현재)에는 서브넷 마스크만 사용하고 있다고 한다.
  2. subnet의 broadcast address란 무엇인가?

    • 서브넷의 호스트 자리에 1을 채운 것으로 255.255.255.255를 사용하거나 위의 예시에서는 12.34.56이 서브넷이므로 12.34.56.255가 broadcast address가 된다.
    • broadcast address에 패킷을 전달할 경우, 해당 서브넷의 모든 호스트에 패킷을 전달하게 된다. 따라서 255.255.255.255에 패킷을 보낼 경우, 인터넷의 모든 IP 주소에 패킷을 보내게 되는 것이다.
  3. Netmask로 IP Address를 나타내기 위한 방식에는 어떤 것이 있는가?

    • 서브넷과 넷마스크를 AND 연산하면 네트워크 주소를 얻을 수 있고, 그 뒤에 호스트 주소를 가져오면 IP 주소를 나타낼 수 있다.
  4. Public IP와 Private IP는 어떻게 다른가?

    • 공인 IP (Public IP)는 인터넷 사용자의 로컬 네트워크를 식별하기 위해 ISP(인터넷 서비스 공급자)가 제공하는 IP 주소이다. 공용 IP 주소라고도 불리우며 외부에 공개되어 있는 IP 주소이다.

    • 공인 IP 주소가 외부에 공개되어 있기에 인터넷에 연결된 다른 PC로부터의 접근이 가능하다. 따라서 공인 IP 주소를 사용하는 경우에는 방화벽 등의 보안 프로그램을 설치할 필요가 있다.

    • 사설 IP (Private IP)는 일반 가정이나 회사 내 등에 할당된 네크워크의 IP 주소이며, 로컬 IP 또는 가상 IP 라고도 한다. IPv4의 주소부족으로 인해 서브넷팅된 IP 이기 때문에 라우터에 의해 로컬 네트워크 상의 PC 나 장치에 할당된다.

    • 사설 IP 주소대역은 다음 3가지 주소대역으로 고정된다.

      • Class A : 10.0.0.0 ~ 10.255.255.255

      • Class B : 172.16.0.0 ~ 172.31.255.255

      • Class C : 192.168.0.0 ~ 192.168.255.255

  • 사설 IP 주소만으로는 인터넷에 직접 연결할 수 없다. 라우터를 통해 1개의 공인 IP 만 할당하고, 라우터에 연결된 개인 PC 는 사설 IP 를 할당 받아 인터넷에 접속할 수 있게 된다.

  1. IP Address의 Class에는 어떤 것이 있는가?

    • IP 주소는 Class라는 개념을 통하여 네트워크 영역과 호스트 영역을 구분하고 있다. 다시 말해, Class는 하나의 IP 주소에서 네트워크 영역과 호스트 영역을 나누는 방법이자 약속이다.

    • Class는 네트워크의 규모에 따라 결정되며, Class의 차이는 A~C(D, E도 있으나 멀티캐스트 또는 연구용으로 사용) 사이에 몇 개의 호스트 주소를 할당할 수 있느냐의 차이이다. 그러나 고정구간으로 낭비가 많아서 CIDR 체계로 변경되었다.

  1. TCP vs UDP

    • TCP는 Transmission Control Protocol의 약자이고, UDP는 User Datagram Protocol의 약자이다. 두 프로토콜은 모두 패킷을 한 컴퓨터에서 다른 컴퓨터로 전달해주는 IP 프로토콜을 기반으로 구현되어 있지만, 서로 다른 특징을 가지고 있다.

    • 수신자와 수신이 제대로 되었는지 확인과정이 이루어지는 TCP에 반해, UDP는 일방적으로 데이터를 송신만 할 뿐, 수신 확인은 하지 않는다. 즉, 신뢰성이 요구되는 애플리케이션에서는 TCP를 사용하고 간단한 데이터를 빠른 속도로 전송하고자 하는 애플리케이션에서는 UDP를 사용한다.

  • 표로 비교하는 TCP vs UDP

TCP(Transmission Control Protocol)

TCP는 네트워크 계층 중 전송 계층에서 사용하는 프로토콜로서, 장치들 사이에 논리적인 접속을 성립(establish)하기 위하여 연결을 설정하여 신뢰성을 보장하는 연결형 서비스 이다. TCP는 네트워크에 연결된 컴퓨터에서 실행되는 프로그램 간에 일련의 옥텟(데이터, 메세지, 세그먼트라는 블록 단위)를 안정적으로, 순서대로, 에러없이 교환할 수 있게 한다.

TCP(Transmission Control Protocol)TCP의 특징

  • TCP는 네트워크 계층 중 전송 계층에서 사용하는 프로토콜로서, 장치들 사이에 논리적인 접속을 성립(establish)하기 위하여 연결을 설정하여 신뢰성을 보장하는 연결형 서비스 이다. TCP는 네트워크에 연결된 컴퓨터에서 실행되는 프로그램 간에 일련의 옥텟(데이터, 메세지, 세그먼트라는 블록 단위)를 안정적으로, 순서대로, 에러없이 교환할 수 있게 한다.

  • 연결형 서비스 : 연결형 서비스로 가상 회선 방식을 제공한다.

  • 흐름제어 (Flow control) : 데이터 처리 속도를 조절하여 수신자의 버퍼 오버플로우를 방지

  • 혼잡제어 (congestion control) : 네트워크 내의 패킷 수가 넘치게 증가하지 않도록 방지

  • 신뢰성이 높은 전송 (Reliable transmission)

    • Dupack-based retransmission

      • 정상적인 상황에서는 ACK 값이 연속적으로 전송되어야 한다.
      • 그러나 ACK값이 중복으로 올 경우 패킷 이상을 감지하고 재전송을 요청한다.
    • Timeout-based retransmission

      • 일정시간동안 ACK 값이 수신을 못할 경우 재전송을 요청한다.
    • 전이중, 점대점 방식

      • 전이중 (Full-Duplex)전송이 양방향으로 동시에 일어날 수 있다.

      • 점대점 (Point to Point)각 연결이 정확히 2개의 종단점을 가지고 있다.

        => 멀티캐스팅이나 브로드캐스팅을 지원하지 않는다.

TCP Header 정보

응용 계층으로부터 데이터를 받은 TCP는 헤더를 추가한 후에 이를 IP로 보낸다. 헤더에는 아래 표와 같은 정보가 포함된다.

제어 비트(Flag Bit) 정보

ACK 제어비트

  • ACK는 송신측에 대하여 수신측에서 긍정 응답으로 보내지는 전송 제어용 캐릭터

  • ACK 번호를 사용하여 패킷이 도착했는지 확인한다.

    -> 송신한 패킷이 제대로 도착하지 않았으면 재송신을 요구한다.

TCP의 연결 및 해제 과정

TCP Connection (3-way handshake)

  1. 먼저 open()을 실행한 클라이언트가 SYN을 보내고 SYN_SENT 상태로 대기한다.
  2. 서버는 SYN_RCVD 상태로 바꾸고 SYN과 응답 ACK를 보낸다.
  3. SYN과 응답 ACK을 받은 클라이언트는 ESTABLISHED 상태로 변경하고 서버에게 응답 ACK를 보낸다.
  4. 응답 ACK를 받은 서버는 ESTABLISHED 상태로 변경한다.

TCP Disconnection (4-way handshake)

  1. 먼저 close()를 실행한 클라이언트가 FIN을 보내고 FIN_WAIT1 상태로 대기한다.
  2. 서버는 CLOSE_WAIT으로 바꾸고 응답 ACK를 전달한다. 동시에 해당 포트에 연결되어 있는 어플리케이션에게 close()를 요청한다.
  3. ACK를 받은 클라이언트는 상태를 FIN_WAIT2로 변경한다.
  4. close() 요청을 받은 서버 어플리케이션은 종료 프로세스를 진행하고 FIN을 클라이언트에 보내 LAST_ACK 상태로 바꾼다.
  5. FIN을 받은 클라이언트는 ACK를 서버에 다시 전송하고 TIME_WAIT으로 상태를 바꾼다. TIME_WAIT에서 일정 시간이 지나면 CLOSED된다. ACK를 받은 서버도 포트를 CLOSED로 닫는다.

주의반드시 서버만 CLOSE_WAIT 상태를 갖는 것은 아니다.서버가 먼저 종료하겠다고 FIN을 보낼 수 있고, 이런 경우 서버가 FIN_WAIT1 상태가 됩니다.누가 먼저 close를 요청하느냐에 따라 상태가 달라질 수 있다.

UDP Header 정보

응용 계층으로부터 데이터 받은 UDP도 UDP 헤더를 추가한 후에 이를 IP로 보낸다.

TCP 헤더와 다르게 UDP 헤더에는 포함된 정보가 부실한 느낌마저 든다.UDP는 수신자가 데이터를 받는지 마는지 관심이 없기 때문이다. 즉, 신뢰성을 보장해주지 않지만 간단하고 속도가 빠른 것이 특징이다.

정리

공통점

차이점

  1. Network layers는 무엇인가?

    • 네트워크 상에서 여러 대의 컴퓨터가 데이터를 주고 받으려면 이들을 서로 연동할 수 있도록 표준화된 인터페이스를 지원해야한다. OSI 7모델과 TPC/IP 모델 모두 계층 구조를 갖고 있기 때문에, 자세히 알아보기 전에 먼저 계층 구조가 어떤 것인지, 적용하면 어떤 점이 좋은지를 알 필요가 있다. 계층 구조(Layered)는 네트워크 뿐만 아니라 운영체제 등 다양한 분야에서 적용되는데, 계층 구조를 사용하는 목적은 분할 정복(Divide and Conquer) 때문이다. 어떠한 복잡한 문제를 해결하고자 할 때, 나누어 생각하면 쉽게 해결할 수 있다는 취지인 것이다.
    • 계층 구조의 또다른 특징은 위, 아래 층으로만 이동할 수 있다는 점이다. 건너뛰어 한번에 맨위 또는 아래로 갈 수 없다. 즉, 다음 단계로 넘어가려면 이전 계층이 전제조건이 되어야한다.
  2. OSI model은 무엇인가?

    OSI 7 Model은 네트워크 통신 과정을 7개의 계층으로 구분한 산업 표준 참조 모델이다. 초창기의 네트워크는 각 컴퓨터마다 시스템이 달랐기 때문에 하드웨어와 소프트웨어의 논리적인 변경없이 통신할 수 있는 표준 모델이 나타나게 되었다.

    OSI 참조 모델은 위의 그림과 같이 7개의 층으로 이루어져 있다.

PDU 란?OSI 7계층에서는 PDU 개념을 중요시 하는데, PDU(Process Data Unit)란 각 계층에서 전송되는 단위이다. 1계층에서 PDU가 비트(Bit)라고 생각하기 쉽지만 PDU라고 하지 않고 여기서 비트는 단위라기 보다는 단지 전기 신호의 흐름일 뿐이다.PDU는 2계층-프레임(Frame), 3계층-패킷(Packet), 4계층-세그먼트(Segment) 만 생각하면 된다. 네트워크 통신과정을 깊게 이해하기 위해서는 왜 각각의 계층의 PDU가 다른지 알아야 하고, 역할에 대해 알고 있어야 한다.

1계층 : 물리계층 (Physical Layer)

물리계층은 OSI 모델의 최하위 계층에 속하며, 상위 계층에서 전송된 데이터를 물리 매체(허브, 라우터, 케이블 등)를 통해 다른 시스템에 전기적 신호를 전송하는 역할을 한다.

즉, 기계어를 전기적 신호로 바꿔서 와이어에 실어주는 것이다.

  • PDU : 비트(Bit)
  • 프로토콜 : Modem, Cable, Fiber, RS-232C
  • 장비 : 허브, 리피터

2계층 : 링크계층 (Link Layer)

링크계층은 네트워크 기기들 사이의 데이터 전송을 하는 역할을 한다. 시스템 간의 오류 없는 데이터 전송을 위해 패킷을 프레임으로 구성하여 물리계층으로 전송한다. 3계층에서 정보를 받아 주소와 제어정보를 헤더와 테일에 추가한다.

  • PDU : 프레임(Frame)
  • 프로토콜 : 이더넷, MAC, PPP, ATM, LAN, Wifi
  • 장비 : 브릿지, 스위치

3계층 : 네트워크계층 (Network Layer)

네트워크계층은 기기에서 데이터그램(Datagram)이 가는 경로를 설정해주는 역할을 한다. 라우팅 알고리즘을 사용하여 최적의 경로를 선택하고 송신측으로부터 수신측으로 전송한다. 이때, 전송되는 데이터는 패킷 단위로 분할하여 전송한 후 다시 합쳐진다. 2계층이 노드 대 노드 전달을 감독한다면, 3계층은 각 패킷이 목적지까지 성공적이고 효과적으로 전달되도록 한다.

  • PDU : 패킷(Packet)
  • 프로토콜 : IP, ICMP 등
  • 장비 : 라우터, L3 스위치

4계층 : 전송계층 (Transport Layer)

발신지에서 목적지(End-to-End) 간 제어와 에러를 관리한다. 패킷의 전송이 유효한지 확인하고 전송에 실패된 패킷을 다시 보내는 것과 같은 신뢰성있는 통신을 보장하며, 헤드에는 세그먼트가 포함된다. 주소 설정, 오류 및 흐름 제어, 다중화를 수행한다.

  • PDU : 세그먼트(Segment)
  • 프로토콜 : TCP, UDP , ARP, RTP
  • 장비 : 게이트웨이, L4 스위치

5계층 : 세션계층 (Session Layer)

통신 세션을 구성하는 계층으로, 포트(Port)번호를 기반으로 연결한다. 통신장치 간의 상호작용을 설정하고 유지하며 동기화한다. 동시송수신(Duplex), 반이중(Half-Duplex), 전이중(Full-Duplex) 방식의 통신과 함께 체크 포인팅과 유후, 종료, 다시 시작 과정 등을 수행한다.

  • 프로토콜 : NetBIOS, SSH, TLS

6계층 : 표현계층 (Presentation Layer)

표현계층은 송신측과 수신측 사이에서 데이터의 형식(png, jpg, jpeg...)을 정해준다. 받은 데이터를 코드 변환, 구문 검색, 암호화, 압축의 과정을 통해 올바른 표준방식으로 변환해준다.

  • 프로토콜 : JPG, MPEG, SMB, AFP

7계층 : 응용계층 (Application Layer)

응용계층은 사용자와 바로 연결되어 있으며 응용 SW를 도와주는 계층이다. 사용자로부터 정보를 입력받아 하위 계층으로 전달하고 하위 계층에서 전송한 데이터를 사용자에게 전달한다.

파일 전송, DB, 메일 전송 등 여러가지 응용 서비스를 네트워크에 연결해주는 역할을 한다.

  • 프로토콜 : DHCP, DNS, FTP, HTTP

5. TCP/IP 모델

그렇지만 OSI 참조 모델은 말그대로 참조 모델일 뿐 실제 사용되는 인터넷 프로토콜은 을 7계층 구조를 완전히 따르지는 않는다. 인터넷 프로토콜 스택(Internet Protocol Stack)은 현재 대부분 TCP/IP를 따른다.

TCP/IP는 인터넷 프로토콜 중 가장 중요한 역할을 하는 TCPIP의 합성어로 데이터의 흐름 관리, 정확성 확인, 패킷의 목적지 보장을 담당한다. 데이터의 정확성 확인은 TCP가, 패킷을 목적지까지 전송하는 일은 IP가 담당한다.

TCP/IP의 4계층TCP/IP는 OSI 참조 모델과 달리 표현계층, 세션계층을 응용계층에 다 포함시키고 있지만, 사실상 TCP/IP Model의 Application 계층 하나에서 Application, Presentatiom, Session 계층의 구현을 다 하고 있다고 이해하는 게 올바르다.

데이터는 아래 그림과 같이 단계 별로 헤더(Data Segment Datagram Frame)를 붙여 전송하며 이를 데이터 캡슐화라고 한다.

  1. DHCP Server와 DHCP Protocol은 무엇인가?

DHCP 프로토콜

동적 호스트 설정 프로토콜(Dynamic Host Configuration Protocol)로서 해당 호스트에게 IP주소, 서브넷 마스크, 기본게이트웨이 IP주소, DNS서버 IP주소 를 자동으로 일정 시간 할당해주는 인터넷 프로토콜

DHCP를 통한 IP 주소 할당은 임대(Lease)라는 개념을 가지고 있는데 이는 DHCP 서버가 IP 주소를 영구적으로 단말에 할당하는 것이 아니고 임대기간(IP Lease Time)을 명시하여 그 기간 동안만 단말이 IP 주소를 사용하도록 하는 것이다. 단말은 임대기간 이후에도 계속 해당 IP 주소를 사용하고자 한다면 IP 주소 임대기간 갱신(IP Address Renewal)을 DHCP 서버에 요청해야 하고 또한 단말은 임대 받은 IP 주소가 더 이상 필요치 않게 되면 IP 주소 반납 절차(IP Address Release)를 수행하게 된다.

즉,

유동 IP를 할당한다 == DHCP서버로부터 IP를 DHCP서버에서 설정해놓은 사용시간만큼 임대해온다.

1.1. DHCP의 구성

1) DHCP 서버

DHCP서버는 인터넷을 제공해주는 곳의 서버에서 실행되는 프로그램으로 일정한 범위의 IP주소를 다른 클라이언트에게 할당하여 자동으로 설정하게 해주는 역할을 한다. DHCP서버는 클라이언트에게 할당된 IP주소를 변경없이 유지해 줄 수 있다. DHCP가 설정해주는 주소 정보들은 아래와 같다.

2) DHCP 클라이언트

클라이언트들은 시스템이 시작하면 DHCP서버에 자신의 시스템을 위한 IP주소를 요청하고, DHCP 서버로부터 IP주소를 부여받으면 TCP/IP 설정은 초기화되고 다른 호스트와 TCP/IP를 사용해서 통신을 할 수 있게 된다.

즉, 서버에게 IP를 할당받으면 TCP/IP 통신을 할 수 있다.

1.2. DHCP 임대 절차

IP 주소 할당(임대) 절차에 사용되는 DHCP 메시지는 아래 그림과 같이 4개의 메시지로 구성되어 있다.

1) DHCP Discover

  • 패킷 방향 : 클라이언트 -> DHCP 서버
  • 브로드캐스트 패킷 : Destination MAC = FF:FF:FF:FF:FF:FF
  • 의미 : 클라이언트가 DHCP 서버를 찾기 위한 메시지. 그래서 LAN상에(동일 subent상에) 브로드캐스팅을 하여 "거기 혹시 DHCP 서버 있으면 내게 응답 좀 해 주세요"라고 단말이 메세지를 보낸다. 이 Discover 패킷에는 IP 주소가 필요한 호스트의 MAC 주소가 담겨져 있어서 DHCP 서버가 응답할 때 패킷을 수신할 수 있게 된다.
  • 주요 파라미터(패킷 내용) :
    • Client MAC : 클라이언트의 MAC 주소

2) DHCP Offer

  • 패킷 방향 : DHCP 서버 -> 클라이언트

  • 브로드캐스트 메시지 : Destination MAC = FF:FF:FF:FF:FF:FF 혹은 유니캐스트.

    이는 클라이언트가 보낸 DHCP Discover 메시지 내의 Broadcast Flag의 값에 따라 달라지는데, 이 Flag=1이면 DHCP 서버는 DHCP Offer 메시지를 Broadcast로, Flag=0이면 Unicast로 보내게 된다.

  • 의미: DHCP 서버가 "저 여기 있어요~"라고 응답하는 메시지. 단순히 DHCP 서버의 존재만을 알리지 않고, 클라이언트에 할당할 IP 주소 정보를 포함한 다양한 "네트워크 정보"를 함께 실어서 클라이언트에 전달한다.

  • 주요 파라미터(패킷 내용) :

    • Client MAC: 단말의 MAC 주소
    • Your IP: 단말에 할당(임대)할 IP 주소
    • Subnet Mask (Option 1)
    • Router (Option 3): 단말의 Default Gateway IP 주소
    • DNS (Option 6): DNS 서버 IP 주소
    • IP Lease Time (Option 51): 단말이 IP 주소(Your IP)를 사용(임대)할 수 있는 기간(시간)
    • DHCP Server Identifier (Option 54): 본 메시지(DHCP Offer)를 보낸 DHCP 서버의 주소. 2개 이상의 DHCP 서버가 DHCP Offer를 보낼 수 있으므로 각 DHCP 서버는 자신의 IP 주소를 본 필드에 넣어서 단말에 보냄.

3) DHCP Request

  • 패킷 방향: 클라이언트 -> DHCP 서버
  • 브로드캐스트 메시지 : Destination MAC = FF:FF:FF:FF:FF:FF
  • 의미: 단말은 DHCP 서버(들)의 존재를 알았고, DHCP 서버가 단말에 제공할 네트워크 정보(IP 주소, subnet mask, default gateway등)를 알았다. 이제 단말은 DHCP Request 메시지를 통해 하나의 DHCP 서버를 선택하고 해당 서버에게 "단말이 사용할 네트워크 정보"를 요청한다.
  • 주요 파라미터(패킷 내용) :
    • Client MAC: 단말의 MAC 주소
    • Requested IP Address (Option 50): 난 이 IP 주소를 사용하겠다. (DHCP Offer의 Your IP 주소가 여기에 들어감)
    • DHCP Server Identifier (Option 54): 2대 이상의 DHCP 서버가 DHCP Offer를 보낸 경우, 단말은 이 중에 마음에 드는 DHCP 서버 하나를 고르게 되고, 그 서버의 IP 주소가 여기에 들어감. 즉, DHCP Server Identifier에 명시된 DHCP 서버에게 "DHCP Request" 메시지를 보내어 단말 IP 주소를 포함한 네트워크 정보를 얻는 것.

4) DHCP Ack

  • 패킷 방향: DHCP 서버 -> 클라이언트

  • 브로드캐스트 메시지 : Destination MAC = FF:FF:FF:FF:FF:FF 혹은 유니캐스트.

    이는 단말이 보낸 DHCP Request 메시지 내의 Broadcast Flag=1이면 DHCP 서버는 DHCP Ack 메시지를 Broadcast로, Flag=0이면 Unicast로 보내게 된다.

  • 의미: DHCP 절차의 마지막 메시지로, DHCP 서버가 단말에게 "네트워크 정보"를 전달해 주는 메시지. 앞서 설명한 DHCP Offer의 '네트워크 정보"와 동일한 파라미터가 포함된다.

  • 주요 파라미터(패킷 내용) : DHCP Request 패킷의 파라미터와 동일

  1. DNS Server와 DNS Protocol은 무엇인가?

DNS 프로토콜

도메인 네임과 IP 주소의 대응 관계를 데이터베이스로 구축해 사용하는 인터넷 프로토콜

위에서 배웠듯 클라이언트에게 DNS (Domain Name Server)를 제공하는 것은 DHCP 서버의 책임이다. DNS는 브라우징을 단순화하는 매우 특별한 목적을 수행하는 인터넷 상의 또 다른 컴퓨터라고 볼 수 있다.

네트워크의 각 컴퓨터에는 고유한 IP 주소가 있고, 이는 인터넷에서도 마찬가지이다. 인터넷에 연결된 모든 네트워크 또는 컴퓨터 서버에도 고유한 주소가 있다. 우리가 자주 방문하는 사이트의 각 IP 주소를 매번 기억하는 것은 사실 불가능한 일에 가깝다. 그래서 우리는 도메인 이름(www.으로 시작하는 주소)을 사용하는데, 사용자가 https://velog.io/@hidaehyunlee 과 같이 입력한 주소를 125.209.222.141와 같은 IP 주소로 변환해주는 일을 바로 DNS가 수행하는 것이다. 이러한 DNS를 운영하는 서버를 네임서버(Name Server)라고 한다.

DNS 절차

1.  특정 사이트를 방문하기위해 사용자가 브라우저에 URL을 입력한다.

2.  그러면 브라우저는 DNS에 접속하여 입력한 도메인 이름과 관련된 IP 주소를 요청한다.

3.  획득한 IP 주소를 사용하여 브라우저는 그 컴퓨터와 통신하고 사용자로부터 요청된 특정 페이지를 요청할 수 있다.

https://d1.awsstatic.com/Route53/how-route-53-routes-traffic.8d313c7da075c3c7303aaef32e89b5d0b7885e7c.png
13. 두 개의 IP Address 사이에 통신하기 위한 규칙은 무엇이 있는가?

https://ko.wikipedia.org/wiki/인터넷_프로토콜

  1. Routing은 어떻게 작동하는가?

IP 라우팅(routing) 동작 과정

1.1. 라우터의 개념

라우터는 전용회선을 통해 LAN에 연결된 컴퓨터들이 동시에 인터넷을 사용할 수 있게 해주는 장비로 데이터를 목적지까지 전달하는 기능을 수행하며 2개 이상의 서로 다른 네트워크를 접속하고 이들 간 데이터를 주고 받게하는 중계 기능도 한다. 대부분의 라우터는 IP 라우팅 기능뿐 아니라 LAN용 프로토콜인 IPX, AppleTalk등의 브리징 기능도 함께한다.

즉, 라우터는 IP네트워크, 서브넷을 관리하면서 다른 네트워크를 거쳐 패킷을 전송하는 역할을 하는 장비이고, 라우팅은 그 패킷을 보낼 경로를 선택하는 과정이라고 볼 수 있다.

1.2. 라우터의 동작원리

라우터는 패킷의 전송경로를 결정하기 위해 랜테이블, 네트워크테이블, 라우팅테이블을 사용한다. 라우터는 위의 3가지 테이블을 관리함으로써 다른 네트워크에 연결된 장치들을 비롯하여 네트워크에 연결된 모든 장치들의 주소를 인식하고 이것을 바탕으로 패킷의 전송경로를 결정한다.

동일 네트워크 상에 있는 장치로 패킷을 보낼 때 라우터에서는 아래 순서를 매번 거친다.

  1. 랜테이블 검사를 한다. 이곳에서는 패킷의 목적지가 같은 네트워크에 있는지 아니면 다른 네트워크에 있는지를 확인한다.
  2. 네트워크테이블을 검사하여 패킷을 전달할 네트워크 주소를 찾아낸다.
  3. 라우팅테이블을 검색하여 가장 적합한 경로를 찾아내서 패킷을 보낸다.
  • 랜테이블

    랜테이블은 라우터에 연결되어 있는 랜 세그먼트 내 장치의 주소를 관리하고 있으며 필터링작업에 사용된다.

  • 네트워크테이블

    네트워크상의 모든 라우터의 주소를 보관하며 패킷의 수신지 라우터를 식별하는데 사용된다.

  • 라우팅테이블

    각각의 라우터에 구축되어 있으며 각 경로에 대한 정보를 유지하고 있어서 다른 세그먼트로 전송 되는 패킷의 가장 효율적인 경로를 결정하는데 사용된다.

1.3. 라우터의 목적지 학습 방법

1) Connected (연결)

자신과 물리적으로 직접 연결되어있는 장비의 IP 주소를 자동으로 알아온다. 이때 IP는 네트워크 주소로 라우팅 테이블에 저장된다.

2) Static (정적)

관리자가 직접 라우팅 경로를 선택해서 보내는 설정.

  • 장점 : 관리자가 테이터가 전송될 경로를 직접 설정하므로 경로관리에 가장 효율적이다.
  • 단점 : 네트워크 변화에 대한 대처가 느리다.

3) Dynamic (동적)

각 라우터들이 갖고 있는 정보를 서로에게 공유하여 라우팅 테이블에 저장한다. 주시적으로 최적경로를 계산하여 라우팅 테이블의 정보를 유지하는 방식이다.

  • 장점 : 네트워크 변화에 대한 대처가 빠르다.
  • 단점 : 주기적으로 경로를 계산해야하므로 리소스 소비량(CPU사용량)이 많아진다.

4) Redistribution (재분배)

정보 교환이 이루어지지 않는 장비끼리 관리자가 강제로 교환하는 방식.

  1. Routing의 기본 Gateway는 무엇인가?

    • Default Routing은 라우팅 테이블 안에 없는 원격 네트워크를 수신지로 패킷을 인접한 라우터로 전송하는 프로세스이다.
    • 경로를 찾아내지 못한 모든 네트워크들을 디폴트 라우트로 빠져 나가라고 정의해 놓은 것
    • 사용 용도는 인터넷을 사용하는 라우터와 Stub 네트워크 라우터이다.
    • ip route 0.0.0.0 0.0.0.0 xxx.xxx.xxx.xxx 앞의 0.0.0.0 들은 Default Network 이고, 뒤의 주소는 Default Network 로 보낼 패킷 주소이다.
  2. IP의 관점에서 Port는 무엇이며, 두 기기간의 통신하는데 사용되는 것은 무엇인가?

    https://ko.wikipedia.org/wiki/포트_(컴퓨터_네트워킹)

Prototype

int ft_printf(const char *, ...);

Program name

  • libftprintf.a

Turn in files

  • *.c, *.h, Makefile

Makefile

  • all, clean, fclean, re, bonus

External functs.

  • malloc, free, write, va_strat, va_arg, va_copy, va_end

Description

  • Write a library that contains ft_printf, a function that will mimic the real printf

Comment

  • libft 사용 가능
  • printf를 최대한 똑같이 동작하게 만들기

선행지식

1. stdarg.h 관련 지식

2. printf

목표

  • printf 함수와 최대한 똑같이 동작하게 만들기

구현 방법

  1. format에서 받은 문자열을 저장한다.
  2. format[i]가 문자열일 경우 그대로 출력한다.
  3. format[i]에 % 문자가 있을 때, flag, width, precision 등을 체크한다.
  4. 해당 기호에 맞는 출력형식으로 출력한다.
  5. 2번으로 돌아가 반복한다.

구현해야 하는 인자

flags : '-0.*'

width

precision

type : cspdiuxX%

 

  • 이때는 아직 열심히 정리를 하지 않았을 때라 함수는 깔끔하게 잘 짠 거 같은데 남아있는 자료가 하나도 없다... 평소에 열심히 정리좀 해둘걸 ㅜ
  • 그래도 딱 필요한 것만 모아두었다 ㅎ

get_next_line

Prototype

int get_next_line(int fd, char **line);

Turn in files

  • get_next_line.c
  • get_next_line_utils.c
  • get_next_line.h

Parameters

  1. file descriptor for reading
  2. the value of what has been read

Return value

  • 1 : A line has been read
  • 0 : EOF has been reached
  • -1 : An error happend

External functs.

  • read, malloc, free

Description

  • Write a function which returns a line read from a file descriptor, without the newline

선행지식

1. File descriptor 관련

2. Read 함수

ssize_t read(int fd, void *buf, size_t count);

Description

  • fd에서 count 만큼 읽어 buf에 저장한다.

Return value

  • 읽은 count 만큼 return. 에러가 발생했을 시 -1을 return한다.

3. Static variable

  • 지역변수와 전역변수의 성질을 동시에 가지고 있는 변수. 프로그램이 종료될 때 까지 메모리에 남아있기 때문에 gnl 함수가 다시 호출되었을 때 첫 번째 line이 아닌 두 번째 line을 읽을 수 있도록 할 수 있다. 함수 내에서만 사용이 가능하지만 전역변수처럼 사용이 가능하다.
  • https://blog.naver.com/ddck1321/221865835857

목표

  • get_next_line 함수를 호출하면 EOF 전 까지 file descriptor에서 한 번에 한 줄을 읽을 수 있어야 한다.
  • file로 부터 읽는 경우와 standard input에서도 작동할 수 있어야 한다.
  • 컴파일 시에 -D BUFFER_SIZE=XX flag를 사용하여 BUFFER_SIZE를 임의로 변경할 수 있으며 정의되지 않을 땐 적절한 값을 사용해야 한다.
  • BUFFER_SIZE가 매우 클 때 (10000000) 일 때에도 정상적으로 작동해야 한다.
  • Static variable을 하나만 사용하여 함수 구현하기.

구현 방법

  1. fd에서 적절한 BUFFER_SIZE만큼 읽어 buf에 저장한다.
  2. buf를 static 변수에 backup 해둔다.
  3. static 변수에 개행이 있는지 확인 후 없다면 다시 읽는다.
  4. static 변수에 개행이 있다면 개행 전 까지 line에 저장하고, 개행 후로는 다시 static변수에 저장한다.
  • 처음에 get_next_line 함수를 완성하고 테스트를 돌려봤을 때 첫 한 줄만 출력이 되고 그 다음줄은 출력이 되지 않았다. 원인을 찾아보니 get_next_line 함수를 2회째 호출할 때 부터 backup 변수에 남아있어야 할 문자열이 사라져 있는 것이었다.
  • get_next_line 함수에서 find_ret_value함수로 backup 값을 넘겨줄 때, static variable은 해당 함수 안에서만 값을 변경할 수 있기 때문에 다른 함수에서도 값을 변경하기 위해서는 &연산자를 이용하여 주소값을 넘겨주어야 했다.
  • main을 만들어서 테스트 결과, subject에서 원하는 결과와 같이 출력은 되었으나, 다른 사람들이 만들어 놓은 테스트를 돌려본 결과, 일부 BUFFER_SIZE와 매우 큰 BUFFER_SIZE에서 오류가 발생하였다.
  • BUFFER_SIZE를 정적으로 할당할 경우 매우 큰 수의 경우에는 할당이 불가하여 segfault 오류가 발생할 수 있으므로 동적할당으로 수정하였다.

get_next_line은 과제 이후에도 다른 프로젝트에서 계속 사용하기 때문에 잘 만들어두는 것이 좋다. 그렇지 않으면 나중에 다른 과제를 할 때 get_next_line을 고치고 있어야 할 지도 모르니까... 지금 내가 그렇다...

42서울 본 과정의 첫 과제인 libft는 c 표준 라이브러리에 있는 함수들을 직접 구현해보는 것이다.

구현해야 할 함수들의 prototype과 각 함수들을 구현할 때 주의할 점을 정리해보았다.

 

블로그에 따로 정리를 해보려 했으나 티스토리가 마크다운을 제대로 지원하지 않아서 글자가 다 깨지기 때문에 노션 링크로 대체한다.

 

 

https://www.notion.so/libft-c95c57cf9a644d7981cc35979e818396

 

 

+ Recent posts