점점 지쳐 갑니다.

여러분들도 마찬가지겠죠? ^^

이번 주는 회사일 때문에 집에서도 시간이 잘 안 나는군요. 앞으로는 시간이 조금은 더디게 나갈 것 같은 불길한
예감이 드는군요. 처음엔 내용이 허접이라도 진도라도 빠르면 욕을 적게 먹겠지라고 생각했는데, 이제는 진도까지도 늦어지니 할 말이 없습니다.

가벼운 맘으로 읽을 수 있는 글을 쓰려는 제 의도가 자꾸 무거운 글로 바뀌고 있습니다. 그만큼, COM 이라는
놈이 만만치가 않습니다. 어쩌겠습니까? 그래도 하겠다고 맘 먹은 이상은 해봐야지 않겠습니까? 이제 산 중턱까지 올라간 느낌입니다. 이제 점점
호흡이 가빠지고 몸은 점점 말을 듣지 않을 겁니다. 오로지 산 정상에 섰을 때의 기분을 상상하면서 참는 것만이 산을 정복할 수 있는 유일한
방법일 것 같네요. 아니면 그냥 헬기라도 한대 대절할까요? ^^;

 

그럼 시작하겠습니다.

 

지금까지 COM에 대해 대충은 감이 잡히리라 생각한다. 어떤가?

내 생각으로는 대부분의 사람들은 ‘역시 COM은 할 것이 아니다.’ 이것일 것이다. 아닌가? 그렇다면 그 사람은
우리가 일반적으로 말하는 초보 딱지는 땠다고 할 수 있을 것 같다.

역시 Code 가 설명에 들어가면서 생긴 문제인 것 같다. 왜 Code란 것이 빠질 수 없는 것일까? 사실,
개인적으로 진정한 지식 전달자는 Code 가 한 줄도 필요 없이 지식을 전달 할 수 있어야 한다고 생각한다. ‘David Chappell’
이라는 사람이 있다. ‘Understanding ActiveX and OLE’ 이라는 책으로 유명한 사람이다. 여기서 내가 아는 체 한다고
생각하는 분도 있을 것이다. 하지만, 나도 친구한테 최근에 들은 사람이다. 그래서 이 사람에 대해 조금 아주 조금 알아봤다.
‘Understanding Windows 2000 Distributed Services’ 라는 책도 쓴 사람이었다. 이 사람은 Code를 한
줄도 넣지 않고 설명하기로 유명하다고 한다. 심지어는 COM관련 연구발표회에서 IUnknown, 프락시/스텁 등등 COM에 대한 전반적인
설명하면서도 거의 몇 시간동안 코드를 한 줄도 설명하지 않고 발표 했다고 한다. 대단하지 않은가? 그의 책을 읽어보면, 책도 그리 두껍지 않다.
우리나라의 왠만한 번역서의 반 두께도 되지 않는다. 하지만, 지식 전달 차원에서 이 사람을 따라갈 사람을 없을 것 같다. 왜 이런 일이 가능한
것일까? 그것이 바로 경험에서 우러나는 노하우인 것이다. 아직 난 경험이라고 내세울 것이 눈꼽만큼도 없다. 그래서 나의 설명은 당연히 한계점에
부딪힌다. COM 내가 아무리 설명해도 이해하지 못할 부분이 많을 것이다. 분야도 좁은 분야가 절대 아니다. 결국 COM 서적 한 권 정도는
화장실 갈 때 조차도 끼고 다니면서 독파를 해야 한다. 그리고 천천히 이책 저책 읽어 보는 것이 중요하다고 생각한다.

물론, 실습도 빠질 수 없다. 하지만, 중요한 것은 COM을 왜 써야 하는지에 대한 동기 유발이다.

말이 나온 김에 다른 것도 알아보자. COM을 지금 하고 있지만, COM+ 라는 말도 많이 들어 봤으리라
생각한다. 이것은 또 뭐야 하는 사람도 있을지 모르겠다. 하지만, 이것 역시 COM을 한단계 업그레이드 한 것에 불과하다. 지금까지 한 모든
COM 관련 내용들을 COM+ 라고 해도 아무도 딴지 걸 사람은 없다. COM+ 역시 COM을 그대로 사용하고 몇 가지를 추가한 것일 뿐이기
때문이다. 한마디로 표현하자면 COM+는 COM을 대체하는 것이 아니고, 여러분이 COM에 대해 알고 있는 모든 것은  COM+에서도 응용할 수
있다는 것이다.

