EgoCube.IISWebAdmin 컴포넌트 03.

등록일시: 2002-03-15 이전,  수정일시: 2018-04-07 08:48
조회수: 15,004
본문은 최초 작성 이후, 약 22년 이상 지난 문서입니다. 일부 내용은 최근의 현실과 맞지 않거나 동떨어져 있을 수 있으며 문서 내용에 오류가 존재할 수도 있습니다. 또한 본문을 작성하던 당시 필자의 의견과 현재의 의견에 많은 차이가 존재할 수도 있습니다. 이 점, 참고하시기 바랍니다.

GetLastWebServerIndex() 메서드

GetLastWebServerIndex() 메서드는 웹 서버에 존재하는 모든 가상 웹 서버들의 인덱스 중에서 가장 큰 인덱스 값을 리턴해준다. 이 메서드의 정확한 시그니처는 다음과 같다.

Public Function GetLastWebServerIndex(Optional WebServerName As String = "") As Integer

언제나처럼 WebServerName 인자는 가상 웹 서버가 설정된 웹 서버의 NetBIOS 이름으로, 이를 생략할 경우 현재 컴포넌트가 실행되고 있는 웹 서버의 NetBIOS 이름이 사용된다.

이 메서드는 가상 웹 서버들의 인덱스 중에서 가장 큰 값을 찾을 뿐, 목록 중간 중간에 있을지도 모를 빈 인덱스는 전혀 고려하지는 않는다. 가령, 어떤 IIS 관리자가 모두 다섯 개의 가상 웹 서버를 만들었고, 그 가상 웹 서버들의 인덱스가 각각 1 ~ 5까지 순차적으로 설정되었다고 가정하자. 그 후, 관리자가 어떤 이유로 세 번째 가상 웹 서버를 삭제했다면 결국 메타베이스에는 1, 2, 4, 5 이렇게 네 개의 인덱스만이 남게 될 것이다. 그러나, GetLastWebServerIndex() 메서드는 단지 가장 큰 인덱스인 5를 찾아서 리턴해줄뿐 중간에 삭제된 인덱스인 3은 전혀 고려하지 않는다.

GetWebServerBindings() 메서드

GetWebServerBindings() 메서드는 지정한 가상 웹 서버의 바인딩(Binding) 정보를 리턴한다. 이 메서드가 하는 일 자체는 매우 간단 명료하다. 말 그대로 가상 웹 서버의 바인딩 정보를 리턴해주는 것이다. 오히려 필자는 가상 웹 서버의 바인딩이라는 개념 자체가 여러분의 머리속을 혼란하게 만들 것이라고 생각한다. 이 메서드의 정확한 시그니처는 다음과 같다.

Public Function GetWebServerBindings(WebServerIndex As Integer,
                Optional WebServerName As String = "") As Variant

벌써 몇 번이나 설명한 WebServerName 인자와 WebServerIndex 인자에 대한 설명은 생략하고, 대신 가상 웹 서버의 바인딩(이하 바인딩)에 대하여 좀 더 자세히 알아보자.

여기에서 말하는 바인딩이란 한 마디로 말해서 IP 주소Port 번호, 그리고 호스트 헤더(Host Header)의 조합을 뜻한다. 그리고, 바인딩은 전체 IIS의 모든 가상 웹 서버에 대해서 유일해야만 한다. 마치 그 특성이 데이타베이스의 테이블에서 Unique 제약 조건이 걸린 다중 인덱스와도 비슷하다고 볼 수 있다. 또한, 하나의 가상 웹 서버에 동시에 여래 개의 바인딩이 걸리는 것이 가능하다. 이를 종합해 보면 다음과 같다.

  1. 바인딩은 IIS 전체에 걸쳐서 유일해야 한다.
  2. 하나의 가상 웹 서버에 여러 개의 바인딩이 걸릴 수 있다.

이 바인딩이라는 것은 글로만 설명하기엔 너무 추상적이다. 좀더 구체적인 모습을 살펴보는 것이 이해에 도움이 될 것이다.

'기본 웹 사이트 등록 정보' Dialog-Box

이 그림은 필자 PC의 기본 웹 사이트의 등록 정보 중 웹 사이트 탭의 모습이다. 상단 부근에 IP 주소TCP 포트 항목을 볼 수 있다. 자주 보던 항목이겠지만 사실 이 항목들 역시 바인딩의 구성 요소다. 그 오른쪽에 있는 고급... 버튼을 눌러보자. 그러면, 다음 그림과 같은 고급 복수 웹 사이트 구성 대화 상자가 나타난다.

