전문가칼럼

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

COM+ 컴포넌트

전문가칼럼
DBMS별 분류
Etc
작성자
dataonair
작성일
2002-03-01 00:00
조회
12416





COM+ 컴포넌트

유경상 ksyu@tysystems.com


이번 컬럼은 지난 회에서 약속했듯이 원격 컴퓨터 에 존재하는 COM+ 컴포넌트를 액세스하는 방법에 대해 이야기하 고자 한다.

VB 6.0이나 VC++로 COM+ 컴포넌트를 작성했을 때 는 DCOM을 통해 원격 COM+ 컴포넌트를 액세스할 수 있었다.

게다가 구성 요소 관리자는 클라이 언트에서 COM+ 컴포넌트를 액 세스할 수 있도록‘내보내기’기능 까지 제공했다.

이제는 상황이 달라졌다. CO M+의 내보내기 기능은 COM의 타입 라이브러리에 의존한 것이므 로 더 이상 닷넷 환경에서 사용할 수 없다. 즉, DCOM을 통해 원격 COM+ 컴포넌트를 액세스하지 않는다는 말이다. 어떻게 바뀔까 닷넷은 원격 객체를 액세스하기 위 한 닷넷 리모팅(.NET Remoting) 을 제공한다.

그리고 이 닷넷 리모 팅은 COM+ 컴포넌트에도 동일 하게 적용된다. 이번회에서는 닷넷 리모팅에 대한 사항과 이것을 COM+ 컴포넌트에 어떻게 적용 할 수 있는지 살펴보도록 하자.

컬럼을 읽고 나면 닷넷 리모팅 과 COM+의 관계를 명확하게 파 악할 수 있을 것이며 닷넷 리모팅 이 기업용 애플리케이션의 아키텍 처를 어떻게 유연하게 해주는가를 이해할 수 있을 것이다. 독자들이 컬럼의 내용을 즐기기 바라며 이 제 여러분을 리모팅의 세계에 초대한다.


닷넷 프레임워크 정식 버전 출시

드디어‘닷넷 프레임워크’와‘비주얼 스튜디오 닷넷(이하 VS. NET)’의 정식 버전이 나왔다. 나왔다는 소식을 접하기가 무섭게 MSDN에 달려가 영문판을 다운로드했다. 압축된 파일 크기가 1.8GB이며, 압축을 풀면 CD 5장 분량인 2.5GB에 달하는 무시무시 ()한 녀석이었다.

필자 사정상 아직 많이 사용해 보지는 못했지만 예전의 버그들이 많이 수정됐고 프레임워크 클래스의 API에 약간 변화가 있는 듯 하 다. 베타 2에서 변화된 API 목록은 VS.NET의 설치 디렉터리 내의 FrameworkSDK\Docs 폴더에 존재하는 APIChangesBeta2to RTM.htm 파일로부터 알 수 있다. 실제 변화된 내용은 기존 베타 2 의 코드 수정을 요구하기도 하는데 그다지 큰 변화는 아닌 듯 하다. 닷넷 리모팅에 대한 내용을 다루기 전에 VS.NET 정식 버전에 대해 서 몇 가지만 살펴보자.

베타 2와 정식 버전의 차이점을 여기서 다 설명할 수 없으므로 지 난 컬럼과 관련된 한 가지 변화된 점을 소개하고자 한다. 지난 컬럼 에서 필자는 서버 타입의 COM+ 애플리케이션의 경우, 컴포넌트 DLL을 GAC(Global Assembly Cache)에 등록해야 한다고 했다. 이 등록 과정은 DLL을 컴파일할 때마다 매번 수행돼야 했다. 이 작 업은 개발 과정상 매우 불편함에 틀림없다. 그런데 정식 버전에서는 더 이상 GAC에 등록할 필요가 없어졌다.

COM+ 컴포넌트를 담는 어셈블리(DLL)가 등록될 필요가 없는 이유를 살펴보자. DLL이 COM+ 내에서 작동되기 위해서는 COM+ 카탈로그에 등록돼야 하고 이를 위해 regsvcs 유틸리티 혹 은 자동 등록 과정을 거치면 된다. 이렇게 COM+ 카탈로그에 등록 된 컴포넌트는 COM+의 입장에서 볼 때 닷넷 이전의 VB나 VC++로 작성된 COM 컴포넌트와 다를 바 없다. 즉, 닷넷의 Servi cedComponent 클래스로 작성된 COM+ 컴포넌트 역시 COM 컴 포넌트처럼 여겨지며, 이것이 의미하는 바는 곧 레지스트리에 COM 과 관련된 CLSID가 생성된다는 말이다.

이렇게 생성된 레지스트리 항목은 <화면 1>과 같다. VB 6.0으로 작성한 컴포넌트와 비슷하지만 추가적인 정보가 포함돼 있는 것을 알 수 있다. COM에 대한 지식을 갖고 있는 독자라면 InprocSer ver32 항목의 값을 의아해 할 것이다. 이 항목의 값은 COM 컴포넌 트를 담고 있는 DLL 파일의 경로가 명시되는 것이 일반적이다. 하 지만 <화면 1>은 엉뚱하게도 mscoree.dll에 대한 경로가 명시돼 있 다. mscoree.dll은 닷넷 런타임 엔진(runtime execution engine)으 로서 CLR 정도로 생각할 수 있는 DLL이다. 왜 컴포넌트를 담는 DLL이 아니라 엔진이 InprocServer32에 명시돼 있을까

이유는 이렇다. 닷넷 이전 환경에서는 별다른 런타임 환경이 없었 고 다만 프로그래밍 언어에 따르는 엔진 정도가 있었을 뿐이다. VB 6.0을 생각해 보면 VB 코드가 수행됨에 따라 엔진을 불러왔다. 하지 만 닷넷 환경에서는 코드가 즉시 수행 가능한 형태가 아니다. 즉, 엔 진이 MSIL 코드를 JIT 컴파일(Just-In-Time Compile)을 수행한 이후에야 수행 가능한 형태가 된다. 이 말은 엔진이 먼저 로드돼야 한다는 말과 상통한다. 때문에 mscoree.dll이 먼저 로드된 다음에 우 리의 컴포넌트가 mscoree.dll에 의해 로드된다.

mscoree.dll는 로드할 어셈블리(DLL)를 어떻게 찾을까 <화면 1> 을 살펴보면 컴포넌트를 구현하고 있는 어셈블리에 대한 정보를 볼 수 있다. 컴포넌트의 버전, 강력한 이름(strong name)과 관련된 public key token은 물론 어셈블리의 위치 정보가 기록돼 있다. mscoree.dll은 이 정보를 통해 DLL을 로드한다.

베타 2에서도 이 정보들이 동일하게 레지스트리에 기록됐었으나 mscoree.dll의 버그 때문인지 CodeBase 키로부터 어셈블리를 로드 하지 못했다. 그래서 GAC에서 어셈블리를 로드하려고 시도했던 것 이다. 정식 버전은 Codebase 키에 기록된 DLL 위치 정보를 이용해 어셈블리를 제대로 로드해준다. 따라서 앞서 말한 대로 컴포넌트 DLL은 GAC에 등록될 필요가 없다. 물론, 필요하다면 등록해도 되 지만 개발 기간만큼은 등록하지 않는 것이 좋다. 컴파일할 때마다 GAC를 갱신해야 하기 때문이다.

3-2.jpg

이후에야 수행 가능한 형태가 된다. 이 말은 엔진이 먼저 로드돼야 한다는 말과 상통한다. 때문에 mscoree.dll이 먼저 로드된 다음에 우 리의 컴포넌트가 mscoree.dll에 의해 로드된다. mscoree.dll는 로드할 어셈블리(DLL)를 어떻게 찾을까 <화면 1> 을 살펴보면 컴포넌트를 구현하고 있는 어셈블리에 대한 정보를 볼 수 있다. 컴포넌트의 버전, 강력한 이름(strong name)과 관련된 public key token은 물론 어셈블리의 위치 정보가 기록돼 있다. mscoree.dll은 이 정보를 통해 DLL을 로드한다. 베타 2에서도 이 정보들이 동일하게 레지스트리에 기록됐었으나 mscoree.dll의 버그 때문인지 CodeBase 키로부터 어셈블리를 로드 하지 못했다. 그래서 GAC에서 어셈블리를 로드하려고 시도했던 것 이다. 정식 버전은 Codebase 키에 기록된 DLL 위치 정보를 이용해 어셈블리를 제대로 로드해준다. 따라서 앞서 말한 대로 컴포넌트 DLL은 GAC에 등록될 필요가 없다. 물론, 필요하다면 등록해도 되 지만 개발 기간만큼은 등록하지 않는 것이 좋다. 컴파일할 때마다 GAC를 갱신해야 하기 때문이다.