DCOM 역시도 마찬가지이다. 물론, 이것도 COM+ 의 한 부분이다.

 

 

그림은 시대흐름과 전체적인 관계를 보는 데 참조하면 되겠다. 설명하자면 이렇다.

1993년 MS는 COM을 도입해서 1996년 Windows NT 4.0의 일부로 DCOM을 넣었다. 그리고 그
해 후반에 Option Pack 을 통해서 MTS(Microsoft Transaction Server)를 배포하였다. 그리고 1998년에
COM+ 에서 MTS와 COM을 아주 효과적으로 통합하였다. 그렇다고 해서 COM+가 MTS와 COM을 합친 것이라고만 생각해서는 안 될
것이다. 갑자기 왠 트랜잭션 서버냐고 반문하는 사람들이 많을 것이다. 나 역시 이것이 왜 필요하고 COM과는 전혀 별개의 문제라고 생각했다.
트랜잭션이라는 말은 데이터베이스에서 듣던 말인데, 왜 COM 하고 연결이 되었을까? 트랜잭션이란는 말을 데이터베이스에 한정시켜서 생각한다면 이
부분은 이해가 불가능하다. 데이터베이스와 COM은 무관하니깐 말이다. 트랜잭션이라는 말 뜻에 의미를 두어야 한다. MTS가 통합되면서 COM은
다음과 같은 점이 나아졌다. 결국 COM+에 추가된 기능이라 해야 할 것 같다.

 

자동 트랜잭션

개체 사용 기간 서비스

스레딩 및 동시성 서비스

보안 서비스

 

그리고 MTS와는 상관없이 다른 서비스들도 추가 되었다.

 

COM+ 이벤트

대기열 구성 요소

구성요소 로드균형

기타 등등.

 

여기서 그림과는 조금은 차이가 있지만, 나의 생각은 이렇다.

 

COM < DCOM < MTS < COM+

 

이런 포함관계와 발전관계를 말하고 싶다.

자세한 것은 나중에 다루도록 하자. 상당히 머리가 아파오는 부분들이다.

이 모든 것을 이해 하려는 것은 엄청난 시간과 노력이 필요하게 된다. 윈도우 2000 분산형 환경, COM,
ADO, DTC, MSMQ, ADSI, SSL 등등 잘 들어보지 못했던 많은 분야도 반드시 알고 넘어가야 하는 부분이다. 도대체 COM과
연관되지 않은 운영체제 기술이 있을까 라는 생각이 들 정도로 방대하다. 그래서 COM 개발자들이 그리 많지 않은지도 모르겠다.(정말 방대한
분량이다. 언제 이걸 다 하나? 내가 설명을 너무 넓게 시작한 나머지 안 다루는 것이 없어진 것 같다는 느낌이다.)