'고급 복수 웹 사이트 구성' Dialog-Box

이 그림에서 이 웹 사이트의 복수 ID 영역이 바로 바인딩을 설정하는 부분이다. 아마 여러분들의 기본 웹 사이트 등록 정보에서는 TCP 포트 항목이 80인 바인딩 하나만 나타날 것이다. 그 아래의 TCP 포트 항목이 8080인 바인딩은 필자가 설명을 위해서 추가로 입력한 것이다. 이 그림의 설정을 토대로 설명하자면 다음과 같이 정리할 수 있다.

  1. 필자의 기본 웹 사이트 가상 웹 서버에는 모두 두 개의 바인딩이 설정되어 있다.
  2. 그 두 개의 바인딩은 각각 모두 할당되지 않음:80:모두 할당되지 않음:8080:이다.

잠깐 짚고 넘어가자면 아마도 인터넷 서비스 관리자를 사용해 오면서 모두 할당되지 않음이라는 조금 애매모호한 용어의 뜻을 계속 궁금하게 생각해 오신 분들도 있을 것이다. 이 용어는 '특별히 IP 주소를 지정하지는 않지만, 웹 서버에 할당된 IP 주소들 중 어느 것이라도 상관 없음' 정도로 해석할 수 있다. 이는 마이크로소프트 코리아에서 용어를 번역하면서 너무 융통성 없이 번역한 결과라고 생각한다.

하여간 이와 같은 설정으로 인하여 필자의 PC에 설정된 기본 웹 사이트는 http://localhost/로도 접속이 가능하고 http://localhost:8080/으로도 접속이 가능하다. 아마도 눈치가 빠른 분들은 이미 짐작하고 있겠지만, 바로 이 방법을 조금만 더 응용하면 지난번 글에서 설명했던 한 개의 IP 주소를 이용해서 다중 웹 사이트를 만드는 3가지 방법 중 가장 마지막 방법을 구현할 수 있다.

IP 주소가 123.123.123.123, 한 개만 할당된 가상의 웹 서버에 사용자 두 명의 웹 사이트 구축을 위한 두 개의 가상 웹 서버를 설정한다고 가정해보자. 일반적인 방법을 사용한다면 IP 주소가 한 개 밖에 없으므로 일단 IP 주소를 각각 부여해주는 방법은 불가능하다. 더군다나 실무에서 사용자마다 IP 주소를 무료, 혹은 저렴한 비용으로 할당해 주는 것은 비용 측면에서 사실상 불가능한 방법이다. 그렇다고 80번 이외의 Port 번호를 부여해주는 것은 URL의 미관상 보기가 좋지 않다.

바로 이런 경우, 바인딩을 활용하면 문제를 해결할 수 있는데, 그 구체적인 방법은 다음과 같다. 일단 IIS에 가상 웹 서버 두 개를 만들고 바인딩을 각각 '123.123.123.123:80:user1.egocube.pe.kr''123.123.123.123:80:user2.egocube.pe.kr'로 설정한다. 그리고, DNS Server에서 egocube.pe.kr 도메인에 user1과 user2의 A 레코드를 123.123.123.123으로 설정하면 깔끔하게 해결된다.

만약, 외부에서 사용자가 http://user1.egocube.pe.kr/에 접속하기 위해서 웹 브라우저에 URL을 입력하면 DNS Server는 123.123.123.123을 웹 브라우저에 리턴해준다. 그러면, 웹 브라우저는 123.123.123.123 서버에서 실행되고 있는 IIS에 접속하게 되는데, 이때 웹 브라우저는 HTTP 요청 헤더에 http://user1.egocube.pe.kr/에 접속하려는 것이라는 것을 명시한다. 따라서, IIS가 이 Header 값을 살펴보고 메타베이스를 뒤져서 일치하는 가상 웹 서버로 요청을 전환하고 결국 사용자들은 이런 제반 사정은 알지 못한채 정상적으로 사이트에 접속한다고 생각하게 되는 것이다.

다음 링크들은 이 기술에 관한 마이크로소프트의 기술 문서이다. 관심있는 분들은 참고하기 바란다.

다만 한 가지 주의할 점은 이러한 방법으로 구성된 가상 웹 서버들은 IP 주소, 그 자체를 사용해서는 접근이 불가능하다는 것이다. 이는 매우 당연한 결과로서 그런 경우에 IIS는 자신의 메타베이스에 설정된 다중 가상 웹 서버들 중에서 사용자가 원하는 가상 웹 서버가 어느 것인지 구별할 방법이 없으므로 올바른 결과를 돌려줄 수 없다.