닷넷 리모팅

닷넷 리모팅에 대한 내용은 필자가 기고한 본지의‘실전! 강의실’에 서도 소개된 바가 있다. 따라서 이 글에서는 리모팅의 도입에 관해서 만 간략히 설명할 것이다. 좀더 자세한 내용이 필요하다면 앞서 말한 본지 2001년 7월호 실전! 강의실‘웹 서비스와 리모팅에서 SOAP 활용’을 참조하거나 MSDN을 참조하기 바란다.


애플리케이션 도메인

닷넷 리모팅은 원격지에 존재하는 닷넷 객체를 액세스하는 메커니즘 을 말한다. 이 때‘원격’은 클라이언트 애플리케이션 도메인(Appli cation Domain)이 아닌 다른 애플리케이션 도메인을 말한다. 애플 리케이션 도메인은 닷넷 애플리케이션이 수행되는 추상적인 공간을 의미한다. 이것은 고유의 메모리, 스택, 시스템 자원 등의 수행환경 을 가지며 다른 애플리케이션 도메인과 분리되고 보호된다. 즉, 다른 애플리케이션 도메인의 객체나 코드를 접근할 수 없다. 운영체제의 프로세스 개념과 비슷하지만 그보다 작으며 추상적인 개념이다. 하 나의 프로세스는 여러 애플리케이션 도메인을 포함할 수 있으며 프 로세스를 공유하는 애플리케이션 도메인은 서로 독립적이다.

3.3.jpg

닷넷 리모팅은 원격 애플리케이션 도메인의 닷넷 객체를 액세스하 는 메커니즘이다. 원격 애플리케이션 도메인은 클라이언트 애플리케 이션 도메인과 같은 프로세스에 존재할 수도 있고 다른 프로세스에 존재할 수도 있다. 혹은 원격 애플리케이션 도메인이 다른 컴퓨터에 존재할 수도 있다. <그림 1>은 애플리케이션 도메인과 리모팅의 관계 를 잘 보여준다.


마샬링(Marshaling)

마샬링은 원격 프로시저 호출(RPC, Remote Procedure Call)에서 등장하는 개념이다. 동일 애플리케이션 도메인에 존재하는 객체의 메쏘드를 호출할 때는 매개변수나 결과값은 스택을 통해 전달된다. 반면, 원격 애플리케이션 도메인에 존재하는 객체의 메쏘드를 호출 할 때는 더 이상 스택을 사용할 수 없다. 두 애플리케이션 도메인은 서로 다른 스택을 사용하기 때문이다. 원격 객체의 메쏘드를 호출하 기 위해 호출에 사용되는 매개변수는 바이트 스트림(메모리 버퍼)에 기록되고 기록된 데이터가 네트워크나 기타 방법을 통해 전송되는 것이다. 이렇게 매개변수, 결과 값을 바이트 스트림으로 변환하는 것 을 마샬링(marshaling)이라 하며, 바이트 스트림으로부터 매개변수 등을 추출하는 것은 언마샬링(unmarshaling)이라 한다(마샬링이란 용어는 책에 따라서‘정렬’이라는 표현을 쓰기도 하는데, 필자는 언 마샬링에 대한 적절한 용어를 찾을 수 없어서 한글 용어를 사용하지 않았다).

정수나 실수, 혹은 문자열과 같은 기본 데이터 타입을 마샬링하는 것은 간단하다. 이들의 값을 데이터로 바꾸면 되기 때문이다. 하지만 개발자가 생성한 사용자 클래스의 객체를 마샬링하려면 어떻게 해야 할까 닷넷의 클래스는 마샬링 관점에서 세 종류로 나눌 수 있다. 첫 번째는 객체의 메모리 내용을 그대로 복사하는 값에 의한 마샬링 (Marshal By Value; MBV)으로서 정수나 문자열과 같은 기본 데이 터 타입이 이 카테고리에 속한다. MBV 객체가 마샬링되면 목적지 에는 객체의 복사본이 생성되고 클라이언트는 이 복사본을 액세스하 게 된다. 이것은 값에 의한 호출(Call By Value)에서의 개념과 매우 흡사하다. 두 번째는 참조에 의한 마샬링(Marshal By Reference;

3.4.jpg

MBR)으로서 객체의 참조(Object Reference)가 생성되고 이것이 데 이터 스트림에 기록되는 것을 말한다. MBR 객체가 마샬링되면 클라 이언트는 원본 객체를 액세스하게 되며, 이 때 리모팅이 사용된다. 마 지막으로 마샬링될 수 없는 객체가 있는데, 이것을 ContextBound 객체라 부르며 리모팅에서는 사용할 수 없다. <그림 2>는 MBV와 MBR의 상황을 보여준다.

구체적인 예를 들어보자. 다음처럼 Test 클래스가 있을 때 이 클래 스를 원격 클라이언트가 액세스하고자 한다. 만일 이 클래스의 인스 턴스가 MBV로 마샬링돼 클라이언트로 넘어가고 Output() 메쏘드 가 호출되면“Can you see it”이라는 메시지가 클라이언트의 콘솔 화면에 나타날 것이다. 반면 이 클래스가 MBR로 마샬링돼 클라이 언트로 넘어가고 Output() 메쏘드가 호출되면 메시지는 서버의 화 면에서 나타나게 될 것이다.

class Test {
public void Output()
{
Console.WriteLine(“Can you see it ”);
}
}

요약하면 닷넷 리모팅은 MBR 객체를 클라이언트에서 액세스하 는 것을 정의한다. MBR에 의해 객체가 마샬링되도록 하기 위해서 클래스는 MarshalByRefObject 클래스에서 파생돼야 한다. 객체가 전혀 마샬링되지 않도록 하기 위해서 클래스는 ContextBound Object 클래스에서 파생돼야 한다. 그리고 위 두 가지 경우에 포함되 지 않는 객체들은 모두 MBV로 마샬링된다.


포메터와 채널

포매터(formatter)는 마샬링의 결과로 생성되는 데이터에 대한 구체 적인 포맷을 제공한다. 리모팅은 SOAP 포매터와 Binary 포매터를 제공한다. SOAP 포매터는 XML 기반의 SOAP를 사용해 호출할 메 쏘드, 매개변수 등을 표현하고 Binary는 닷넷에서 사용하는 고유의 바이너리 포맷을 말한다. 애플리케이션은 SOAP 포매터 혹은 Binary 포매터 중 하나를 선택할 수 있으며 두 포매터는 고유의 장 단점을 갖고 있다. SOAP 포매터는 XML 기반이므로 상호운용성(interoperability)이 높아 원격 객체가 인터넷을 통해 연결돼 있을 때 적합하지만 Binary 포매터에 비해 느린 점이 흠이다. 반면 Binary 포매터는 SOAP 포매터에 비해 빠르지만 인트라넷 상의 원 격 객체를 액세스하는 데 적합하다. <그림 3>은 SOAP 포매터가 적 용된 원격 객체 액세스의 예를 보여준다.

채널은 포매팅된 메시지, 즉 호출 정보를 담는 메시지가 원격 객체 로 전달되는 네트워크 프로토콜을 의미한다. 리모팅은 HTTP 채널 과 TCP 채널을 제공한다. HTTP 채널은 메시지 전송을 HTTP 프로 토콜을 통해 수행하며 TCP 채널은 저수준의 TCP/IP를 그대로 사용 한다. HTTP 채널은 TCP/IP 기반에 부가적인 메시지를 추가한 프 로토콜이므로 TCP 채널에 비해 빠르지 못하지만 인터넷에서 잘 작 동하며 SSL과 같이 지금까지 많이 사용되어 온 HTTP 응용을 모두 사용할 수 있다. TCP 채널은 빠르지만 인트라넷에서 사용하는 것이 더 선호되는 채널이다.