지금 두서없이 나가고 있다고 생각하는 사람들이 많을 것이다. 여기서 잠시 정리 하자. 결국 내가 하고픈
말은 COM+ 가 나왔다더라 또는 DCOM이 어떻다더라 .net 컴포넌트가 어떻다더라는 말에 대해 신경 쓸 필요가 없다는 것이다. 모든 기초는
COM 에서 시작한다. COM 을 완전히 이해 한다면 다른 것들은 조금의 노력만으로 저절로 따라오는 보너스 같은 것들이다라는 것을 강조하고
싶다. 물론, 실전에 당장 들어가고 싶다면 Code가 중요한 요소가 될 수 있다. 하지만, 앞으로 또 어떻게 바뀔지 모른다. C#도 나왔다.
컴포넌트 기술은 하루하루 틀리게 발전하고 있다. 그 컴포넌트를 구현하는 방법은 계속 발전해 갈 것이다. 여기서 Code에 연연할 필요가 없는
이유가 바로 이러한 이유 때문일 것이다.
생각지도 않게 말이 길어졌다. 왜 마샬링을 하는데 이런 긴 말들이 나왔을까? 잘 생각해 보자. #5에서
실습을 하면서도 마샬링과 관련된 코딩을 한 적이 없다. 결국 인프로세스에서는 굳이 마샬링이 필요가 없기 때문이다. 하지만 좀더 나은 서비스를
제공하기 위해서는 필수적으로 구현해야 한다. 대부분 프로세스 경계를 드나드는 로컬서버나 원격서버에서 필요한 것들이다. 따라서 DCOM 과
COM+를 조금 언급해봤다. COM의 최대 장점인 위치 투명성을 제공하기 위해 많은 복잡한 것들이 필요하게 되었고, 그중의 하나도 바로 이
마샬링이다. 그리고 한 분이 질문 해주셨다. 왜 클래스팩토리가 필요한가라고 말이다. 이것 역시 위치 투명성과 직접 관련이 있다. 클라이언트에서
인프로세스 COM 개체를 new 연산자를 사용해서 생성하는 것도 가능하다. 꼭 클래스팩토리를 이용할 필요가 없는 것이다. 하지만, 왜 굳이 이
클래스팩토리를 사용해서 COM 개체를 생성하는 것일까? 그 대답이 바로 위치 투명성을 위한 것이다. 일단 new 연산자를 통해 개체를 생성한다는
것은 자신의 메모리 영역에 개체를 로드한다는 것이 된다. 하지만, 다른 프로세스에서 동작한다거나 멀리 떨어진 PC 상에서 동작하는 COM
컴포넌트를 그 같은 방법으로 생성할 수는 없지 않겠는가? 결국COM이 어디에 있던 클라이언트에서는 같은 생성방법을 제공할 필요가 있었던 것이다.
그래서 나오게 된 것이 클래스팩토리라고 생각하면 쉬울 것 같다.

또 말이 새어 나가려고 하는군. 빨리 여기서 끊어 버리자.

오늘 그것에 대해 알아보겠다고 했었다. 그럼 알아봐야지. 왜 자꾸 엉뚱하게 새어 나가려구 하냐구(아무래도
머리가 너무 복잡해서 정리가 안 되는 것 같다. 넓은 아량으로 이해하시길 바란다.)
그럼 저번 장에 이어서 계속 말을 이어 나가보자. #7 에서 우리는 마샬링, 언마샬링, 프락시 스터브에
대해 언급했다.

사실, 대부분의 COM 관련 서적에서 이 내용은 중간 이후에 언급이 되기 시작한다. 하지만, 내 생각은 다르다.
초반에 언급하고 대충 무엇이란 것을 알고 넘어가는 것이 나중에 더 도움이 될 것 같다.

혹시 CORBA(Common Object Request Broker Architecture) 라고 들어 봤는지
모르겠다. 나 역시 이 부분에 대해서는 잘 모른다. 대충은 MS의 DCOM 과 경쟁하는 놈으로 알고 있다.(반 MS 진영이다. 역사 역시
DCOM 보다 오래 되었고 한 때 우리나라에서도 엄청난 바람이 분적이 있다.) 대부분 컴포넌트는 JAVA로 구현 되고 있고(따라서, 당연히
SUN에서 강력하게 밀어주고 있다. 하지만, 요즘은 또 EJB가 한참 주가를 올리고 있다. 말 그대로 JAVA 만으로 모든 것을 해결하겠다는
의지가 아닐까?)  인터페이스의 지원을 위해 IDL 파일을 역시 사용한다. 신기하게도 여기서도 프락시나 스텁 마샬링, 언마샬링은 그대로
적용된다.(인터페이스의 개념 역시 거의 동일하다.) 결국 분산 컴포넌트라는 놈에게 이 모든 개념은 필수적으로 갖추어져 있어야 한다는 얘기이자
개념상의 문제라는 것을 알 수 있다. 결국 컴포넌트이든 분산컴포넌트이든 간에 COM 에 대한 완벽한 이해는 모든 컴포넌트 기반 기술을 이해 하는
데 버릴 것이 하나도 없는 지식이 될 수 있다는 것이다.

자바의 빈즈를 하더라도 COM과 하나하나 매치가 가능하다. 빈즈의 이놈은 COM의 이놈이 하는 역할이랑 똑 같네.
어 이 놈은 COM의 이 놈이잖아. 이런식으로 말이다.

