설계 | 플로우차트
Last updated
Last updated
웹서버는 2~3인 협업이 필요한 프로젝트입니다. 거기다 규모도 크기 때문에, 플로우차트 없이 구현에 들어갔다간 몇 번이고 코드를 엎어야 할 거에요. 여러분의 코드가 여러분의 손을 벗어나기 전에, 처음부터 꼼꼼하게 설계를 하고 들어가야 해요.
저는 말이나 글로 플로우차트를 먼저 작성합니다. 플로우차트란 말 그대로 '코드의 흐름'을 차트로 나타내는 것인데, 차트를 작성하게 되면 한 단계 한 단계 깊이 생각해야 하기 때문에 오히려 생각의 흐름이 끊깁니다. 그래서 의식의 흐름을 따라가듯이 코드가 흘러가는 정상적인 흐름을 그대로 그려보며 글을 쓰고, 글을 바탕으로 플로우 차트를 구체화합니다. 그리고 예외처리를 보강하지요. 글로 쓰는 플로우차트는 이런 식입니다.
인자로 들어온 파일 주소가 있으면 그 주소로, 없으면 디폴트 주소로 설정 파일을 읽자. 서버들이 동작하는 인프라에 대한 정보, 서버에 대한 정보들로 설정 파일을 나누자. 서버 정보는 서버 자체에 대한 정보와 URL 패턴에 대한 처리를 담는 로케이션 정보들로 한 번 더 나누자. 이렇게 나누어진 Config 블록, Server 블록, Location 블록들에 대한 유효성 검사를 전부 진행하는 거야. 문제가 없으면 블록을 인자로 삼아 생성자들을 호출해서 객체를 만드는 거지. 그 다음에는 생성한 서버들을 순회하면서 요청들을 처리하는 거고...
...
제어 흐름이 서버들을 순회할 때, 서버를 들리면서 정확히 어떤 일들을 할까? 연결되어 있는 클라이언트들을 한 번씩 체크할 거야. 클라이언트한테 보낼 응답이 있는지부터 확인하겠지. 지난 차례에 요청을 처리했다면, 보낼 수 있는지 select 함수를 통해 확인하느라 그 차례에는 응답을 보내지 못했을 테니까 말이야. 또 소켓 버퍼에도 한계가 있으니까 응답이 큰 경우 한 번에 보낼 수도 없잖아? 그래서 이 경우데 첫 응답 전송 작업인지, 마지막 응답 전송 작업인지, 아니면 그 중간의 작업인지에 따라 하는 일이 조금씩 다를 거야.
...
만약에 보낼 응답도 없고, 실행 중인 CGI 프로그램과 읽기/쓰기할 작업도 없다면, 새로운 리퀘스트가 있는지를 확인해야 해. 먼저 시작줄이 딱 세 조각으로 스플릿되는지, 메소드나 지원하는 프로토콜 버전이 서버 차원에서 유효한지를 체크해야 해. 다음에는 URL에 일치하는 Location을 탐색하고, 해당 로케이션에서 허용되는 메소드인지 실제로 존재하는 리소스인지 등을 확인해야지. 문제가 없다? 그러면 헤더를 한 줄씩 읽으면서 유효성을 검증하고, 필요한 경우 body를 읽는 거야. body는 content-length를 이용한 방식과 chunked, 두 가지 방식으로 읽을 수 있어야겠는데...
웹서버 플로우차트는 서버의 생성과 실행에 관한 전반적인 흐름을 표현합니다. configuation file의 분할과 유효성 검사, select 함수를 중심으로 서버를 순회하는 메인 제어흐름, 커넥션을 순회하며 요청 수신, 처리, 응답 생성과 전송을 실행하는 서버 내 제어흐름이 주가 됩니다. 요청의 처리 단계에서는 메소드 별 플로우를 정리하되, URL이 디렉토리인 경우와 CGI 프로그램을 가리키는 경우까지 케어해야 합니다.
일반적인 플로우 차트와 달리 웹서버 플로우 차트에서 특히 신경써야 하는 것은 응답의 생성입니다. 요청과 응답이 1:1로 대응하는 프로그램의 특성상 정상적인 요청이든, 문제가 있는 요청이든 응답은 생성되어야 합니다. 그리고 응답의 종류는 상태 코드의 개수만큼 다양합니다. 그리고 응답에 따라 페어링되는 헤더들은 다르지요. 저는 아래와 같이 전체 플로우 차트를 작성하고, 정상/에러 응답이 발생하는 시점 곳곳에 상태 코드와 헤더들을 마킹했습니다. 참고해서 여러분만의 플로우 차트를 작성해보세요.
프로젝트 초기 학습 단계에 제작했던 이미지들로, 저희가 최종적으로 이해한 내용이나 구현한 결과물과는 차이가 있습니다. 참고만 하세요.