요약하면 인트라넷 상에 존재하는 원격 객체를 액세스할 때는 TCP 채널과 Binary 포매터를 사용하는 것이 좋으며 인터넷으로 연 결된 원격 객체는 HTTP 채널과 SOAP 포매터를 사용하는 것이 상 대적으로 유리하다고 할 수 있겠다. 이러한 것을 반영해서인지 포매 터를 개발자가 명시하지 않을 경우, TCP 채널이 사용되면 Binary 포매터가 디폴트로 선택되며, HTTP 채널이 사용되면 SOAP 포매 터가 디폴트로 선택된다.


원격 객체 활성화

원격 객체가 생성돼 원격 호출을 받을 준비가 된 상태를 그 객체가 활성화(activate)됐다고 한다. 리모팅은 활성화와 관련된 세 가지 모 드를 갖고 있다. 첫 번째가 SingleCall 모드로서 이 모드의 원격 객체 는 매 원격 호출마다 새로운 객체가 생성되고 이 객체가 서비스를 수 행한다. 지난 컬럼에서 설명한 COM+의 적시 활성화(Just-In- Time Activation)와 비슷하다. 하지만 COM+의 적시 활성화는 컴 포넌트가 SetComplete 혹은 SetAbort를 호출해야만 비활성화 (deactivate)됐다. 반면 리모팅의 SingleCall 모드는 객체의 의사와 관계없이 항상 원격 호출이 종료되면 그 객체는 GC(garbage collection)의 대상이 됨에 유의하자.

3.5.jpg

두 번째 모드는 Singleton 모드이다. 이름이 내포하듯이 이 모드의 객체는 오직 하나의 객체가 생성되고 이 객체가 모든 클라이언트 호 출을 처리한다. 두 개 이상의 클라이언트가 동시에 Singlecall 모드의 객체를 호출하면 쓰레드 풀에 의해 두 개 이상의 쓰레드가 객체를 액 세스하므로 Singlecall 모드의 객체는 스스로 동기화에 신경을 써야 한다. 즉, Singlecall 모드의 객체는 스스로 동기화를 수행하지 않으 면 안됨에 유의해야 한다. 나중에 설명하겠지만 Singlecall 모드는 COM+의 트랜잭션 컴포넌트와 사이가 매우 좋지 않다.

SingleCall과 Singleton은 공통적으로 클라이언트가 이들 모드의 원격 객체의 활성화 시점을 결정할 수 없다. SingleCall은 매 원격 호 출마다 객체가 활성화되고, Singleton은 최초의 원격 호출시에 객체 가 활성화되고 이 객체는 여러 호출에 대한 서비스를 수행한다. 비록 클라이언트가 new 연산자를 통해 원격 객체를 생성한다 할지라도 그것은 원격 객체가 아닌 로컬 애플리케이션 도메인에 생성되는 프 록시(proxy)임에 유의하자. 이렇게 SingleCall 모드와 Singleton 모 드의 객체를 통틀어 리모팅에서는 WKO(Well-Known Object)라 부 른다.

세 번째 모드는 소위 CAO(Client Activated Object)로서 원격 객 체의 활성화를 클라이언트가 결정하는 원격 객체를 말한다. CAO 모 드의 원격 객체는 클라이언트가 new 연산자를 통해 객체를 생성하 고자 하면 로컬 애플리케이션 도메인에 프록시가 생성됨은 물론 원 격 애플리케이션 도메인에서 원격 객체가 생성된다.

그리고 CAO 모드의 객체의 일생은 리스(lease)라 불리는 객체에 의해 좌우된다. 리스 객체는 CAO 모드의 객체 생성과 동시에 닷넷 리모팅 서비스에 의해 생성되는 객체로서 CAO 객체가 얼마동안 살 아 있어야 하는가를 결정한다. 리스 객체는 리스 타임(lease time)이 라 불리는 시간을 갖고 있어서 이 타이머가 0이 되면 CAO 객체는 더 이상 클라이언트 호출을 받을 수 없으며 GC의 대상이 된다. 리스 객체가 생성되면 InitialLeaseTime 값이 리스 타임으로 할당되는데 이 값의 디폴트는 5분이다. 그렇다면 5분이 지나면 CAO 객체는 항 상 제거될까 그렇지는 않다. 리스 객체는 CAO 객체가 호출될 때마 다 리스 타임을 늘릴 수 있다. 객체가 호출될 때마다 늘어나는 리스 타임을 RenewOnCallTime이라 부르며 이 값의 디폴트는 2분이다.

InitialLeaseTime, RenewOnCallTime 등 리스에 관련된 설정값 은 LifeTimeServices 클래스의 정적(static) 프로퍼티로서 제공되 므로 서버 측에서 적절한 값을 할당할 수 있다.

이렇게 리스를 통해 객체의 생명주기를 관할하는 것을 닷넷 리 모팅에서는 Lease-Based Lifetime Management라 부른다. 리스 에 대한 것을 설명하자면 상당히 복잡하고 이 컬럼의 목적이 리모 팅 자체가 아닌 원격 COM+ 컴포넌트에 대한 액세스 방법이므로 여기서는 생략하겠다. 상세한 내용은 MSDN을 참고하기 바란다.


리모팅 서비스 호스팅

리모팅을 통해 원격 객체를 액세스하기 위해서는 원격 객체를 호스 팅하는 애플리케이션 도메인이 필요하다. 호스팅 애플리케이션 도 메인을 갖는 프로세스를 간단히 호스트라 부르며, 호스트는 원격 액 세스를 수신할 채널을 설정하고 이 채널이 사용할 포매터 설정, 그리 고 이 호스트가 제공할 원격 객체를 등록하는 역할을 한다. 일단 이 러한 설정이 완료되면 닷넷 리모팅 서비스가 스스로 리스너 쓰레드 를 수행하고 원격 클라이언트의 호출을 수신하기 시작한다. 채널에 대한 리스너를 리모팅 서비스가 수행해 주므로 호스트는 별다른 작 업을 수행하지 않아도 되며 단지 서비스가 진행되는 동안 호스트가 종료되지 않도록 유지해주면 된다.

TCP 채널을 사용하는 경우, 호스트는 개발자에 의해 작성돼야 한 다. 이 경우, 호스트는 윈도우 2000 서비스 형태로 구현돼 운영체제 부팅과 더불어 수행되도록 하는 것이 일반적이다. 물론 호스트가 HTTP 채널을 사용할 수도 있다. 하지만 HTTP 채널을 사용할 때는 또 다른 옵션이 있다. 리모팅의 호스트로서 IIS를 사용할 수 있는 것 이다. IIS가 HTTP 채널로 수신되는 리모팅 호출을 원격 객체로 전 달할 수 있는 능력이 있기 때문이다. IIS를 리모팅 호스트로 사용하 는 구체적인 방법은 설정 파일에 대해 설명한 후에 다시 언급하겠다.


리모팅 예제

리모팅에 대한 전반적인 내용을 간략히 살펴봤으므로 이젠 예제를 살펴보자. 리모팅 예제는 크게 세 부분으로 나눠진다. 원격 액세스를 제공할 원격 객체 부분, 원격 객체를 호스팅할 호스트, 그리고 클라 이언트다. 개발 도구는 VS.NET 베타 2이다. 이 컬럼을 독자들이 읽 을 시점이면 한글판 VS.NET 정식 버전이 출시됐을 수도 있

3.6.jpg

지만 대부분의 독자들은 아직 정식 버전을 갖고 있지 않을 것이다. 이런 상 황을 감안해 필자는 이번 컬럼도 베타 2를 기반으로 진행하겠다.

먼저 새로운 솔루션을 만들자. 이 솔루션은 새 프로젝트 대화상자 에서 Visual Studio 솔루션 항목의‘빈 솔루션’이다. 이 솔루션에 세 개의 프로젝트를 추가할 것이다. 빈 솔루션을 만들고 여기에 프로젝 트를 추가하면 산뜻한 디렉터리 구조가 되므로 두 개 이상의 프로젝 트를 사용할 때 필자가 주로 사용하는 방법이다.


원격 객체

원격 액세스를 제공할 클래스를 별도의 클래스 라이브러리 프로젝트 로 생성하자. 원격 객체를 별도의 DLL로 만드는 이유는 원격 객체 의 클래스에 대한 타입 정보를 클라이언트가 참조해야 하기 때문이 다. 또한 생성된 클래스가 로컬에서 직접 사용되거나 원격 액세스를 위해 호스트가 호스팅할 수도 있기 때문이다.