참고로, CORBA에 대해 궁금해 하시는 분들은 http://www.omg.org/ 를 참조하기 바란다.

(1989년 분산 객체의 상호 운용을 위한 개방형 내부 구조를 정의하고자 결성된 OMG는 CORBA라는 이름으로
분산 객체에 대한 버스 구조를 정의하였다. OMG는 현재 약 800개 업체가 가입하여 활동하고 있는 거대 그룹이 되었다.)

다시 본론으로 들어가자.(아~~~~악! 미치겠다. 왜 자꾸 엉뚱한 소리를 하는지 원~ 나 자신이 제어가
되질 않는다.) 결론은 이거다. 우리가 오늘 하는 프락시, 스텁등등이 결국 마샬링 때문에 나온 기술이라는 것을 알아야 한다. 즉, 마샬링 하나를
하기 위해 프락시나 스텁을 사용해야 하고 그 반대 개념인 언마샬링도 알아야 하는 것이다.

도대체 마샬링이 뭘까? 앞장에서 말한 것이 이해가 쉬웠는가? 여전히 오리무중이다. 어쨌든, 진도를 나가려면
이 놈을 파헤쳐야 한다.

마샬링을 정의 해보자.

마샬링은 한마디로 하나의 메커니즘에 가깝다고 할 수 있다. 즉, 클라이언트가 사용하고자 하는 객체의 형태에
관계없이 같은 방식으로 인터페이스를 사용할 수 있게 하는 메커니즘인 것이다. 기술적인 측면에서 다시 설명해 보겠다. 단일 주소공간에서 마샬링이
필요 없다고 했다. 그것은 컴포넌트를 사용한다고 가정할 때 동작이 일어난다는 것은 메서드 인자들이 메서드 호출을 위한 스택으로 push 되고
실행 될 때 pop 되기 때문이다. 하지만, 실행형 컴포넌트들과 원격 컴퓨터에서 실행되는 것은 마샬링에 대한 신경을 써야만 한다. 왜냐?
마샬링이 메서드의 호출과 인자를 전송가능한 패킷으로 포장해서 컴포넌트로 패킷을 전송하기 때문이다. 그리고 그 반대과정이 언마샬링이라는 것은
충분히 짐작이 가능하다.

참고로, 마샬링은 크게 세가지로 나뉜다.
표준 마샬링(Standard marshaling)

타입라이브러리 마샬링(Type livrary marshaling)

커스텀 마샬링(Custom marshaling)

위의 세가지 이다.

표준 마샬링의 경우 MIDL로 컴파일 해서 나온 파일들을 가지고 사용한다.

옛 기억을 잠시 상기해보자. 특히 MIDL로 IDL 파일을 컴파일 했을 때 생겼던 파일들을 말이다.

iAdd.h            : C와 C++ 버전의 인터페이스 정의

iAdd_i.c                    : IID와 CLSID 상수 정의

iAdd_p.c         : 프락시/스텁 마샬링 코드

iAdd.tlb                     : 타입 라이브러리(IDL 파일의 바이너리 버전)

dlldata.c         : 마샬링 코드에 대한 DLL 엔트리 포인트

기억나쥐? 이 파일들을 컴파일하고 링크하면 해당 인터페이스를 정확하게 마샬링해주는 프록시/스텁 DLL을
생성할 수 있다. 간단할 것 같지 않은가? 다 만들어 주는데 말이다. 실습은 나중에 하자. 지금은 아직 시기가 아니다.
두번째 나온 타입라이브러리 마샬링은 오토메이션 마샬러를 사용한다. 이것은 IDispatch 인터페이스를
구현해서 비주얼베이직이나 자바 스크립트값은 언어와도 동작한다. 여기에 대해선 이정도만 알고 넘어가자.
그리고 마지막 커스텀 마샬링이다. 가장 기본적인 마샬링이라고 할 수 있다. 마샬링 과정에 대해 제어권을
완전히 가져와서 하는 것이다. 따라서 구현하기가 꽤 까다로울 것이라고 짐작된다. 효율을 중시 한다면 이 커스텀 마샬링을 사용해야 할 것이다.
그럼 이제 이해를 해보자. 원격에 있는 COM 서버를 사용하기 위해서는 그 서버를 대체해줄 것이 필요하고
그 대체품은 클라이언트와 같은 프로세스에서 실행 되어야 한다. 그래야만 클라이언트에서 인식이 가능하지 않겠는가? 여기서 그 대체품으로 프락시나
핸들러가 필요하게 된 것이다. 프록시는 원격의 서버를 순수하게 대행하지만, 핸들러는 대행을 할 수도 있고, 자신이 구현할 수도 있는 혼합
형태이다. 어쨌든 둘 다 원격의 객체와 클라이언트의 연결을 위한 대행의 역할을 한다. 클라이언트가 서버의 함수를 호출할 때 넘겨지는 인자,
그리고 서버 함수의 리턴값은 프로세스의 경계를 넘어서 유효해야 한다. 이 측면 또한 마샬링이 개입되는 곳이다.