그다지 널리 알려지지는 못했었지만 필자는 이 방법으로 1999년 말경 Windows NT 4.0 Server상에서 ASP 웹 호스팅을 구축해 본 경험이 있는데 (아마 국내 최초였던 것으로 기억되지만, 현재는 해당 서비스가 중단되었다.), 정확한 사양은 기억나지 않지만 팬티엄 3, Xeon Dual 정도의 조립 서버에서 한 개의 IP 주소로 약 500 ~ 600개 정도의 가상 웹 서버를 운영했었다.

그 당시 트래픽 자체는 많지 않았으나 여러모로 부족했던 프로그램에 비해서 그다지 눈에 띄는 서버의 성능 감소는 느끼지 못했었다. 개인적으로는 상당히 재미있는 경험이었다고 생각한다.

다음 ASP 코드에서 실제 GetWebServerBindings() 메서드의 사용법을 볼 수 있다. 비록 설명은 길었지만 사용법 자체는 매우 간단하다.

<%
  
  '******************************************************
  '*
  '* 바인딩 정보는 Variant 배열로 리턴된다.
  '*
  '******************************************************

  Dim oIISAdmin
  Dim arrBinding
  Dim i

  Set oIISAdmin = Server.CreateObject("EgoCube.IISWebAdmin")
  
  '** 기본 웹 사이트(Index 1)의 바인딩 정보를 얻는다.
  arrBinding = oIISAdmin.GetWebServerBindings(1)
  
  '** 루프를 돌면서 바인딩 정보를 출력한다.
  For i = 0 To UBound(arrBinding)
    Response.Write "<font size=2>ServerBindings " & i & " → " & arrBinding(i) & "</font><br>"
  Next
  
  Set oIISAdmin = Nothing
  
%>

이 ASP 코드는 필자의 머신에서 문자열 ':80:'':8080:'를 리턴했다. 이 결과는 현재 필자의 기본 웹 사이트 설정에 IP 주소 부분과 호스트 헤더 부분에 설정된 값이 없으므로 올바른 값이다. 위의 두 그림의 설정과 이 결과를 비교해 보기 바란다.

이 리턴값에서 볼 수 있는 것처럼 실제로 메타베이스에 설정되는 바인딩의 값은 'IP:Port:Host Header' 형식이다. 각각의 항목이 ':' (콜론)으로 구분된다는 점에 주의하기 바란다.

그리고, 마지막으로 다시 한 번 강조하지만 바인딩은 절대로 중복될 수 없다.

CreateWebServer() 메서드

이제 EgoCube.IISWebAdmin 컴포넌트의 가장 마지막 메서드이자 그 핵심인 CreateWebServer() 메서드에 관해서 알아본다. CreateWebServer() 메서드는 IIS에 새로운 가상 웹 서버를 생성하고 생성된 가상 웹 서버의 인덱스 값을 리턴해준다. 이 메서드의 정확한 시그니처는 다음과 같다.

Public Function CreateWebServer(DisplayName As String,
                FullPath As String,
                Optional IPAddress As String = "",
                Optional Port As String = "80",
                Optional HostHeader As String = "",
                Optional WebServerName As String = "") As Integer

언제나처럼 사용되는 WebServerName 인자 외에 추가로 5개의 인자가 필요하고 이 인자들은 모두 String 형식이다. DisplayName 인자는 필수 인자이며 단지 인터넷 서비스 관리자에서 표시되는 친숙한 이름으로 사용될 문자열일 뿐으로 기술적인면에서는 전혀 중요하지 않다. 그리고, FullPath 역시 필수 인자이며 새로 생성되는 가상 웹 서버의 루트가 될 폴더의 전체 경로이다. 만약, 지정한 폴더가 존재하지 않으면 새 폴더가 생성된다. 그리고, 나머지 IPAddress, Port, HostHeader 인자는 앞에서 설명한 바인딩을 결정하는 인자들이다.

새로 생성되는 가상 웹 서버의 인덱스에는 GetLastWebServerIndex() 메서드를 이용하여 얻은 존재하는 가장 큰 인덱스 값에 1을 더한 값이 설정되며, 지정한 바인딩이 이미 존재하는 바인딩 정보와 충돌하는 경우 오류를 발생시킨다. 이때 발생하는 오류는 ASP 코드상에서 Err 개체를 통해 접근이 가능하다.