원격 객체의 클래스는 매우 간단하다. 단 MarshalByRefObject 클 래스에서 파생됐다는 것을 제외하고 말이다. 원격 애플리케이션 도 메인에 존재하는 객체를 액세스하기 위해선 반드시 원격 객체는 MarshalByRefObject 클래스에서 파생돼야 한다. 그래야만 MBR로 마샬링되며 리모팅에 사용할 수 있다. <리스트 1>은 원격 객체 클래 스 RemoteObject를 보여준다. MarshalByRefObject 클래스에서 파 생됐고 문자열을 BASE64로 인코딩/디코딩하는 메쏘드를 제공한 다. 물론 예제이기 때문에 이런 클래스를 구현한 것이지 BASE64 인 코딩/디코딩을 위해 원격 액세스를 할 일은 없을 것이다.

이로써 원격 액세스할 클래스의 구현이 끝났다. 생각보다 간단해서 서운한 독자는 좀더 읽어가다 보면 서운한 감이 사라질 것이다.


원격 객체 호스트

원격 객체 호스트를 작성하기 위해 솔루션에 콘솔 애플리케이션을 만든다. 그리고 리모팅 사용을 위해 System.Runtime.Remoting.dll 을 참조(reference)에 추가한다. 또한, 호스트가 제공할 원격 객체의 타입을 참조하기 위해 앞서 만든 RemotingObject.dll 역시 참조한 다. 하나의 솔루션에 프로젝트가 모두 존재하기 때문에‘프로젝트 참 조’를 이용하는 것이 더 나을 것이다.

이제 코드를 작성하면 된다. 리모팅에 사용되는 클래스를 위해 System.Runtime.Remoting 네임스페이스와 채널을 위한 System.Runtime.Remoting.Channels 네임스페이스 그리고 사용 하는 채널에 따라 System.Runtime.Remoting.Channels.Tcp 네임 스페이스 혹은 System.Runtime.Remoting.Channels.Http 네임스 페이스 역시 using 키워드를 통해 참조한다. 필자의 예제는 TCP 채 널을 사용할 것이므로 System.Runtime.Remoting.Channels.Tcp 네임스페이스만 사용했다.

호스트에서 가장 먼저 할 일은 리모팅 서비스를 제공할 채널과 포 매터를 지정하는 것이다. 가장 간단한 방법은 채널만을 지정해 주는 것이다. 채널은 디폴트로 사용될 포매터를 자동으로 설정하기 때문 이다(실제는 하나의 서버 채널에 두 포매터를 모두 사용할 수 있다.다만 우선순위가 서로 다를 뿐이다). 만일 자동 설정과 다르게 설정 하고 싶다면 채널 객체를 생성할 때 직접 포매터를 명시해주면 된다.

<리스트 2>는 호스트 코드를 보여준다. 이 예제는 TCP 채널을 사 용하며 앞서 <리스트 1>에서 보여준 RemoteObject 클래스를 Well- Known 객체로 서비스하고 있다. 호스트 코드에서 주의할 점은 채널 객체를 생성할 때 반드시 리스닝(listening)할 포트 번호를 생성자 (constructor)에 명시해야 한다는 점이다. TcpChannel 객체는 생성 자에 포트 번호가 주어지면 리모팅 서버용 채널(TcpServerCha nnel)을 생성하고, 생성자에 매개변수가 주어지지 않으면 클라이언 트용 채널(TcpClientChannel)을 생성하기 때문이다.

또 한 가지 살펴봐야 할 것은 원격 액세스를 제공할 클래스를 등록 하는 것인데, 여기에 사용된 메쏘드는 RemotingConfiguration 클래 스의 정적 멤버인 RegisterWellKnownServiceType 메쏘드다. 이 메 쏘드에 원격 액세스로 제공할 클래스 타입(Type 클래스)과 URI, Well-Known 객체 모드를 명시하면 된다. 주의할 점

3.7.jpg

은 URI인데, 임의의 URI를 주면 되지만 가급적이면 확장자를 .rem 혹은 .soap로 주는 것이 좋다. 이는 IIS를 호스트로 사용할 때 IIS가 리모팅 호출을 구분하기 위해 요구되기 때문이다. 이에 대한 내용은 잠시 후에 다시 설명하겠다. <리스트 2>처럼 URI가 주어지면 클라이언트가 원격 객 체에 접근하기 위해 사용하는 URL은 tcp://server_name:8085/ RemoteObject.rem이 된다. 만일 URI를 dir/RemoteObject.rem으 로 주었다면 클라이언트가 사용하는 URL은 tcp://server_name: 8085/dir/RemoteObject.rem이 된다. URL에 포트 번호가 주어졌 음을 유의한다.

이렇게 설정이 완료되면 호스트가 해야 할 일은 끝난 셈이다. 그렇 다고 호스트가 종료돼서는 안된다. 호스트가 종료되면 리모팅 서비 스 역시 종료되므로 호스트는 서비스를 제공하는 동안에는 죽지 않 고 살아 있어야 한다. <리스트 2>에서는 단순히 콘솔로부터 입력을 기다리도록 했다. 만일 독자들이 예제가 아닌 실제 프로젝트에 호스 트 코드를 작성해야 한다면 보다 우아한 방법을 찾아보는 것이 좋을 것 같다. 윈도우 2000 서비스 프로그래밍에 대한 지식이 있는 독자 라면 필자가 말하는 것이 어떤 것인지 잘 이해할 것이라 믿는다.

3.9.jpg

서비스 프로그래밍에 대해 잘 모르는 독자라면 이제라도 늦지 않았으니 서비스 프로그래밍에 대한 관련 도서나 자료를 찾아보기를 권한다.


원격 객체클라이언트

이제 남은 것은 클라이언트를 작성하는 것이다. 클라이언트 작성은 그다지 어렵지 않다. 원격 객체의 클래스를 로컬 객체처럼 사용하면 된다. 다만, 사용할 객체가 원격 객체라는 것을 닷넷 프레임워크에 알려주면 된다. 이렇게 하기 위해서는 먼저 리모팅에 사용할 채널과 포매터를 설정해야 한다. 설정 방법은 호스트 작성시와 매우 비슷하 다. 채널 객체를 만들어 등록하면 되는데, 주의할 점은 포트 번호를 명시하면 안된다는 점이다. 포매터를 설정하기 위해서는 앞서 설명 한 대로 포매터 객체, 정확히 말해 포매터 싱크 프로바이더 객체를 생성하고 이 객체를 채널의 생성자에 매개변수로 넘겨주면 된다. 다음으로 수행할 작업은 리모팅을 사용할 타입을 등록하는 것이다. 이 작업은 닷넷 프레임워크에게“이 클래스는 원격 애플리케이션 도 메인에 있으므로 리모팅을 통해 액세스하도록 해줘”라고 말하는 것과 같다. 이와 같은 작업도 RemotingConfiguration 클래스의 정적 메쏘 드인 RegisterWellKnownClientType 메쏘드를 호출하면 된다. WKO 이기 때문에 이 메쏘드를 호출하는 것이다. 만일 원격 객체가 CAO이 라면 RegisterActivatedClientType 메쏘드를 호출해야 한다. 어찌됐 건 이 메쏘드는 두 개의 매개변수를 취하는데, 리모팅에 사용할 클래 스 타입과 원격 액세스를 위한 URL을 명시해 주면 된다. 이제 남은 건 원격 객체를 생성하고 그것을 사용하는 것이다. 원격 객체를 생성하는 것은 매우 간단하다. new 연산자를 사용해 객체를 만들고‘사용’하면 끝난다. 일반적인 로컬 객체를 생성하고 사용하 는 것과 전혀 다를 바 없다. 주의할 점은 new를 이용해 객체를 생성 하더라도 원격 객체가 생성되지 않는다는 점이다. new가 생성하는 것은 원격 객체에 대한 프록시(<그림 3> 참조)만이 생성될 뿐이며 실 제 원격 객체는 원격 객체의 메쏘드가 호출될 때이다. 물론 WKO 모 델이기 때문에 new가 원격 객체를 생성하지 않는 것이다. 만약 예제 에서 CAO 모델을 사용했다면 new 연산자가 수행될 때 원격 객체가 생성될 것이다. 클라이언트가 웹 애플리케이션이라면 어떻게 해야 할까 ASP.NET에서도 상황은 동일하다. <리스트 3>과 마찬가지로 리모 팅 설정을 수행한 후에 new 연산자를 통해 객체를 생성해 사용하면 된다. 다만 웹 애플리케이션에서 리모팅과 관련된 설정 수행은 애플 리케이션 레벨에서 한번만 수행하면 되므로 global.asax 파일의 Application_Start 이벤트 핸들러에서 수행한다.