인자의 형태에 따라 다른 형태의 마샬링이 일어나기도 한다. DWORD같이 간단한 타입은 직접 복사가 된다. 그러나
어떤 영역을 가리키는 포인터가 넘어갈 때는 그 영역 전체가 프로세스 경계를 넘어 복사되어야 한다. 이 작업이 그렇게 만만한 작업이 아니다.
배열을 마샬링할 때를 생각해보자. 마샬러에서 어떻게 배열의 크기를 알 수 있을까? 그리고 전체 배열을 알았다 치더라도 아직 앞의 몇 바이트만
사용했을 수도 있다. 그걸 다 보낼 것인가? 가장 심각하게 걱정되는 것은 원형 링크드리스트를 생각해보자. 끝이 없을 것이 아닌가? 이것도 엄청
머리가 아플 것임을 알 것이다. 나중으로 미루자..ㅋㅋ (귀찮은 건 지금 다 나중으로 미루고 있다. 나중에 정말 이것을 다 하게 될지도
의문이다. 아무래도 괜히 시작했다는 느낌이 든다. 아예 말을 안 꺼내고 대충 넘어갈 걸 그랬나?)

여기서 마샬링의 전체적인 기본 메커니즘을 살펴보자. 이 부분이 가장 중요하다.

클라이언트는 CoGetClassObject를 실행하여 원격 서버를 실행하고, 원격 서버는
CoRegisterClassObject함수를 통해 마샬링을 시작하게 된다. 이 과정을 통해 일단 서버의 IClassFactory가 클라이언트에
넘겨진다.

좀더 자세히 살펴보자.

CoRegisterClassObject안에서 COM은 객체에게 클라이언트 프로세스에 포함될 프록시의 CLSID를
요구한다. 만일 객체가 CLSID를 제공하지 않을 때는 COM은 표준 마샬링 프록시를 사용한다.

COM은 객체에게 마샬링 패킷을 요구한다. 마샬링 패킷은 프록시가 객체와 연결할 때 필요한 정보들을 담고 있다.
객체가 제공하지 않으면 역시 COM은 표준 패킷을 사용한다.

COM은 프록시 CLSID와 마샬링 패킷을 클라이언트에 넘긴다.

클라이언트의 프로세스에서 COM은 1에서 얻어진 CLSID로 프록시를 생성하고, 2에서 얻어진 마샬링 패킷을
가져온다.

이제 프록시는 클라이언트가 CoGetClassObject에서 요구한 인터페이스의 포인터를 넘긴다. 클라이언트는 이
포인터(보통 IClassFactory)로 실제 객체를 생성할 수 있다.

1,2과정은 CoMarshalInterface함수가 담당하고, 3과정은 Service Control
Manager가 담당한다. 4,5과정은 CoUnmarshalInterface가 담당한다.

이제는 정리할 시간이다.

마샬링이 하는 역할은 결국 원격 컴퓨터에 또는 다른 프로세스공간에 있는 COM 서버를 자신의 공간 안에 있는
것처럼 사용하게 해주는 메커니즘이다. 그러기 위해서는 클라이언트의 주소 공간안에 인터페이스의 v-table을 재생성해야 한다. 그리고 이 역할을
프락시가 한다.

