ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SW 정글 49일차] Tiny 웹 서버 구현하기
    기타/SW 사관학교 정글 2021. 9. 20. 02:13

    오늘은 첫 번째 과제인 Tiny 웹 서버 만들기를 시작했다.

    소켓 인터페이스 구현 부분을 꽤 깊이있게 공부해서 그런지 처음보는 매크로나 함수들에 대한 이해도를 제외하면 코드를 이해하는 데 어려움은 없었다.

    그래도 일단은 과제를 다 하고 복습은 해야한다고 생각한다.

     

     

    1. 서버는 무엇인가?

    오늘 구현한 Tiny 웹 서버를 알아보기 전에 웹 서버가 무엇인지 알아볼 필요가 있고 웹 서버를 알아보기 전에 근본적으로 서버가 무엇인지 알아볼 필요가 있다.

     

    먼저, 우리가 흔히 알고있는 네트워크라는 큰 틀에서는 클라이언트와 서버라는 모델에 기초하고 있다.

    여기서, 클라이언트는 자신이 필요로 하는 무언가를 요청하는 대상이고 서버는 클라이언트의 요청을 받아 필요로 하는 서비스를 제공, 응답해주는 대상이다.

    즉, 물리적으로는 서버라는 개념이 하나의 컴퓨터라고 볼 수 있고 소프트웨어적으로는 요청을 받아 그에 대한 응답을 해주도록 구현되어진 것이다.

    예를 들어, 클라이언트가 이미지나 동영상, 파일 등을 필요로 하여 요청을 보내면 서버는 자신이 가지고 있는 것들을 찾아보며 클라이언트가 요청한 것이 있는지 살펴보고 있으면 요청한 것을 응답으로 보내주고 없다면 없다는 응답을 보내준다.

     

    그러면 클라이언트와 서버가 요청과 응답을 주고 받을 때, 서버는 고정적으로 응답을 해주는 것이니까 언제나 서버일까?

    그렇지는 않다.

    만약에 클라이언트가 요청한 것이 서버에게는 또 다른 누군가에게 요청하여 얻어와야 한다면 서버는 클라이언트 입자잉 되고 또 다른 누군가가 서버가 되는 것이다.

    즉, 서버라는 것은 고정적인 개념이 아니라 역할적인 개념이라는 것이다.

     

    서버를 보다 명확하고 쉽게 알고자 한다면 실생활의 예를 들어보면 좋다.

    우리가 server라는 용어에서 serve라는 동사원형을 추출할 수 있고 serve는 '제공하다'라는 의미를 가지고 있다.

    serve에서 severing이라는 단어를 연상할 수 있는데 실생활에서 serving하면 떠오르는 것이 홀서빙 알바가 있을 것이다.

    홀서빙 알바는 손님이 주문한 것에 대해 메뉴를 알고 있어야하고 주방으로부터 나온 음식을 잘 전달해주어야하는 역할을 한다.

    즉, 손님의 요청에 따라 그에 맞는 응답을 해주는 것이 홀서빙의 역할이고 네트워크에 대입하면 홀서빙이 서버이다.

    그러면 홀서빙 알바가 클라이언트의 입장이 되는 경우가 있을까?

    상황을 묘사해보면 음식을 만들 재료가 모두 소진되었다면 재료 주문을 위해 발주(요청)를 넣어야하고 발주를 받는 발주사가 있을 것이다.

    여기서 홀서빙 알바는 요청을 보내는 클라이언트 입장이 되고 발주사가 응답을 하는 서버의 입장이 된다. 

     

    key point!

    1. 서버라는 것은 고정적인 개념이 아닌 역할적인 개념이다.

    2. 서버와 클라이언트 관계는 언제든지 뒤바뀔 수 있다.

    3. 서버와 클아이언트의 관계는 1:N이다.

    4. 서버는 클라이언트의 요청에 따라 응답을 해주는 역할을 하는 것이다.

     

    2. Web Server와 Web Application Server

    그러면 web server는 무엇일까?

    web server는 클라이언트로부터 HTTP 요청을 받아 HTML 문서나 각종 리소스를 응답하는 컴퓨터이다.

    즉, 큰 개념에서는 위에서 설명한 server와의 개념을 내포하고 그 중에서 클라이언트의 요청이 HTTP라는 프로토콜을 사용하여 들어오면 그에 대한 응답처리를 하는 것이다.

     

    web sever가 응답을 해줄 수 있는 리소스는 HTML, CSS, 이미지 등 정적인 데이터만으로 한정되어 있다.

    그러면 정적인 컨텐츠(추가적인 가공을 하지않는 기존에 존재하는 리소스) 이외에 동적인 컨텐츠(실행파일이 런타임에 만들 출력물)에 대한 요청은 어떻게 처리할까?

    이러한 물음을 해결하기 위해 등장한 것이 Web Application Sever(WAS)이다.

    Web Application Server에서 Web Application이라는 것은 웹 브라우저에서 이용할 수 있는 응용 소프트웨어를 말하고 Web Application Sever는 웹 애플리케이션과 서버 환경을 만들어 동작시키는 기능을 제공하는 소프트웨어 프레임워크이다.

     

    WAS는 정적인 콘텐츠를 처리하는 Web Sever와 동적인 컨텐츠를 처리하는 Web Container로 이루어져있다.

    WAS의 구조를 보면 아래의 그림과 같다.

    출처: https://www.youtube.com/watch?v=F_vBAbjj4Pk

    클라이언트의 요청이 정적인 컨텐츠라면 Web server에서 처리하여 응답을 해주고 동적인 컨텐츠라면 Web container가 요청을 받아 응답을 한다.

     

    그러면 여기서 드는 궁금점이 WAS가 정적인 컨텐츠와 동적인 컨텐츠 둘 다 처리가 가능하면 Web server를 따로 두지 않고 WAS만 두면 되지않을까? 이다.

     

    정답이라는 것은 없지만 대규모 프로젝트에서는 Web server와 WAS를 따로 두어 관리한다.

    그 이유는 아래와 같다.

    1. 기능을 분리하여 서버 부하 방지

    (WAS의 종류 중 하나인 Tomcat 5.5. 버전 이상부터는 성능 상 차이가 있지 않는다고 함.)

     

    2. 물리적으로 분리하여 보안 강화

    이 부분은 아래의 그림을 보며 추가적인 설명이 필요하다.

    동적인 콘텐츠 응답을 위해 DB 조회나 접근 등같이 보안 상 위험에 노출될 수 있다.

    이러한 경우를 대비하여 WAS의 앞에 web server를 두어 공격에 대해 WAS까지 전파되지 못하게 한다.

    출처: https://www.youtube.com/watch?v=F_vBAbjj4Pk

    3. 여러 대의 WAS를 연결이 가능하다.

    web server에 여러 대의 WAS를 연결하여 load balancing이 가능해지고 fail over(하나의 WAS가 고장이 나면 다른 WAS로 대체 가능, fail back(고장 난 WAS가 다시 정상동작)이 가능하다는 것이다.

    또한, 대용량 웹 애플리케이션의 경우 Web server와 WAS를 분리하여 무중단 운영을 위한 장애 극복에 쉽게 대응할 수 있다.

     

    4. 다른 종류의 WAS로 서비스가 가능해진다.

    예를 들어, 하나의 서버에서 PHP Application과 Java Application을 함께 사용할 수 있다는 것이다.

     

     

    3. Tiny Web Server 구현

    여기서는 내가 쓴 코드를 적으면서 각각이 어떻게 구현되는지를 설명하기 보다는 함수 내에서 쓰여진 새로운 함수나 매크로에 대한 설명을 해보려고 한다.

    코드는 아래 깃헙 repository에 있고 각각의 코드에 대한 설명은 주석으로 달아놓았다.

    https://github.com/JJong-Min/webproxy/tree/main/tiny

     

    GitHub - JJong-Min/webproxy: tiny 웹서버와 proxy구현 저장소입니다.

    tiny 웹서버와 proxy구현 저장소입니다. Contribute to JJong-Min/webproxy development by creating an account on GitHub.

    github.com

    TIny Web Server의 구현에 사용된 함수들은 아래와 같다.

    • I/O 함수 : 데이터를 읽고 쓰기 위한 함수로서 Linux I/O 함수를 기반으로 가공한 wrapper 함수
      • rio_readinitb : read 버퍼를 초기화 하는 함수
      • rio_readlineb : 파일에서 텍스트 라인을 읽어 버퍼에 담는 함수
      • rio_readnb : 파일에서 지정한 바이트 크기를 버퍼에 담는다.
      • rio_writen : 버퍼에서 파일로 지정한 바이트를 전송하는 함수
    • main : 웹 서버 메인 로직
      • open_listenfd : 위에서 설명
      • doit : 한 개의 HTTP 트랜잭션을 처리하는 함수
      • read_requesthdrs : request header를 읽는 함수
      • parse_uri : 클라이언트가 요청한 URI를 파싱하는 함수
      • static_serve : 정적 콘텐츠를 제공하는 함수
      • dynamic_serve : 동적 콘텐츠를 제공하는 함수
      • get_filetype : 받아야 하는 filetype을 명시하는 함수
      • client_error : 에러 처리를 위한 함수

    [오늘의 나는 어땠을까?]

    오늘은 대부분의 동료들이 추석 연휴여서 본가로 가서 강의실에 사람이 별로 없었다.

    평소와 다르게 정말 조용한 분위기가 익숙치 않았고 정말 오랜만에 누군가와 의견을 나누는 시간없이 혼자서 공부하는 시간만 가졌다.

    이렇게 하루를 보내보니 내가 좋아하는 공부방법을 알게 되었는데 개인적인 취향은 다른사람들과 얘기를 나누면서 공부하는 것이 더 좋다.

    물론, 혼자서 고민하는 시간을 충분히 가지고 나서..

     

    추석 연휴가 주말을 껴서 생각보다 길게 느껴질 것 같았는데 벌써 주말 이틀이 지났다.

    남은 날을 최대한 효율적으로 보내야 한다.

    내가 부족한 것을 채우던가 해보고 싶었던 것을 해보던가

    일단은 missing semester를 들어보고 싶어서 오늘 처음으로 들어봤는데 지금 필요하다고 느껴지거나 혼자서 강의를 들으면서 공부하기에는 효율성이 나오지 않는다는 생각에 고민이 든다.

    내일 아침에 다시 고민해봐야겠다.

    댓글

Designed by Tistory.