테스트

이제 작성된 리모팅 예제를 테스트해 보자. 먼저 커맨드 라인 콘솔에 서 Host.exe를 수행시킨다. Host.exe는 리모팅 서비스를 초기화하 고 클라이언트의 원격 액세스를 리스닝하기 시작할 것이다. 그리고 RemoteClient.exe를 호출하면 리모팅을 통해 호출이 진행되는 것을 알 수 있을 것이다. 원격 호출이 실제로 수행되는지 확인하고 싶다면 SOAP 툴킷에 포함된 Trace Utility를 사용한다. 파일 메뉴에서 새 로운 Unformatted 트레이스를 생성하고 Trace Setup 대화상자에 서 Listening 포트를 8086으로, Destination 포트를 8085로 설정한 다. 그리고 RemoteClient.cs의 RegisterWellKnownClientType 메 쏘드 호출에 사용된 URL을 8086 포트를 사용하도록 다음과 같이 수정한다. // 원격 액세스로 사용할 원격 클래스를 등록한다. RemotingConfiguration.RegisterWellKnownClientType( typeof(RemotingObject.RemoteObject), “tcp://localhost:8086/RemoteObject.rem”); 다시 RemoteClient.exe를 수행시키면 <화면 2>와 같은 결과를 얻 을 것이다. TCP 채널과 Binary 포매터가 사용됐으므로 이와 같은 결과를 얻은 것이다. HTTP 채널과 SOAP 포매터를 사용한다면 Trace Utility에서 Foramtted 트레이스를 생성해야 제대로 된 결과 를 볼 수 있다. SOAP 포매터가 사용되면 원격 호출과 호출 결과는 XML 형식의 SOAP 메시지가 될 것이다.


리모팅 컨피규레이션

지금까지 작성한 예제의 내용을 요약해 보면 이렇다. 원격 액세스를 제공할 클래스를 MarshalByRefObject 클래스로부터 파생해 별도의 DLL로 만든다. 그리고 이 클래스에 대한 원격 액세스를 호스팅할 호스트 프로그램을 작성한다. 이 호스트는 리모팅에 대한 설정 작업 을 수행하고 대기하게 된다. 클라이언트 역시 원격 액세스를 위한 설 정 작업을 수행하고 원격 객체를 생성 및 사용한다. 원격 액세스를 위한 객체 작성은 제외하고 호스트와 클라이언트에서 공통적으로 수 행되는 작업은 리모팅에 대한 설정 작업일 것이다. 채널을 선택하고 이 채널이 사용하는 포트, URL, 이 채널에 적용할 포매터, 그리고 원격 액세스로 제공할 클래스 타입 등을 설정하며, 이것은 호스트와 클라이언트가 서로 약속에 의해 맞춰져야 한다.

코드가 그다지 복잡하지 않지만 만약 이 설정 사항이 변경돼야 한 다면 어떨까 예를 들어 HTTP 채널과 SOAP 포매터를 사용하다가 약간의 성능 향상을 위해 TCP 채널과 Binary 포매터를 써야 한다 면 물론 호스트 코드와 클라이언트 코드를 변경하고 이것을 다시 컴파일하면 된다. 간단한 프로그램이라면 이러한 작업이 쉽게 끝날 수도 있지만 기업용 애플리케이션과 같이 수백개의 화면과 수십, 수 백개의 원격 객체를 사용한다면 어떻게 될까 일일이 코드를 돌아다니며니며 URL을 수정하는 노가다()를 감수해야 할 것이다. 특히 로컬 에서 사용하던 객체를 원격 객체로서 액세스해야 한다면 원격 객체 가 한 컴퓨터에 존재하다가 다른 컴퓨터로 옮겨간다면 매번 우리의 개발자는 날밤을 새며 코드를 수정해야 할 것이다. 많은 코드를 수정 했더라도 우리의 불쌍한 개발자는 혹시나 수정하지 않은 것이 없나 전전긍긍할 가능성도 많다.

이러한 문제를 한방에 날려버리도록 해주는 것이 리모팅 설정 파 일(configuration file)의 사용이다. 호스트나 클라이언트에서 코드를 통해 설정했던 리모팅 관련 사항을 별도의 설정 파일에 두고 이것을 통해 리모팅 설정을 수행할 수 있다. 다음 코드는 설정 파일을 사용 하는 클라이언트 코드의 예다.

RemotingConfiguration.Configure(“config_file”);
RemotingObject.RemoteObject obj
= new RemotingObject.RemoteObject();
Console.WriteLine(obj.GetBase64String(“Hello World”));

이 코드는 설정 파일을 통해 리모팅에 대한 설정을 수행하고 객체 를 사용한다. Configure 메쏘드를 호출하는 라인을 제외하고는 일반 적인 로컬 객체를 사용하는 것과 다른 점이 전혀 없다. 이것이 의미 하는 바는 무엇인가 설정 파일은 호스트와 클라이언트를 다시 컴파 일하지 않아도 되도록 해준다. 재 컴파일을 요구하지 않는다는 말은 매우 매력적이다. 이것은 클라이언트 프로그램을 다시 배포하지 않 아도 된다는 말과 상통하기 때문이다(물론 새로운 설정 파일을 다시 배포해야겠지만 프로그램을 배포하는 것보다는 훨씬 쉽다). 설정 파일을 사용함으로써 가질 수 있는 진정한 이점은 클라이언 트 코드가 객체의 위치로부터 독립된다는 점이다. 위 예제 코드에서 RemoteObject 클래스의 인스턴스가 로컬 애플리케이션 도메인에서 생성돼야 한다면 리모팅 설정 파일을 비워 두면 된다. 만약 클라이언 트가 원격 애플리케이션 도메인에서 활성화돼야 한다면 리모팅 설정 파일을 수정하면 된다. 이로써 클라이언트 코드를 개발할 때 로컬 객 체인지 원격 객체인지 구분하지 않고 코드 작성이 가능해진다. 리모팅 설정 파일은 닷넷 애플리케이션에서 전반적으로 사용하는 설정 파일의 일부다. 설정 파일은 다양한 내용을 포함한다. 어셈블리 (DLL) 바인딩에 대한 내용, 로드할 어셈블리를 검색할 디렉터리 설 정 등이 설정 파일에 포함되며 닷넷 리모팅에 대한 설정 역시 여기에 포함된다. 설정 파일은 직관적인 XML 파일이다.< configuration>이 라는 루트 태그 밑에 각 설정별로 하위 태그들을 갖게 된다. 리모팅 과 관련된 설정은< system.runtime.remoting> 태그 밑에 존재하며 다양한 태그들을 통해 리모팅 설정을 수행할 수 있다.

호스트는 태그의 하위 태그로서 < service>태그를 통해 원격 액세스를 제공할 클래스 타입, URL, 호 출 모드(singlecall/singleton)를 설정하고, 클라이언트는< client> 태 그를 사용한다. 그리고 호스트와 클라이언트 공히 태그 와 태그를 통해 사용할 채널을 설정할 수 있다. 리모팅 관련 태그들은 상당히 양이 많으므로 지면 관계상 여기서 모두를 설명할 수는 없다. 여기서는 예제를 중심으로 설명하고, 설정 과 관련된 다른 사항들은 참고문헌 과 MSDN 라이브러리의 .NET Framework Configuration File Schema 항목을 참조하기 바 란다.


호스트 설정

호스트의 리모팅 설정 파일은 <리스트 4>와 같다. 닷넷의 설정 파일 은 애플리케이션 파일 뒤에 .config 확장자를 붙여야 한다. 호스트가 host.exe이므로 설정 파일은 host.exe.config가 된다. ASP.NET 웹 애플리케이션은 web.config 파일이 사용된다. <리스트 4>를 살펴보 면 일반적인 XML 파일과 다를 바가 없다. 이 우리가 관심을 갖는 리모팅 설정이다. 태 그가 먼저 등장하고 애플리케이션에서 사용하는 리모팅 설정들이 이 태그의 하위 태그로서 나타나게 된다. 호스트는 원격 액세스로 제공 할 클래스를 명시하는데, 이들 클래스에 대한 설정은< service >태그 의 하위 태그들로 나타난다. WKO는 >태그를 사용하 고, CAO는< activated >태그를 사용한다. 태그는 원격 객체를 제공할 클래스의 풀 네임(네임스페이스를 포함한 클래스 이 름)과 이 클래스를 정의하고 있는 어셈블리 이름, 즉 확장자를 제외 한 DLL 파일 이름이 컴마로 구분돼 명시되고 원격 객체의 URI, WKO의 모드(SingleCall, Singleton)를 명시해야 한다. 반면 태그는 클래스 타입만을 명시하면 된다.

