5.1 [ 다채로운 웹서버 ]
•
웹서버
1.
HTTP 요청을 처리하고 응답을 제공한다
2.
모든 웹서버는 리소스에 대한 HTTP요청을 받아서 콘텐츠를 클라이언트에게 돌려준다.
그럼 웹 서버 구현에 대해서 한번 살펴보자
5.1.1 [ 웹서버 구현 ]
웹 서버는 1. HTTP 및 그와 관련된 TCP 처리를 구현한 것이며 , 2. 자신이 제공하는 리소스를 관리하고 웹서버를 설정, 통제 확장하기 위한 관리기능을 제공한다.
•
웹서버는 TCP 커넥션 관리에 대한 책임을 운영체제와 나눠 가진다.
웹서버는 여러가지 형태가 가능하다
•
다목적 소프트웨어 웹 서버를 표준 컴퓨터 시스템에 설치하고 실행 할 수 있다.
•
마이크로프로세서의 기적으로, 어떤회사들은 사용자에게 판매할 전자기기 안에 몇개의 컴퓨터 칩만으로 구현된 웹서버를 내장시켜서 완전한 관리 콘솔로 제공한다.
•
운영체제의 역할
1.
컴퓨터 시스템의 하드웨어를 관리한다.
2.
TCP/IP 네트워크 지원하며 웹 리소를 유지하기 위한 파일 시스템, 현재 연산활동을 제어하기위한 프로세스 관리를 제공한다.
5.1.2 [ 다목적 소프트웨어 웹 서버 ]
다목적 소프트웨어 웹서버는 네트워크에 연결된 표준 컴퓨터 시스템에서 동작한다. 아파치나 W3C의 직소 같은 오픈소스 소프트웨어를 사용할 수 도있고, 마이크로소프트나 아이플래닛의 웹서버 같은 상용 소프트웨어를 사용할 수 도있다. 웹서버 소프트웨어는 거의 모든 컴퓨터와 운영체제에서 동작한다.
5.1.3 [ 임베디드 웹 서버 ]
임베디드 웹 서버는 일반 소비자용 제품에 내장될 목적으로 만들어진 작은 웹 서버이다.
예) 프린터, 가전제품
임베디드 웹 서버는 사용자가 그들의 일반 소비자용 기기를 간편한 웹 브라우저 인터페이스로 관리 할 수 있게 해준다.
5.2 [ 간단한 펄 웹 서버]
•
완전한 기능을 갖춘 HTTP 서버를 만들고자 한다면 50,000줄이 넘는 코드로 되어있고, 부가적인 처리 모듈들을 더 하면 훨씬 커진다.
•
HTTP/1.1의 기능들을 지원하려면, 풍부한 리소스 지원, 가상 호스팅, 접근 제어, 로깅, 설정, 모니터링, 그 외 성능을 위한 기능 필요하다
•
최소한으로 기능하는 HTTP서버라면 30줄 이하의 펄(perl)코드로 만들 수 도 있다.
•
type - o - serve 라는 작은 프로그램에 대한 코드를 확인해보자
1.
클라이언트와 프록시 간의 상호작용 테스트에 유용한 진단 툴이다.
2.
요청메시지를 받으면 화면에 메시지를 출력한다.
3.
클라이언트에게 답해줄 응답메시지를 타이핑하기를 기다린다.
4.
HTTP 요청 메시지를 정호가하게 기록하고 어떤 HTTP 응답메시지라도 돌려보내줄 수 있도록 해준다.
#!/usr/bin/perl
use Socket;
use Carp;
use FileHandle;
/* 1. 기본 포트 설정 8080 */
$port = (@ARGV ? $ ARGV[0] : 8080);
/* 2. 로컬 TCP 소켓을 생성하고 커넥션을 기다리도록 listen 설정 */
$porto = getprotobyname('tcp');
socket(S, PRF_INET, SOCK_STREAM, $proto) || die;
setsockopt(S, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die;
bind(S, sockaddr_in($port, INADDR_ANY)) || die;
listen(S, SOMAXCONN) || die;
/* 3. 시작메세지 출력 */
printf("Type - O - Server Accepting on Port", $port);
while(1){
/* 4. 커넥션을 기다린다. */
$cport_caddr = accept(C,S);
($cport, $caddr) = sockaddr_in($cport_caddr);
C->autoflush(1);
/* 5. 누구로부터의 커넥션인지 출력 */
$cname = gethostbyaddr($caddr, AF_INET);
printf("Request From", $cname);
/* 6. 빈 줄이 나올때까지 요청 메세지를 읽어서 출력 (요청메세지의 마지막은 빈 줄로 끝나기 때문.)*/
while($line = <C>){
print $line;
if($line =~ /^\r/) {last;}
}
/* 7. 응답 메세지를 위한 프롬프트를 만들고 응답줄을 입력받는다.
"." 하나만으로 되어있는 줄이 입력되기 전까지 입력된 줄을 클라이언트에게 보낸다. */
printf("Type Response Followed by '.'>>>\n");
while($line = <STDIN>){
$line =~ s/\r//;
$line =~ s/\n//;
if($line =~ /^\./) {last;}
print C $line . "\r\n";
}
close(C);
};
Java
복사
•
type-o-serve 를 이용해 어떻게 HTTP 통신을 테스트하는지 보여준다.
5.3 [ 진짜 웹 서버가 하는 일 ]
1.
커넥션을 맺는다 → 클라이언트의 접속을 받아들이거나 원치 않는 클라이언트라면 닫는다.
2.
요청을 받는다 → HTTP 요청 메시지를 네트워크로부터 읽어 들인다.
3.
요청을 처리한다 → 요청 메시지를 해석하고 행동을 취한다.
4.
리소스에 접근한다 → 메시지에서 지정한 리소스에 접근한다.
5.
응답을 만든다 → 올바른 헤더를 포함한 HTTP 응답 메시지를 생성한다.
6.
응답을 보낸다 → 응답을 클라이언트에게 돌려준다.
7.
트랜잭션을 로그로 남긴다 → 로그파일에 트랜잭션 완료에 대한 기록을 남긴다.
위 7가지의 작용이 어떻게 흐르는지 아래 사진과 같이보자
5.4 [ 단계 1 : 클라이언트 커넥션 수락 ]
•
클라이언트가 이미 서버에 대해 열려 있는 지속적 커넥션을 갖고있다면, 클라이언트는 요청을 보내기 위해 그 커넥션을 사용할 수 있다.
•
그렇지 않다면 클라이언트는 서버에 대한 새 커넥션을 열 필요가 있다.
5.4.1 [ 새 커녁션 다루기 ]
1.
클라이언트가 웹 서버에 TCP 커넥션 요청을 한다
2.
웹 서버는 그 커넥션을 맺고 TCP 커넥션에서 IP주소를 추출하여 커넥션 맞은편에 어떤 클라이언트가 있는지 확인한다.
3.
새 커넥션이 받아들여지면 서버는 새 커넥션을 커넥션 목록에 추가하고 커넥션에서 오가는 데이터를 지켜보기 위한 준비한다.
웹 서버는 어떤 커넥션이든 마음대로 거절하거나 즉시 닫을 수 있다.
클라이언트의 IP주소나 호스트 명이 인가되지 않았거나 악의적이라고 알려진것인 경우 커넥션을 닫는다.
5.4.2 [ 클라이언트 호스트 명 식별 ]
•
웹 서버는 ‘역방향 DNS (reserve DNS)’를 사용해서 클라이언트의 IP 주소를 클라이언트의 호스트명으로 변환하도록 설정되어 있다.
•
웹서버는 클라이언트 호스트 명을 구체적인 접근 제어와 로깅을 위해 사용할 수 있다.
•
호스트 명 룩업 은 꽤 시간이 많이 걸릴 수 있어 웹 트랜잭션을 느려지게 할 수있음 주의하자!
•
많은 대용량 웹서버는 호스트명 분석을 꺼두거나 특정 콘텐츠에 대해서만 켜놓는다.
•
아파치에서는 HostnameLookups 설정 지시자로 호스트 명 룩업을 켤 수 있다.
HostnameLookups off
<Files ~"\.(html|htm|cgi$">
HostnameLookups on
</Files>
Java
복사
5.4.3 [ ident를 통해 클라이언트 사용자 알아내기 ]
1. ident 프로토콜이란 ?
서버에서 어떤 사용자 이름이 HTTP 커넥션을 초기화했는지 찾아낼 수 있게 해주는 프로토콜이다, 웹 서버 로깅에서 유용하기 떄문에, 널리 쓰이는 일반 로그 포맷의 두 번째 필드는 각 HTTP요청의 ident 사용자 이름을 담고 있다.
ident는 조직 내부에서는 잘 사용할 수 있지만, 콩콩 인터넷에서는 다음을 포함한 여러이유로 잘 동작하지 않는다.
•
많은 클라이언트 PC는 identd 신원확인 프로토콜 데몬 소프트웨어를 실행하지 않는다.
•
ident 프로토콜은 HTTP 트랜잭 션을 유의미하게 지연시킨다..
•
방화벽이 ident 트래픽이 들어오는 것을 막는경우가 많다.
•
ident 프로토콜은 안전하지 않고 조작하기 쉽다.
•
idem 프로토콜은 가상 IP 주소를 잘 지원하지 않는다.
•
클라이언트 사용자 이름의 노출로 인한 프라이버시 침해의 우려가 있다.
아파치 웹 서버의 경우 IdentityCheck 지시어를 이용해 ident룩업을 사용하게 할 수 있다. 만약가능한 ident 정보가 없다면, 아파치는 ident 로그 필드를 하이폰(-)으로 채울 것이다, 보통 ident정보가 없기 때문에 일반 로그 포맷 로그파일의 두 번 째 필드는 하이픈올 채워진다.
5.5 [ 단계 2 : 요청 메시지 수신 ]
커넥션에 데이터가 도착하면, 웹 서버는 네트워크 커넥션에서 그 데이터를 읽어 들 이고 파싱하여 요청 메시지를 구성한다.
요청 메시지를 파싱할 때, 웹 서버는 다음과 같은 일을 한다.
•
요청줄을 파싱하여 요청 메서드, 지정된 리소스의 식별자<URI), 버전 번호5를 찾 는다. 각 값은 스페이스 한 개로 분리되어 있으며, 요청줄은 캐리지 리턴 줄바꿈 (CRLF)문자열6로 끝난다.
•
메시지 헤더들을 읽는다. 각 메시지 헤더는 CRLF로 끝난다.
•
헤더의 끝을 의미하는 CRLF로 끝나는 빈 줄을 찾아낸다. (존재한다면)
•
요청 본문이 있다면, 읽어 들인다(길이는 Content-Length 헤더로 정의된다).
요청 메시지를 파싱할 때, 웹 서버는 입력 데이터를 네트워크로부터 불규칙적으로 받는다. 네트워크 커넥션은 언제라도 무효화될 수 있다. 웹 서버는 파싱해서 이해 하는 것이 가능한 수준의 분량을 확보할 때까지 데이터를 네트워크로부터 읽어서 메시지 일부분을 메모리에 임시로 저장해 둘 필요가 있다.
5.5.1 [ 메시지의 내부 표현 ]
5.5.2 [ 커넥션 입력/출력 처리 아키텍쳐 ]
고성능 웹 서버는 수천 개의 커넥션을 동시에 열 수 있도록 지원한다. 이 커넥션들 은 웹 서버가 전 세계의 클라이언트들과 각각 한 개 이상의 커넥션을 통해 통신할 수 있게 해준다. 어떤 커넥션들로부터는 요청이 느리게 혹은 드물게 흘러 들어오 고, 또 어떤 것들은 나중에 일어날 활동을 위해 조용히 대기하고 있는데 비해, 일부 커넥션들은 웹 서버로 급속히 요청을 보내고 있을 것이다.
웹 서버들은 항상 새 요청을 주시하고 있다. 왜냐하면 요청은 언제라도 도착할 수 있기 때문이다. 아래 그림에 그려진것 과 같이 , 웹 서버 아키텍쳐의 차이에 따라 요청을 처리하는 방식도 달라진다.
a.
단일-스레드 I/O 아키텍처
•
한 번에 하나씩 요청을 처리트랙잭션이 완료되면 다음 커넥션 처리구현하기 간단하지만 처리 도중에 모든 다른 커넥션이 무시되고, 이것은 심각한 성능 문제를 만들어내므로 오직 로드가 적은 서버나type - o -server와 같은 진단도구에서만 적당하다.
b.
멀티스레드 I/O 아케틱처
•
여러 요청을 동시에 처리하기 위해 여러 개의 프로세스 혹은 고효율 스레드를 할당한다.
•
스레드 / 프로세스는 필요할 때마다 만들어질 수도 있고 미리 만들어질 수 있다.
•
몇몇 서버는 매 커넥션마다 스레드 / 프로세스 하나를 할당하지만, 서버가 수천 개의 동시 커넥션을 처리할 때그로 인해 만들어진 수많은 프로세스나 스레드는 많은 메모리나 시스템 리소스를 소비 하므로 최대 개수를 제한을 건다.
c.
다중 I/O 아키텍처
•
대량의 커넥션을 지원하기 위해, 많은 웹 서버는 다중 아키텍처를 채택모든 커넥션은 동시에 그 활동을 감시당한다.
•
커넥션 상태가 바뀌면, 그 커넥션에 대한 작은 양의 처리가 수행된다.
•
처리가 완료되면, 커넥션은 다음번 상태 변경을 위해 열린 커넥션 목록으로 돌아간다.
•
커넥션에 대한 작업을 수행하는 것은 그 커넥션에 해야 할 일이 있을 때 뿐이다.
•
스레드와 프로세스는 유휴 상태의 커넥션에 매여 기다리느라 리소스를 낭비하지 않는다.
d.
다중, 멀티스레드 I/O 아키텍처
•
CPU 여러개의 이점을 살리기 위해 멀티스레딩과 다중화를 결합여러개의 스레드(보통 하나의 물리적 프로세스)는 각각 열려있는 커넥션(혹은 열려있는 커넥션의 부분 집합)을 감시하고 각 커넥션에 대해 조금씩 작업을 수행한다.
5.6 [ 단계 3 : 요청 처리 ]
• 서버가 요청을 받으면, 서버는 요청으로부터 메서드, 리소스, 헤더, 본문(없는 경우도 있다)을 얻어내어 처리
• POST를 비롯한 몇몇 메서드는 요청 메시지에 엔터티 본문이 있을 것을 요구하고그 외 OPTIONS를 비롯한 다수의 메서드는 요청에 본문이 있는 것을 허용하되 요구하진 않는다.많지는 않지만 GET과 같이 요청 메시지에 엔터티 본문이 있는 것을 금지하는 메서드도 있다 .
5.7 [ 단계 4 : 리소스의 매핑과 접근 ]
웹 서버는 리소스 서버다. 그들은 HTML 페이지나 JPEG 이미지 같은 미리 만들어 진 콘텐츠를 제공하며, 마찬가지로 서버 위에서 동작하는 리소스 생성 애플리케이 션을 통해 만들어진 동적 콘텐츠도 제공한다.
웹 서버가 클라이언트에 콘텐츠를 전달하려면, 그전에 요청 메시지의 URI에 대 응하는 알맞은 콘텐츠나 콘텐츠 생성기를 웹 서버에서 찾아서 그 콘텐츠의 원천을 식별해야 한다.
5.7.1 [ Docroot ]
웹 서버는 여러 종류의 리소스 매핑을 지원한다. 하지만 리소스 매핑의 가장 단순 한 형태는 요청 URI를 웹 서버의 파일 시스템 안에 있는 파일 이름으로 사용하는 것이다. 일반적으로 웹 서버 파일 시스템의 특별한 폴더를 웹 콘텐츠를 위해 예약 해 둔다. 이 폴더는 문서 루트 혹은 docroot로 불린다. 웹 서버는 요청 메시지에서 URI를 가져와서 문서 루트 뒤에 붙인다.그림 5-8에서, /specials/saw-blade.gif에 대한 요청이 도착했다. 이 예에서 웹 서 버는 문서 루트 /usr/local/httpd/files를 갖고 있다. 웹 서버는 /usr/local/httpd/files/ specials/saw-blade.gif 파일을 반환한다.
다음과 같이 httpd.conf 설정 파일에 DocumentRoot 줄을 주가하여 아파치 웹 서버 의 문서 루트를 설정할 수 있다.
DocumentRoot /usr/local/httpd/files
Plain Text
복사
서버는 상대적인 url이 docroot를 벗어나서 파일 시스템의 docroot 이외 부분이 노 출되는 일이 생기지 않도록 주의해야 한다. 예를 들어 대부분의 성숙한 웹 서버는 Joe’s Hardware의 문서 루트 위의 파일을 보려고 하는 이와 같은 URI를 허용하지않는다.
http://www.j oes-hardware.com/.•/
Plain Text
복사
가상 호스팅된 docroot
가상 호스팅 웹 서버는, 각 사이트에 그들만의 분리된 문서 루트를 주는 방법으로 한 웹 서버 에서 여러 개의 웹 사이트를 호스팅 한다. 가상 호스팅 웹 서버는 URI나 Host 헤더에서 얻은 IP 주소나 호스트 명을 이용해 올바른 문서 루트를 식별한다. 이 방법으로, 하나의 웹 서버 위에서 두 개의 사이트가 완전히 분리된 콘텐츠를 갖 고 호스팅 되도록 할 수 있다.
서버는 두 사이트 www.joes-hardware.com와 www.marys- antiques.com을 호스팅 한다. 서버는 두 웹 사이트를 HTTP Host 헤더나 서로 다른 IP 주소를 이용해 구분할 수 있다.• 요청 A가 도착했을 때, 서버는 /docs/joe/index.html 파일을 가져온다.• 요청 B가 도착했을 때, 서버는 /docs/mary/index.html 파일을 가져온다.
•
가상으로 호스팅 되는 docroot 설정은 대부분의 웹 서버 에서 간단하다. 널리 쓰이 는 아파치 웹 서버에서는, 각 가상 웹 사이트의 VirtualHost 블록이 가상 서버에 대 한 DocumentRoot 지시자를 포함하도록 설정해야 한다
5.7.3 [ 동적 콘텐츠 리소스 매핑]
웹서버는URI를동적 리소스에매핑할수도있다.즉,요청에맞게콘텐츠를생성 하는 프로그램에 URI를 매핑하는 것이다(그림 5-11). 사실, 웹 서버들 중에서 애플 리케이션 서버라고 불리는 것들은 웹 서버를 복잡한 백엔드 애플리케이션과 연결 하는 일을 한다. 어떤 리소스가 동적 리소스라면, 애플리케이션 서버는 그에 대한 동적 콘텐츠 생성 프로그램이 어디에 있는지, 그리고 어떻게 그 프로그램을 실행하 는지 알려줄 수 있어야 한다. 대부분의 웹 서버는 동적 리소스를 식별하고 매핑할수 있는 기본적인 메커니즘을 갖고 있다.
5.8 [ 단계 5:응답 만들기 ]
한번 서버가 리소스를 식별하면, 서버는 요청 메서드로 서술되는 동작을 수행한 뒤 응답 메시지를 반환한다. 응답 메시지는 응답 상태 코드, 응답 헤더, 그리고 응답 본 문(생성되었다면)을 포함한다. HTTP 응답 코드에 대해서는 3장의 “상태 코드”에 자세하게 나와 있다.
5.8.1 [ 응답 엔터티 ]
만약 트랜잭션이 응답 본문을 생성한다면, 그 내용을 응답 메시지와 함께 돌려보낸 다. 만약 본문이 있다면, 응답 메시지는 주로 다음을 포함한다.• 응답 본문의 MIME 타입을 서술하는 Content-Type 헤더• 응답 본문의 길이를 서술하는 Content-Length 헤더 • 실제응답본문의내용
5.8.2 MIME 타입 결정하기
웹 서버에게는 응답 본문의 MIME 타입을 결정해야 하는 책임이 있다. 다음은 MIME 타입과 리소스를 연결하는 여러 가지 방법이다.mime.types웹 서버는 MIME 타입을 나타내기 위해 파일 이름의 확장자를 사용할 수 있다. 웹 서버는 각 리소스의 MIME 타입을 계산하기 위해 확장자별 MIME 타입이 담겨 있 는파일을탐색한다. 이러한확장자기반타입 연계가가장흔한방법이다. 이는그림 5-12에 묘사되어 있다.
5.8.3 [ 리다이렉션 ]
웹 서버는 종종 성공 메시지 대신 리다이렉션 응답을 반환한다. 웹 서버는 요청을 수행하기 위해 브라우저가 다른 곳으로 가도록 리다이렉트 할 수 있다. 리다이렉션 응답은 3XX 상태 코드로 지칭 된다. Location 응답 헤더는 콘텐츠의 새로운 혹은 선 호하는 위치 에 대한 URI를 포함한다. 리다이 렉트는 다음의 경우에 유용하다.
영구히 리소스가 옮겨진 경우
리소스는 새 URL이 부여되어 새로운 위치로 옮겨졌거나 이름이 바뀌었을 수 있다.웹 서버는 클라이언트에게 리소스의 이름이 바뀌었으므로, 클라이언트는 북마크를 갱신하거나 할 수 있다고 말해줄 수 있다. 301 Moved Permanently 상태 코드는 이 런 종류의 리다이 렉트를 위해 사용된다.
임시로 리소스가 옮겨진 경우
만약 리소스가 임시로 옮겨지거나 이름이 변경 된 경우, 서버는 클라이언트를 새 위 치로 리다이렉트하길 원할 것이다. 그러나 이름 변경이 임시적이기 때문에, 서버는 클라이언트가 나중에는 원래 URL로 찾아오고 북마크도 갱신하지 않기를 원한다. 303 See Other와 307 Temporary Redirect 상태 코드는 이 런 종류의 리다이 렉트를 위해 사용된다.
그 외에도
•
URL 증강
•
부하 균형
•
친밀한 다른 서버가 있을 때
•
디렉터리 이름 정규화
5.9 [ 단계 6:응답 보내기 ]
웹 서버는 받을 때와 마찬가지로 커넥션 너머로 데이터를 보낼 때도 비슷한 이슈에직면한다. 서버는 여러 클라이언트에 대한 많은 커넥션을 가질 수 있다. 그들 중 일부는 아무것도 안하고 있는 상태이괴 일부는 서버로 데이터를 보내고 있으며, 또다른 일부는 클라이언트로 돌려줄 응답 데이터를 실어 나르고 있을 것이다.서버는 커넥션 상태를 추적해야 하며 지속적인 커넥션은 특별히 주의해서 다룰 필요가 있다. 비지속적인 커넥션이라면, 서버는 모든 메시지를 전송했을 때 자신쪽의 커넥션을 닫을 것이다.지속적인 커넥션이라면, 서버가 Content-Length 헤더를 바르게 계산하기 위해특별한 주의를 필요로 하는 경우나, 클라이언트가 응답이 언제 끝나는지 알 수 없 는 경우(4장을 보라)에, 커넥션은 열린 상태를 유지할 것이다.
5. 10 [ 단계 7:로깅]
마지막으로, 트랜잭션이 완료되었을 때 웹 서버는 트랜잭션이 어떻게 수행되었는 지에 대한 로그를 로그파일에 기록한다. 대부분의 웹 서버는 로깅에 대한 여러 가 지 설정 양식을 제공한다. 더 자세한 것은 21장을 보라.