그러면, 클라이언트에서는 프락시를 호출할 때 프락시는 스텁과 통신하고 스텁을 개체에 있는 실제 호출을 할 것이다.
그리고 여기서 프락시와 스텁의 통신은 RPC을 사용할 것이다.

아직 잘 모르겠다고? 사실 나도 더 이상 어떻게 설명할 방법이 없다. 나의 한계이다. 더 공부가 고픈 사람은 책을
사서 보기 바란다. COM 관련 도서가 그렇게 많지는 않지만, 그래도 몇몇 책은 꽤 볼만하다.(참고로, 난 책장수가 아니다.)

총정리를 할 겸해서 다음 그림을 보면서 전체적인 윤곽을 머리에 넣어보자. 대충 보면 알 것 같고 앞에서 다
설명한 것들이니 따로 설명은 하지 않겠다.

 

 

< Clients always call in-process code; objects are always
called by in-process

code. COM provides the underlying transparent RPC. >

그림의 글자가 잘 안 보이는 사람은 그림을 확대해보길 바란다. 나도 잘 안 보인다. 확대하니깐 보이던데
여기서는 지면 관계상 확대할 수 없다. 다들 마우스로 그림잡고 드래그 한번 해봐라. 심심하지도 않고 재미 있잖아~~~~

복잡하다고 생각되면 다음 그림처럼 쉽게 이해해도 된다.

 

< Components of COM’s distributed architecture >

결국 마샬링 하나를 가지고 하나의 장이 끝나 버렸다. 에겅~~~ 언제 이 많은 것을 다 다룰지 막막하기만
하다. 왜 이렇게 진도가 안 나가는 것일까? 여러분은 어떤 것이 더 좋은가? 그냥 알아들을 정도로만 설명하고 빨리 COM을 끝내는 것이 좋은가?
아니면 하나하나 자세히 알아보면서 COM을 끝내는 것이 좋은가? 이제는 조언이 필요하다. 어떻게 나아가야 할지 길을 잃은 느낌이다. 난 솔직히
후자가 좋긴 하다. 하지만, 기간이 오래 걸리는 만큼 부담 역시 커진다. 전자의 경우 부담은 적겠지만, 이 강좌를 할 의미가 조금은 퇴색될 듯
싶다. 왜냐하면, 전자의 경우 대부분의 책이 지향하는 바니깐 말이다. 전자의 경우는 책을 읽는 것이 훨씬 도움이 될 듯 싶기도 하다.
어쨌든 말도 많고 탈도 많은 COM 공부 하시느라 오늘도 정말 수고들 하셨다. 다시 한번 강좌가 늦어지는
점에 대해 사과를 한다. 옛날 같으면 어림도 없는 일이다. 그냥 내가 하고싶을 때 하면 그만이기 때문이다. 그런데, 내가 조금은 변한 것 같다.
왜일까? ㅋㅋ 알아서들 생각하기 바란다.

그럼 다음강좌에서 보자.

 

 

세상이 공평하다고 생각하십니까?

요즘은 자꾸 회의가 드는군요. 누구는 좋은 회사 들어가서 돈 많이 받으면서 편하게 생활하고 누구는 박봉에 거의
밤새다시피 일하고, 개인적으로 저는 중간쯤에 끼어 있는 것처럼 느껴집니다만, 많은 프로그래머들이 제 밥그릇 못 찾아 먹는 걸 볼 때마다 왜 화가
나는지 모르겠습니다. 이만한 노가다 직종도 없는데 말입니다. 프로그래머라는 직업이 남들한테는 좋아보일지 모르겠지만, 아시는 분은 다 아시다시피,
정말 피곤한 직업입니다. 왜 프로그래머는 대접을 받지 못하는 걸까요? 정말 노가다 직장이라서 그럴까요? 별다른 기술 없이 시간과 몸으로 떼우는
직업이라서?

왜 프로그래머가 되려고 그렇게 공부했을까요.

 

후~~우~~~~~~~~ 한숨이 절로 나옵니다. ㅜㅜ;;

 

그래도 내일을 또다시 찾아오겠죠.

아무리 삶이 그대를 속일지라도 내일도 모두들 즐겁게 보내길..

Leave a Reply

Your email address will not be published. Required fields are marked *