다음으로 나타나는 것이 채널 설정으로 태그와 ,chan nel >태그를 사용한다.< channels> 태그는 호스트에서 사용하는 채 널들의 집합을 의미하고, channel 태그는 각 채널 설정이 명시된 다. 이는 하나의 호스트가 여러 채널을 통해 리모팅 서비스를 수행할 수 있음을 의미한다. 어찌됐건 태그에 사용할 채널과 포 트를 명시하면 되는데, 이는 채널 객체의 타입을 네임 스페이스를 포 함한 클래스의 풀 네임과 어셈블리 이름을 콤마로 구분해 port 애트 리뷰트와 type 애트리뷰트에 표시한다. 8085 포트를 사용하는 HTTP 채널이라면 다음과 같이 설정하면 된다.

<리스트 4>에서는 이미 정의된 채널을 ref 애트리뷰트로‘참조’했다. 리모팅에 사용되는 HTTP 채널과 TCP 채널은 C:\WinNT\Microsoft .NET\Framework\Vxxxxx\Config 폴더에 존재하는 machine.con fig 파일에 채널이 이미 정의돼 있으며 이 채널 정의를 애플리케이션 설 정 ref 애트리뷰트에 “tcp”혹은“http”값을 설정하면 이미 정의된 채널을 사용할 수 있다.

채널 설정이 끝나면 포매터 설정을 수행할 수 있다. 포매터 설정은 생략이 가능한데, 이 경우 TCP 채널은 Binary 포매터, HTTP 채널 은 SOAP 포매터가 디폴트로 선택된다(실제로 두 채널은 Binary 포매터와 SOAP 포매터를 둘 다 사용할 수 있도록 돼 있다. 다만 우선 순위가 차이날 뿐이다). <리스트 4>는 포매터 설정을 예로 보이기 위 해 명시적으로 포매터를 설정하고 있는데, 채널에서 그랬던 것처럼 ref 애트리뷰트를 이용해 machine.config 파일에서 이미 정의된 포 매터 정의를‘참조’했다.


클리이언트 설정

클라이언트 설정은 <리스트 5>와 같다. 호스트용 설정 파일과 그다지 큰 차이가 없어 보인다. 태그 대신< client> 태그가 사용됐 고 태그는 objectUri 애트리뷰트 대신 url 애트리뷰트 가 사용됐다. 컬럼을 정독한 독자라면 벌써 눈치챘겠지만 리모팅 설 정 파일에 명시되는 것은 모두 리모팅 관련 메쏘드 호출의 매개변수 와 일치한다. <리스트 5>의 wellknown 태그에 명시되는 애트리뷰트 는 RegisterWellknownClientType 메쏘드의 매개변수와 일치하며, <리스트 4>의 wellknown 태그에 명시된 애트리뷰트는 RegisterWell knownServiceType 메쏘드의 매개변수와 일치한다. 클라이언트 설 정 파일에서 채널 및 포매터 설정은 호스트용 설정 파일과 동일하다. 다만 serverProviders 태그 대신 clientProviders 태그가 사용됐다는 점이 다를 뿐이다.

ASP.NET 웹 애플리케이션의 경우는 web.config 파일이 설정 파 일 역할을 하므로 이 파일에 리모팅 설정을 하면 된다. web.config 파일이 이미< configuration>태그를 갖고 있으므로 <리스트 5>의태그와 그 하위 태그만을 web.config 파일에 추가하면 된다.

3.10.jpg


호스트 및 클라이언트 코드 변경

이제 앞서 보여준 <리스트 4>와 <리스트 5>의 설정 파일을 사용하도 록 호스트 코드와 클라이언트 코드를 수정해 보자. 수정 사항은 간단 하다. 코드를 통해 수행했던 리모팅 설정 부분을 모두 제거하고 대신 설정 파일을 이용해 설정하면 된다. 원격 액세스를 위한 RemoteObject 클래스(<리스트 1>)는 변경할 것이 없다. <리스트 2> 와 <리스트 3>의 코드를 <리스트 6>과 같이 수정하면 된다. 변경 사 항의 핵심은 RemotingConfiguration 클래스의 Configure 메쏘드에 리모팅 설정 파일의 경로를 명시한 것이다. 리모팅 프레임워크는 설 정 파일의 내용을 이용해 채널, 포매터 그리고 WKO 클래스를 생성 하거나 등록할 것이다. 간단하지 않은가

클라이언트가 ASP.NET 웹 애플리케이션이라면 어떻게 해야 할 까 간단하다. Global.asax의 Application_Start 이벤트 핸들러에서 Configure 메쏘드를 호출하면 된다. 매개변수는 web.config 파일여 야 하고 이 파일의 물리 경로가 필요하므로 Server.MapPath 메쏘 드를 사용하면 될 것이다.

RemotingConfiguration.Configure(Server.MapPath(“web.config”)); 지금까지의 예제는 TCP 채널과 Binary 포매터를 사용했다. 포매터 를 SOAP 포매터로 바꿔보자. <리스트 4>와 <리스트 5>에서 태그의 ref 애트리뷰트를“soap”으로 바꾸면 TCP 채널과 SOAP 포매터를 이용해 서버와 클라이언트는 통신할 것이다. 앞서 설 명한 Trace Utility를 통해 확인해 보자. SOAP 메시지를 주고받는가 클라이언트의 설정 파일을 수정함으로써 로컬에서 객체나 원격 객 체를 생성 및 사용할 수 있다고 했다. 이 때, 클라이언트가 지금 사용 하는 객체가 로컬 객체인지 원격 객체인지를 알아낼 수 있는 방법이 있을까 new를 통해 객체가 생성되므로 알아내기는 힘들 것이다.

3.11.jpg

3.12.jpg

이 때 RemotingServices.IsTransparentProxy 메쏘드를 통해 생성 된 객체가 리모팅 프록시인지 아닌지는 판별해 볼 수 있다.

if (RemotingServices.IsTransparentProxy(obj))

Console.WriteLine(“Accessing Remote Object”);

else

Console.WriteLine(“Accessing Local Object”);


IIS를 리모팅 호스트로

이제까지 리모팅에 대한 대부분을 다뤘다. 마지막으로 남은 이슈는 호스트에 대한 것이다. 리모팅에서 원격 객체 서비스를 수행하기 위 해 원격 객체를 호스팅하는 호스트 애플리케이션 도메인이 필요하다 고 했으며 우리는 이 호스트를 직접 작성했다. 닷넷 프레임워크는 리 모팅에 또 다른 옵션을 준비해 두고 있다. 바로 윈도우 2000의 표준 () 웹 서버인 IIS를 리모팅의 호스트로 사용하는 것이다. 리모팅이 HTTP 채널을 사용한다면(포매터에 상관없이) 별도의 호스트를 작 성할 필요없이 IIS를 호스트로 사용할 수 있다. IIS를 호스트로 사용 할 수 있다는 것은 단순히 호스트를 위해 별도의 코딩이 필요없는 정 도가 아니다. IIS가 제공하는 여러 기능을 모두 리모팅에 적용할 수 있다는 뜻이 된다. IIS가 제공하는 기능이 한두 가지인가 IIS가 제 공하는 높은 성능은 물론 윈도우 기반의 보안 사항을 모두 리모팅에 적용할 수 있으므로 자동으로 많은 장점을 갖게 된다. 하지만 리모팅 서비스는 반드시 HTTP 채널이 사용돼야 하며 WKO 객체의 URI는 .rem 혹은 .soap 확장자를 가져야 한다(CAO는 URI를 명시하지 않 으므로 상관없다)는 제약 사항이 따른다.