그리고, 새로 생성되는 가상 웹 서버의 기본 문서는 Index.asp, Index.html, Index.htm 파일이 설명한 순서대로의 우선 순위로 설정되고 권한은 오로지 읽기 권한만 허용된다. 이러한 기본값들은 필자가 판단하기에 가장 일반적인 설정이라고 판단되어 결정한 것으로, 필요에 의하여 이러한 기본값들을 수정하고 싶다면 재량대로 수정한다고 해도 무방하다.

아마 지금까지 EgoCube.IISWebAdmin 컴포넌트에 관해 설명한 글들과 Taeyo's ASP & ASP.NET의 필자의 글들을 차분히 읽어보신 분들이라면 CreateWebServer() 메서드의 내부 코드를 이해하는 데에는 전혀 무리가 없을 것이라고 생각한다. 따라서 이에 대한 자세한 설명은 생략하기로 하고, 그대신 필자가 생각하기에 중요하다고 생각되는 몇 가지 사항에 대하여 보충 설명을 하고 넘어가기로 한다.

이 CreateWebServer() 메서드의 거의 끝 부분을 살펴보면 생성된 가상 웹 서버의 루트에서 IIsWebVirtualDir 개체의 메서드인 AppCreate() 메서드를 호출하는 부분이 있을 것이다. 이 AppCreate() 메서드는 지정한 가상 디렉터리에 웹 응용 프로그램(Web Application)을 생성하는데 여기에서 말하는 웹 응용 프로그램과 COM+ 응용 프로그램(MTS의 Package)을 혼동하지 않토록 주의하기 바란다.

이 때의 응용 프로그램이라는 용어는 ASP에서 사용하는 세션(Session) 객체의 범위가 되거나하는, 말 그대로 응용 프로그램의 경계를 의미한다. 그러나, 그보다 더욱 중요한 점은 웹 응용 프로그램 단위로 해당 프로세스가 IIS의 프로세스와 격리될지 또는 종속될지가 결정된다는 것이다.

이에 대한 더욱 자세한 내용은 이 글의 범위를 벗어나므로 여러분들이 직접 MSDN에서 'Web Application'으로 검색하여 살펴보기 바란다. 또는, IIS가 설치된 머신의 Internet Explorer에서 http://localhost/iishelp를 입력하면 나타나는 IIS x.0 설명서에서 '응용 프로그램 보호'나 '응용 프로그램 경계 정의' 등으로 직접 검색해보기 바란다. Windows 2000 제품군에서는 이 설명서가 한글로 제공되므로 많은 정보를 얻을 수 있을 것이다.

또 한 가지 주목할 만한 점은 코드상에서 중요한 변화가 있을 때마다 ADSI의 SetInfo() 메서드를 호출하고 있다는 것이다. 이는 Taeyo's ASP & ASP.NET에서 이미 몇 번이나 강조한 내용으로 Transaction이나 Lock에 해당하는 개념이 없는 디렉터리 시스템(Directory System)에서는 매우 중요한 부분이다.

다음 ASP 코드에서 실제 CreateWebServer() 메서드의 사용법을 볼 수 있다. 아마 Port 번호 8000번이 다른 가상 웹 서버에 할당되어 있지만 않다면 정상적으로 실행될 것이다.

<%
  
  '******************************************************
  '*
  '* 이름은 IISWebAdmin Test Server 이고, 루트 폴더는 
  '* C:\Test 폴더이며, 바인딩의 Port 번호는 8000 번인 새
  '* 로운 가상 웹 서버를 생성한다.
  '* 
  '* 만약, 8000 번이 이미 다른 가상 웹 서버에 할당되어져 
  '* 있다면 오류가 발생한다.
  '*
  '******************************************************

  Dim oIISAdmin

  
  Set oIISAdmin = Server.CreateObject("EgoCube.IISWebAdmin")
  
  '** IISWebAdmin Test Server 라는 새로운 이름의 가상 웹 서버를 생성한다.
  oIISAdmin = oIISAdmin.CreateWebServer("IISWebAdmin Test Server", "C:\Test Folder", , "8000")
  Response.Write "<font size=2>생성 성공.</font><br>"
  
  Set oIISAdmin = Nothing
  
%>

주의해야 할 점이 한 가지 더 있다. CreateWebServer() 메서드를 루프문을 사용해서 한 번에 많은 수의 가상 웹 서버를 만들려고 시도하지 말기 바란다. 왜냐하면 ADSI가 메타베이스에 하나의 가상 웹 서버를 설정하는 시간이 반복문이 한 번 실행되는 시간보다 훨씬 더 길기 때문에 대부분 오류가 발생할 것이기 때문이다.