필자는 리모팅에 대한 도입부에서 리모팅은 원격 애플리케이션 도 메인의 객체를 액세스하는 메커니즘이라 했다. 그렇다면 IIS를 호스 트로 사용하기 위해서도 애플리케이션 도메인이 필요하다는 말이 된 다. IIS에서 닷넷 애플리케이션 도메인을 만드는 방법은 너무나 간단 하다. IIS의 웹 애플리케이션을 만들고 이 웹 애플리케이션의 루트 폴더에 web.config 파일만을 만들어 두면 된다. 게다가 앞서 설명한 리모팅 설정을 web.config 파일에 설정해 줄 수 있으므로 간단히 끝 날 것이다.

이러한 과정을 차근차근 수행해 보자. 먼저‘인터넷 서비스 관리자’ MMC를 수행한다. 그리고 적절한 위치에 가상 디렉터리(virtual directory) RemotingSample을 생성한다. 필자는 IIS를 호스트로 사 용할 때 리모팅 클래스 프로젝트의 디렉터리를 가상 디렉터리로 설정 하곤 한다. 즉, 앞서 작성한 <리스트 1>의 프로젝트 폴더를 가상 디렉 터리로 설정한다. 필자가 설정한 가상 디렉터리는 <화면 3>과 같다. 이제 필요한 작업은 <리스트 1>에서 정의한 RemotingObject 클래 스를 담는 DLL을 가상 디렉터리의 하위 bin 디렉터리에 복사렉터리가 없다면 만들 자. 필자가 앞서 설정한 대로 프로젝트 디렉터리를 가상 디렉터리로 설정했다면 이미 bin 디렉터리가 존재할 것이다. 필자가 주로 사용하 는 방법은 프로젝트의 등록 정보에서 DLL이 생성되는 디렉터리를 bin으로 설정하는 것이다. 대개 bin\Debug 혹은 bin\Release로 돼 있는데, 이것이 불편할 때가 바로 이 경우다.

이렇게 DLL을 준비했으면 그 다음은 web.config 파일(<리스트 7>)을 생성하고 적절한 리모팅 관련 설정을 해주면 된다. IIS가 호스

3.13.jpg

트이므로 <리스트 4>의 설정 내용과 매우 흡사하다. 다만 HTTP 채 널이 사용되므로 채널에 대한 설정은 하지 않는 것이 좋다. 포매터는 SOAP 포매터 혹은 Binary 포매터 둘 다 사용할 수 있도록 설정되므 로 포매터 설정 역시 불필요한 작업이다. 다만 원격 서비스로 제공할 WKO 및 CAO 설정만을 수행하면 된다.

이제 클라이언트의 리모팅 설정 파일을 수정해 보자. 수정할 부분 은 WKO의 URL과 채널 관련 설정이다. URL은 작성한 가상 디렉 터리의 경로와 서버의 web.config 파일에서 설정한 objectUri를 병합 하면 된다. 필자가 작성한 예는 가상 디렉터리가 http://localhost /RemotingSample이고 objectUri가 RemoteObject.rem였으므로 클라이언트 설정 파일에 URL 애트리뷰트에 사용될 최종 URL은 http://localhost/RemotingSample/RemoteObject.Rem이 된다. 만 약 가상 디렉터리의 이름이 test이고 web.config에 objectUri를 “complex/test.soap”라고 설정했다면 클라이언트의 wellknown 태 그의 URL은 http://localhost/test/complex/test.soap가 될 것이다.

< wellknown type=”RemotingObject.RemoteObject, RemotingObject”

url=”http://localhost/RemotingSample/RemoteObject.rem” >

클라이언트 설정의 채널은 생략이 가능하다. 태그에 주어진 URL을 기초로 프레임워크가 자동으로 채널과 포매터를 설 정하기 때문이다. 굳이 <리스트 5>의 설정 내용을 수정하자면 HTTP 채널을 사용하고 포매터는 soap 혹은 binary로 설정하면 된다. Binary 포매터가 실제로 작동하는가를 확인하기 위해 binary로 설 정한 예는 다음과 같다.

><

clientProviders

formatter ref=”binary”/

/clientProviders

/channel

/channels

이제 클라이언트를 수행시키면 IIS를 통해 리모팅 서비스를 제공 할 것이다. 앞서 언급한 Trace Utility를 통해 이것을 확인해 보자.


COM+와 리모팅

이제 리모팅과 COM+ 컴포넌트가 어떤 관계가 있는지 살펴보자. 지난 2월호 컬럼에서 닷넷 프레임워크를 사용해 COM+ 애플리케 이션 및 컴포넌트를 어떻게 작성하고 사용하는가에 대해 설명했다. 그리고 이 방법은 COM+ 컴포넌트와 클라이언트가 동일 컴퓨터에 존재하는 경우에만 가능하다고 했다. 그렇다면 원격 컴퓨터에 존재 하는 COM+ 컴포넌트를 호출하는 방법은 어떠할까

컬럼 서두에서 COM+ 내보내기에 대해 간략히 언급했으며 닷넷 환경에서 이 기능을 사용할 수 없음을 설명했다. 차후에 발표될 윈도 우 닷넷 서버는 닷넷으로 작성한 COM+ 컴포넌트를‘내보내기’할 수 있다. 하지만 윈도우 2000이 주력인 현 상황에서는 원격 COM+ 컴포넌트를 사용하려면 닷넷 리모팅을 사용해야 한다(윈도우 닷넷의 COM+ 내보내기에 대한 내용은 잠시 후에 살펴보겠다).

원격 COM+ 액세스하기

원격 COM+ 컴포넌트를 어떻게 리모팅을 통해 호출할까 이미 알 고 있는 독자들도 있겠지만 COM+ 컴포넌트를 작성할 때 베이스 클래스로 사용하는 ServicedComponent 클래스의 조상 클래스 중 MarshalByRefObject 클래스가 있다. ServicedComponent 클래스 가 MarshalByRefObject 클래스에서 파생됐고 우리가 작성하는 COM+ 컴포넌트가 ServicedComponent 클래스에서 파생됐으므로 COM+ 컴포넌트를 리모팅으로 호출할 수 있다. COM+ 컴포넌트 는 MarshalByRefObject에서 파생된 클래스로부터 만들어지므로 리 모팅을 통해 액세스가 가능하다.

구체적으로 어떻게 액세스할 수 있을까 필요한 것은 COM+ 컴포 넌트를 리모팅 서비스로 제공할 호스트와 이 호스트의 적절한 리모팅 관련 코드 혹은 리모팅 설정 파일이다. 직접 호스트를 작성해도 되지 만 IIS를 사용하는 것이 여러 모로 유리하다. 앞서 설명한 대로 컴포넌 트 프로젝트 폴더를 가상 디렉터리로 설정하고 web.config 파일을 <리 스트 7>처럼 설정해 준다. 그리고 클라이언트에서 .config 파일을 작성 하고 적절한 리모팅 설정을 한다. 물론 클라이언트 코드의 초기화 부 분에서 RemotingConfiguration.Configure()를 호출하는 것을 잊지 말자. ASP.NET 웹 애플리케이션이 COM+의 클라이언트라면 web.config 파일에서 리모팅 설정을 해주고 global.asax.cs 파일의 Application_Start()에서 Congiure() 메쏘드를 호출하면 된다. 실제 예제는 앞서 수행한 예제와 중복되고 지면 관계상 생략한다.

리모팅을 통해 COM+ 컴포넌트가 액세스되면 COM+ 컴포넌트는 복잡한 생명주기를 갖게 된다. 예를 들어 보자. COM+ 컴포넌트가 적시 활성화(Just In Time Activation)를 사용하지 않더라도 리모팅 의 SingleCall 모드가 사용되면 객체는 클라이언트가 메쏘드를 호출 할 때마다 활성화/비활성화가 반복된다. 또한 리모팅 상황이라면 COM+ 컴포넌트의 입장에서 클라이언트는 C/S 클라이언트나

3.14.jpg

3.15.jpg

ASP.NET 코드가 아닌 리모팅 호스트에 존재하는 COM+ 프록시 (리모팅 프록시가 아니다!)가 클라이언트로 된다. 이것뿐만이 아니 다. WKO에서 SingleCall이냐 Singleton이냐에 따라 혹은 CAO가 사용됐는가에 따라 COM+ 컴포넌트의 생명주기는 매우 달라진다. 지면 관계상 이들에 대한 내용을 모두 다룰 수 없음에 대해 독자들 에게 양해를 구한다. 다만 필자가 권하는 것은 리모팅 설정은 WKO 의 SingleCall을 사용할 것이며 COM+ 컴포넌트의 설정은 적시 활 성화 및 객체 풀링을 사용하는 것이다. 리모팅의 SingleCall 모드와 COM+의 적시 활성화는 매우 궁합이 좋은 모델이며, 객체 풀링은 적시 활성화가 가져오는 잦은 객체 생성/파괴의 단점을 보완해 줄 것 이다. 이렇게 설정된 리모팅 및 COM+ 컴포넌트는 높은 확장성과 더불어 안정된 성능을 제공할 것이다.


윈도우 닷넷의 내보내기

윈도우 닷넷 서버와 윈도우 XP에 포함된 COM+ 의 버전은 1.5이다. COM+1.5 버전이 윈도우 2000에 포함된 1.0 버전과 다른 점은 참고자료를 살펴보기 바란다. 이번 컬럼과 관련된 변경 사항은 윈도우 닷넷 베타부터 지원되는‘SOAP 루트 설 정’과 새로운‘내보내기’다. ‘SOAP 루트 설정’은 c:\winnt\system32\com\soapvroots 폴더의 하위 폴더에 새로운 폴더를 생성하고 이 폴더를 IIS 가 상 디렉터리로 설정해 주며, 또한 이 폴더에 web.config 파일을 비롯해 리모팅을 통해 COM+ 컴포넌트를 호출할 수 있는 적절한 파일들을 생성 해 준다. 윈도우 2000에서 리모팅을 통해 COM+ 를 액세스하기 위해 수작업으로 설정해야 하는 부 분을 모두 COM+ 1.5 런타임이 알아서 해준다.

또한‘SOAP 루트 설정’이 돼 있는 상태에서‘내 보내기’를 수행하면 클라이언트를 위한 설정 파일 을 비롯한 리모팅 프록시 DLL이 생성되고 이것이 설치 가능한 MSI(Microsoft Installer) 파일로 작 성된다. 윈도우 2000이라면 역시 수작업으로 수행 했어야 하는 작업이다. 이러한 기능은 편리하지만 한계를 갖고 있다. 오직 HTTP 채널만을 사용하며 IIS를 통해서만 가능한 일인 것이다. 또한 윈도우 XP의 경우 다음 서비스 팩에서나‘내보내기’기능 을 사용할 수 있을 것이다.

우리는 리모팅의 원리를 배웠다. 따라서 굳이 COM+ 1.5를 기다릴 것이 아니라 직접 설정을 수행 해 주는 것이 여러모로 편리할 것이다. 특히 개발 단 계에서 COM+ 1.5의 내보내기는 매우 불편한 작업 이 돼 버린다. 컴포넌트를 수정하고 컴파일할 때마다 ‘내보내기’를 수행해야 할지도 모르기 때문이다.


논리적 설계와 물리적 배치의 독립

이제 지난 1월호에서 언급한 닷넷 기업용 애플리케이션 아키텍처를 다시 떠올려 보자. 이 컬럼에서 필자는 논리적 설계와 물리적 배치의 독립에 대해 언급한 적이 있다. 닷넷 엔터프라이즈 애플리케이션 아 키텍처는 논리적으로 다 계층으로 설계하고 각 계층의 요소들을 물 리적으로 다양하게 배치할 수 있으며, 이러한 요소들의 위치 변화가 코드에 거의 혹은 전혀 영향을 미치지 않도록 할 수 있다고 했었다. 그리고 이 논리적 설계와 물리적 배치의 독립을 가능케 해주는 것은 다 계층 애플리케이션 설계와 닷넷 리모팅이라는 것도 언급했었다.

이제 독자들은 그 말의 의미를 이해할 수 있을 것이다. 리모팅은 설정 파일로서 클라이언트와 서버의 설정을 자유롭게 변경할 수 있 다. 그리고 이 변화는 코드의 변화나 재 컴파일을 요구하지 않는다. 지난 컬럼에 등장했던 <그림 4>를 떠올려 보자. <그림 4>는 하나의서버 컴퓨터에 IIS와 COM+를 모두 운용하는 경우다. 이 때 ASP. NET 애플리케이션의 web.config 파일은 리모팅 설정이 비어 있게 된다. 즉, 태그의 하위 태그를 비워 둔 다. 이렇게 되면 닷넷 프레임워크는 동일 컴퓨터의 COM+ 애플리 케이션을 활성화하고 컴포넌트를 사용할 것이다. 물론 이 경우에 RemotingConfiguration.Configure 메쏘드가 호출돼도 상관없다. 리 모팅 설정이 비어 있기 때문에 아무런 문제가 없을 것이다. 웹 애플 리케이션의 web.config 파일은 아마도 다음과 같이 돼 있을 것이다.

...... 생략 ......

< system.runtime.remoting >

< /system.runtime.remoting>

후에 서버의 부하 증가나 기타 보안 문제, 혹은 인트라넷용 서버와 인터넷용 서버 분리 등의 이유 때문에 웹 서버와 애플리케이션 서버 를 별도로 운영해야만 한다고 가정해 보자. 그렇다면 아마도 <그림 5>와 같이 변경될 것이 틀림없다. 이 때 관리자가 해줘야 할 부분은 web.config 파일의 태그의 하부에 리모 팅에 관련된 설정이다. 이렇게 해두면 ASP.NET의 웹 애플리케이션 코드들은 원격 애플리케이션 서버의 COM+ 컴포넌트를 사용하기 시작할 것이다. 간단한 설정 작업만으로 로컬 컴포넌트가 아닌 원격 컴포넌트를 사용할 수 있게 된 것이다!

<그림 4>와 <그림 5>의 C/S 클라이언트(WinForm 클라이언트)의 경우도 설정 파일을 사용하면 된다. COM+ 컴포넌트의 위치가 바 뀌면 단지 변경해야 할 것은 설정 파일의 URL뿐이다.


설렘을 간직한 채로

3개월에 걸쳐 닷넷 엔터프라이즈 애플리케이션 아키텍처에 관련된 내용을 설명했다. 2002년 1월호 컬럼에서 아키텍처에 대한 전반적 인 내용을 다뤘으며, 2월호 컬럼에서는 아키텍처의 핵심 요소로서 COM+에 대한 내용을 다뤘다. 그리고 세 번째인 이 컬럼에서는 닷 넷 리모팅에 대해 설명했다.

컬럼에서 다뤄진 내용 외에도 닷넷 엔터프라이즈 아키텍처에서 고 려해야 할 사항은 매우 많다. 필요에 따라 메시지 대기열(Message Queue; 과거에는 MSMQ라 불렀었다)을 사용해야 할 수도 있으며, 윈도우 2000 서비스를 코딩해야 할 수도 있다. 또한 COM+ 컴포넌 트를 호출할 때 다양한 종류와 크기를 갖는 데이터를 어떻게 넘겨줄 것인가에 대한 이슈, 즉 데이터 레코드를 업데이트하고자 할 때 COM+ 컴포넌트에 이 데이터를 다수의 매개변수를 통해 전달할 것 인가 아니면 데이터 셋을 통해 전달할 것인가 혹은 컨테이너 클래스 를 작성할 것인가 등의 이슈는 매우 많다.

이와 같은 다양한 이슈들을 제한된 컬럼에서 모두 다룰 수 없음을 이 해해 주기 바란다. 필자도 기회가 닿는 대로 이러한 내용들을 계속 다 룰 것임을 약속하는 바이다. 또한 시간이 조금만 필자에게 주어진다면 실전! 강의실을 통해 간단한‘기업용 애플리케이션’을 닷넷 환경에서 작성해 보도록 하겠다. 언제부터라고 장담할 수는 없지만 말이다.

독자들이 이 글을 읽을 때쯤이면 한글판 비주얼 스튜디오 닷넷을 설치하고 사용할 지도 모른다. 새로운 개발 환경과 개발 도구는 항상 필자를 설레게 한다. 십년 전 터보 C가 그러했고, 윈도우 3.0의 개발 환경으로서 볼랜드 C++가 그러했으며 델파이 역시 참신한 개발 환 경이었다. 리눅스의 산뜻한 개발 환경 역시 필자를 매료시켰으며 닷 넷 역시 예외는 아니다(왜인지 자바와 포르테(Forte)라는 개발 환경 은 필자를 매료시키지 않았다!). 이제 정식 버전으로 등장한 닷넷 환 경에서 새로운 경험을 시도해 보는 것도 나쁘지 않을 것 같다.

<img border="0" src="https://211.11