SimpleIsBest.NET

유경상의 닷넷 블로그
이 글은 오래된 전에 작성된 글입니다. 따라서 최신 버전의 기술에 알맞지 않거나 오류를 유발할 수 있습니다. 저자는 이 글에 대한 질문을 받지 않을 것입니다. 하지만 이 글이 리뉴얼 되면 이 글에 대한 질문을 하거나 토론을 할 수도 있습니다.

스마트 클라이언트 시리즈 여덟 번째 글입니다. 어느새 글이 이렇게 길어져 버렸네요. 힘 닫는 데까지 써 볼 랍니다. 시리즈는 아마 10편까지 되지 않을까 싶네요. 여러분의 성원(?)에 감사드립니다. 요즘엔 프로젝트가 너무 바빠서 글쓰는데 시간 내기가 더 어려워져서... 귀차니즘은 어느 정도 물러갔는데... 프로젝트가 제 발목을... (핑계 없는 무덤이 어딨다더냐... -_-;)


시리즈 목차

Smart Client (VIII) : Assembly Deployment (1)

스마트 클라이언트 시나리오에 의해 어플리케이션을 개발하다 보면 항상 걸리는 것이 어셈블리(DLL)의 버전 문제에 걸리곤 한다. 이놈의 것이 어떤 때는 새로운 DLL(새로 수정하여 컴파일 한 DLL)을 잘 다운로드 받는 것 같다가 어떤 때는 새 DLL을 받지 못하고 이전 DLL만 화면에 나타난다는 등의 현상이 있는가 하면, 항상 DLL이 다운로드 되는 듯한 현상도 나타난다는 것이다. 스마트 클라이언트의 버그일까?

스마트 클라이언트에 대한 자료를 열나게 뒤지고 돌아다니다 보면, 혹자는 버그라고 말하기도 하고 혹자는 버전에 무관하게 DLL의 날짜만 본다는 사람도 있고 의견도 가지가지 이다. 이들의 말들은 대부분 틀렸거나 일부만 맞는 것이다. 이제부터 스마트 클라이언트 상황에서 어셈블리(DLL)가 다운로드 되고 수행되는 상황을 정확하게 살펴보도록 하겠다. 필자가 여기서 설명하는 것은 필자가 1년이 넘도록 스마트 클라이언트 관련 프로젝트를 진행하면서 졸라 삽질하고 맨땅에 헤딩 해서 깨우친 노하우이다(졸라 빡셌다... 줸~장). 사실 MSDN을 아무리 디비 보아도 이러한 내용을 설명하는 글은 없다. 왜 이러한 자료가 MSDN에서 조차 없는지는 간단하다. 스마트 클라이언트의 기본 원리와 닷넷 프레임워크의 기본 작동 방식이 그러하기 때문이다. 결론부터 밝히자면 이렇다.

"<OBJECT> 태그 혹은 링크에 의해 다운로드 되는 어셈블리는 버전에 상관 없이 DLL의 날짜에 의해 다운로드 여부가 결정되며, 그 외의 DLL은 기본 어셈블리 바인딩 규칙에 의해 처리된다. 끝 !!"

결론은 이것이다. 명확하지 않은가? 그런데 왜? 새 DLL이 다운로드 되지 않는 현상이나 매번 DLL이 다운로드 되는 듯한 현상이 보이는 것일까? 그것은 개발자가 스마트 클라이언트의 구동 원리를 정확히 이해하지 않았고, 또한 닷넷의 어셈블리 바인딩 규칙에 대해 정확히 알지 못해서이기 때문이다. 닷넷을 탓하기 전에 스스로를 탓할지어다... -_-;

이번 포스트에서는 스마트 클라이언트의 최초 어셈블리가 날짜에 의해 다운로드 되는 원리를 살펴보고 관련된 문제 해결 방법을 살펴보도록 하겠다. 그리고 다음 포스트에서 스마트 클라이언트 시나리오에서 발생할 수 있는 추가적인 어셈블리 배포에 대해 살펴보도록 하겠다. 한 포스트에 다루기에는 내용이 너무 많은 데다가, 글이 길어지면 또 필자 특유의 게으름과 귀차니즘이 창궐하기 때문이다. 독자들도 이미 필자의 게으름과 귀차니즘은 이미 익숙해 졌으리라 생각하는 바이다.

Downloading First Assembly

스마트 클라이언트 시나리오에서 최초로 로드 되는 어셈블리라면 두 가지를 생각해 볼 수 있다. 브라우저 임베디드 스마트 클라이언트인 경우 <OBJECT> 태그에 명시된 어셈블리이며, 독립 스마트 클라이언트라면 <A> 태그 혹은 URL 바로 가기에 명시된 EXE 어셈블리를 말한다. 스마트 클라이언트의 작동원리에서 밝힌바 대로 스마트 클라이언트는 MIME 필터에 의해 작동된다는 것을 잊지 않았다면, 이제 잘 생각해 보자.

MIME 필터라 함은 일단 클라이언트(브라우저)에 다운로드 된 콘텐트에 대해 작동하게 될 것이다. 다운로드도 안 된 상황에서 IE 브라우저가 용가리 통뼈도 아니고 어떤 MIME 타입인가 어찌 알겠는가? 짱구가 아닌 담에야 이해가 갈 것이다. 그렇다면 스마트 클라이언트 시나리오에서 최초로 로드 되는 어셈블리는 죽으나 사나 다운로드 되어야만 스마트 클라이언트가 구동되게 되는 것이다 ! 아니 이런 C8... 그렇다면 매번 어셈블리를 다운로드 받는다면 스마트한 클라이언트가 아니지 않은가? 그렇다. 지금까지 필자가 쑛 뺑이 치면서 구라를 풀어온 스마트 클라이언트는 생각만큼 스마트 하지 않다.

하지만 닷넷 스마트 클라이언트의 이런 구린 상황을 브라우저가 어느 정도 커버해 준다. 무슨 얘기인고 하니, 무조건 스마트 클라이언트가 사용하는 최초의 어셈블리를 무조건 다운로드 하지 않을 수 있다는 것이다. 이는 브라우저와 웹 서버가 HTTP 프로토콜에 의거하여 캐시를 수행하기 때문이다. 즉, 브라우저에 의해 스마트 클라이언트 시나리오의 최초 어셈블리(DLL 혹은 EXE)를 다운로드 받은 후 이것을 캐시 하기 때문에 다음 번의 스마트 클라이언트 구동 시 브라우저에 의해 캐시 된 어셈블리를 로드 할 수 있기 때문이다. 이렇게 브라우저 캐시 사용 이후에 MIME 필터가 작동하기 때문에 이러한 캐시가 가능하게 됨은 당연 빤쑤 되겠다.

그렇다면 IE 브라우저는 닷넷 어셈블리에 대한 어떤 인식이 있어서 캐시를 하는 것일까? 인식은 무슨 얼어 죽을 인식... 브라우저는 닷넷 어셈블리를 전혀 인식하지 못한다. IE 브라우저에게 있어서 다운로드 되는 닷넷 어셈블리는 단순한 이미지 파일과 다를 것이 하나도 없는 단순한 웹 콘텐트일 뿐이다.

여기서 브라우저와 웹 서버가 캐시 하는 메커니즘(요게 표준말이란다...)에 대해 아주 아주 간단히 알아보자. 브라우저가 어떤 콘텐트를 다운로드 하기 위해서는 일단 자신의 캐시를 디비 보게 된다. 만약 동일한 콘텐트가 캐시에 존재하는 경우, If-Modified-Since 라는 HTTP 헤더와 If-None-Match 헤더 등을 통해 웹 서버에게 자신이 캐시하고 있는 콘텐트 정보의 날짜와 E-Tag(entity-tag; 날짜에 의한 캐시의 단점을 보완하기 위해 콘텐트에 붙여진 태그)를 전송한다. 웹 서버는 브라우저가 전송한 이러한 정보를 통해 자신이 가지고 있는 콘텐트의 날짜와 및 E-Tag를 비교하여 서버의 콘텐트에 변화가 없으면 콘텐트를 다운로드 해주지 않고 304 NOT MODIFIED 결과 코드를 반환한다. 물론 304 Not Modified 결과를 담은 HTTP Response는 달랑 HTTP 헤더만이 존재할 뿐 실제 콘텐트는 담고 있지 않다. 브라우저가 304 결과를 수신하면 브라우저 캐시에 존재하는 콘텐트를 사용하게 되는 것이다. 이렇게 함으로써 매번 콘텐트를 느린 네트워크 상에서 다운로드 받지 않고 빠르게 콘텐트를 액세스할 수 있는 것이다.

스마트 클라이언트 시나리오의 최초 어셈블리는 정확하게 이러한 메커니즘에 의해 매번 어셈블리를 다운로드 받지 않을 수 있게 되는 것이다. 방금 설명한 HTTP 캐시 외에 웹 서버 상에서 콘텐트의 만료 시간(expiration time)을 지정함으로써, 주어진 기간 동안 브라우저가 콘텐트(스마트 클라이언트의 최초 어셈블리)를  다운로드 시도 조차 하지 않도록 할 수도 있지만 상세한 설명은 생략하겠다(장단점이 존재한다. 궁금하지? 메~~렁~~).

어찌 되었건 브라우저와 웹 서버의 쑈부에 의해서 최초의 어셈블리는 다운로드 될 수도 있고 그렇지 않을 수도 있다. 다운로드 여부를 결정하는 것은 순전히 브라우저와 웹 서버의 설정에 의해 결정된다는 것이다. 브라우저에서 캐시를 꺼버리거나 웹 서버가 전혀 캐시를 하지 않도록 설정되어 있다면 최초 어셈블리는 무조건 다운로드 될 것이다. 하지만 대개의 경우 브라우저도, 웹 서버도 캐시를 사용하므로 많은 경우 최초 어셈블리가 변경되지 않는다면 304 Not Modified 가 웹 서버로부터 반환될 것이고 브라우저는 캐시 된 어셈블리를 사용하게 될 것이다.

어셈블리의 변경 여부를 결정하는 것은 어셈블리의 버전도 아니고 어떤 특별한 메커니즘이 존재하거나 특정 알고리즘이 있는 것이 아니다. JPG, GIF 파일과 같은 이미지 파일이 다운로드 여부를 결정하는 것과 동일하게 스마트 클라이언트의 최초 어셈블리는 어셈블리 파일(DLL 혹은 EXE)의 날짜에 의해 다운로드 여부가 결정되게 된다. 물론 파일의 크기 역시 영향을 미칠 수 있지만 파일의 크기가 바뀌었다는 얘기는 파일의 변경 날짜가 변경되었다는 말과 동등하므로 쉽게 파일 날짜에 의해 어셈블리의 다운로드 여부가 결정된다고 보면 되겠다.

Simple Test

말로만 하면 잘 이해가 안 가므로 간단한 테스트를 해보자. 정확한 테스트를 위해 먼저 브라우저 캐시를 깨끗이 지운다. 브라우저의 도구 > 인터넷 옵션 메뉴를 선택하고 일반 탭에서 "파일 삭제" 버튼을 클릭하면 된다(화면 1 참조).


화면1. 브라우저 캐시 삭제

이제 우리의 멋진 유틸리티인 Fiddler를 구동시키고 필자의 브라우저 임베디드 스마트 클라이언트 예제 URL을 수행 시켜 보자.

http://www.simpleisbest.net/Apps/SmartClientBasic/HostPage2.aspx

Fiddler는 화면 2와 같은 결과를 보여줄 것이다. 사용자마다 결과가 조금씩 달라질 수 있지만 중요한 부분은 <OBJECT> 태그에 의해 참조된 최초 스마트 클라이언트 어셈블리인 ClientModule.DLL 이 다운로드 된 상황을 살펴보아야 한다(다른 부분은 무시해 줬으면 하는 소망이 있다). 일단 HTTP 결과 코드는 200 OK 이다(붉은색 사각형으로 강조). 200 OK 는 웹 서버가 브라우저에게 콘텐트, 즉 어셈블리 파일을 다운로드 해주었음을 나타낸다. HTTP Response 헤더를 살펴보면 (하늘색 사각형으로 강조) 32KB 정도의 DLL 이 다운로드 되었고, 다운로드 된 콘텐트를 브라우저가 캐시 하는데 사용하라고 서버 콘텐트의 최종 변경 날짜(Last-Modified 헤더)와 E-Tag (ETag 헤더)가 명시되어 있다. 브라우저 캐시를 삭제 했기 때문에 ClientModule.DLL 어셈블리가 무조건 다운로드 되었음에도 주의하자.


화면2. 브라우저 캐시가 없는 상황에서 스마트 클라이언트 액세스

이제 브라우저를 닫고 (반드시 브라우저를 닫아야 한다. 이유는 나중에 설명하겠다.) 다시 브라우저를 새로 기동하고 동일한 URL을 액세스 해보자. Fiddler는 화면 3과 같은 결과를 보여줄 것이다.


화면3. 브라우저 캐시가 있는 상황에서 스마트 클라이언트 액세스

화면 3에서 ClientModule.DLL를 브라우저가 다운로드 하기 위해 웹 서버로 전송한 HTTP Request를 살펴보자(하늘색 사각형으로 강조). HTTP 헤더에 If-Modified-Since 와 If-None-Match 를 명시하여 앞서 브라우저가 웹 서버로부터 캐시를 위해 받은 정보를 그대로 웹 서버로 전송하는 것을 알 수 있을 것이다. 즉, If-Modified-Since 헤더가 명시한 날짜와 If-None-Match 헤더가 명시한 E-Tag를 가진 콘텐트를 브라우저가 캐시하고 있다는 것을 웹 서버에 알리는 것이다. 웹 서버는 이 정보를 통해 서버의 콘텐트의 날짜 및 E-Tag를 비교하여 변화가 있는 경우 200 OK 결과와 더불어 변경된 콘텐트를 다운로드(화면 2처럼)해 줄 것이고, 변경이 없다면 화면 3 처럼(붉은색 사각형으로 강조) 304 Not Modified 결과를 반환하게 된다. 물론 304 Not Modified 결과는 실제 콘텐트를 담지 않고 HTTP 헤더만이 존재한다. 304 Not Modified 결과를 받은 브라우저는 자신이 캐시 한 콘텐트를 사용하게 된다. 이 말은 곧 로컬 브라우저 캐시에 있는 ClientModule.DLL 파일이 <OBJECT> 태그에 사용되어 진다는 말이며, 스마트 클라이언트의 핵심 모듈인 MIME 필터가 처리하게 될 파일 역시 브라우저 캐시에 존재하는 ClientModule.DLL 이라는 것이다.

이러한 작동 방식은 이미지 파일이나 정적 HTML 파일(.htm)과 같은 웹 콘텐트와 완전히 동일한 방식이며, 브라우저 임베디드 스마트 클라이언트 이건 독립 스마트 클라이언트 이건 스마트 클라이언트 시나리오에서 사용되는 최초의 어셈블리는 동일한 방식으로 다운로드 여부가 결정된다.

SmartClient Assembly Downloading Rule of Thumb #1

규칙을 다시 정리해 보자면 이렇다. 스마트 클라이언트의 구동은 MIME 필터에 의해 수행된다. 그리고 MIME 필터는 웹 브라우저가 다운로드 한 콘텐트에 대해 작동하므로 스마트 클라이언트 시나리오에서 <OBJECT> 태그에 명시된 어셈블리나 <A> 태그 혹은 URL 바로가기에 의해 명시된 어셈블리(최초 어셈블리)는 일단 다운로드를 시도한다. '시도' 한다는 말은 브라우저(닷넷 프레임워크가 아니다)가 자신의 캐시 상황에 의해 웹 서버에 다운로드를 요구하는 HTTP GET 요청이 날아갈 수도 있다는 말이다. 이러한 작동 방식은 스마트 클라이언트의 최초 어셈블리가 Strong Name 서명이 되어있건 버전이 바뀌었건 무관하게 수행되는 현상이다.

이러한 것이 복잡하게 느껴진다면 간단한 규칙을 알려주도록 하겠다. 규칙은 이렇다.

브라우저의 캐시에 존재하는 어셈블리보다 최신 날짜 및 시간의 어셈블리가 존재한다면 이것이 다운로드 되고 스마트 클라이언트로서 구동되게 되며 그렇지 않은 경우, 브라우저 캐시의 어셈블리가 사용된다.

이상 ! 간단하지 않은가? 아님 말고... -_-;

두 번째 규칙은 글의 서두에서 이야기 했듯이 스마트 클라이언트 시나리오에서 최초의 어셈블리가 로드 된 후의 어셈블리 다운로드는 닷넷 프레임워크의 어셈블리 바인딩 규칙을 그대로 따른다. 이에 대한 상세한 내용은 다음 포스트에서 구라를 풀기로 하고 넘어가도록 하자. 궁금하더라도 쬐끔만 참아달라는 염치없는 요구를 함 해본다.

Trouble Shooting

자... 이제 이러한 원리를 잘 인지한 사항에서 스마트 클라이언트 시나리오에서 새 버전의 어셈블리가 다운로드 되지 않거나 어셈블리가 항상 다운로드 되는 현상을 해결하는 방법을 살펴보도록 하자. 상세 설명을 하기 전에 앞서 언급한 규칙을 잘 음미해 보면, 스마트 클라이언트의 최초 어셈블리를 다운로드 하느냐 마느냐는 순전히 웹 서버와 브라우저의 콘텐트 캐시 설정에 달려있다는 것을 알 수 있을 것이다. 따라서 문제가 발생하면 브라우저 및 웹 서버의 캐시 설정이 어떠한가 살펴볼 필요가 있다.

역시 이러한 문제를 해결하는 가장 좋은 도구는 Fiddler 이다. Fiddler를 이용하여 브라우저가 어셈블리에 대한 다운로드 요청(HTTP GET Request)을 수행하는지 잘 감시해야 한다. 브라우저가 어셈블리에 대한 다운로드 시도를 하지 않는다면, 웹 서버가 콘텐트 만료(expiration)를 지정해 놓았을 수도 있다. IIS의 경우 화면 4와 같이 디렉터리/파일에 대해 콘텐트 만료 지정을 할 수 있는데, 이렇게 만료 시간이 지정된 콘텐트는 주어진 시간 동안 브라우저에 의해 캐시되며 만료 시간이 경과될 때까지는 웹 서버에게 새로운 콘텐트가 존재하는지 물어보지도 않는다. 즉, 만료가 지정된 콘텐트에 대해서는 만료 전까지 HTTP GET/POST 요청이 전혀 발생하지 않는다는 것이다. 이는 곧 브라우저에 의해 캐시 된 어셈블리가 만료 시간이 될 때까지 다운로드 되지 않는다는 것을 의미한다.


화면4. IIS의 콘텐트 만료 지정

비슷하게 브라우저의 캐시 설정(임시 인터넷 파일 설정)이 화면 5와 같이 '확인하지 않음'으로 되어 있다면 이 역시 브라우저가 항상 캐시 된 어셈블리를 사용하게 되므로 웹 서버의 어셈블리가 새로이 갱신되었더라도 다운로드가 이루어 지지 않는다. Fiddler로 이 상황 역시 확인이 가능하다.


화면5. 브라우저의 캐시(임시 인터넷 파일 -_-;) 설정

이외에도 다양한 상황이 존재할 수 있다. 웹 서버와 클라이언트의 시간 설정이 달라서 어셈블리가 전혀 다운로드 되지 않거나, 매번 다운로드될 수도 있다. 또한 웹 서버의 설정상 브라우저가 캐시를 못하여 어셈블리를 매번 다운로드 할 수도 있다. IIS의 경우 Windows 2003 SP1이 나오기 전에는 버그가 존재해서 콘텐트가 전혀 변경되지 않았음에도 불구하고 E-Tag(앞서 간단히 설명했다)가 바뀌어서 브라우저가 매번 어셈블리를 다운로드 하는 현상이 발견되기도 한다.(Windows 2003에 대한 서비스 팩 1은 웬만하면 재깍 설치하자.)

모든 상황을 다 열거 할 수 없음을 독자는 이해해 주기 바란다. 아무튼 스마트 클라이언트의 최초 어셈블리가 예상대로 다운로드 되지 않거나 항상 다운로드 된다면, Fiddler로 그 상황을 모니터링 해 보고 브라우저의 설정이나 웹 서버의 설정을 의심해 보기 바란다. 물론 무턱대고 의심만 하지 말고, 앞서 필자가 설명한 규칙(?)을 잘 음미해야 할 것이다.

What's Next

스마트 클라이언트 시나리오에서 닷넷 어셈블리들이 배포되는 상황에 대해 몇 마디 구라를 풀어봤다. 다음 포스트에서는 스마트 클라이언트의 최초 어셈블리가 로드 된 이후에 추가적으로 로드 되는 어셈블리, 즉 최초 어셈블리가 직/간접적으로 로드 하는 어셈블리들은 어떻게 클라이언트까지 다운로드 되는지 살펴보도록 하겠다. 원리를 상세히 설명하면 이번 포스트 보다 복잡한 설명이 되겠지만, 원리 부분을 간략(?)하게 설명하고 나타나는 현상만을 지적하면 그다지 어려울 것도 없다. 언제 다음 포스트가 나올지 모르겠지만... 개봉 박두... -_-;



Comments (read-only)
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / 위시 / 2006-08-07 오후 3:11:00
"또 필자 특유의 게으름과 귀차니즘이 창궐하기 때문이다. 독자들도 이미 필자의 게으름과 귀차니즘은 이미 익숙해 졌으리라 생각하는 바이다."


으하하..쥔장님의 유머도 날로 늘어나시는듯 합니다..항상 좋은 글 감사합니다.. 이런글이라면 귀차니즘쯤이야..얼마든지
감수합니다..^^ Best FavoriteSite ^^
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / 블로그쥔장 / 2006-08-07 오후 3:29:00
항상 와서 읽어 주시고 한마디씩 남겨주시는 위시님께 감사드립니다...
제겐 위시님 같은 분의 한마디 글이 귀차니즘을 극복하는데 큰 도움이 된답니다.

^^
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / masoman / 2006-08-07 오후 10:20:00
조엘과는 다른 차원의 블로그 책을 내 보심이 어떠실런지 ㅎㅎ
글 잘 읽었습니다. ^^
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / 매버릭 / 2006-08-08 오후 9:01:00
이번 3월달에 VS2005와 .NET FW 2.0 가지고 그럭저럭 StandAlone 방식의 프로젝트를 끝냈었는데....
그전에 여길 알게됐다면 얼마나 많은 도움이 되었을까... 아쉬움이 남네요....
일정에 쫒겨 어떻게든 구현만 시켜놓고 말았는데.... 쥐장님 글보고 많이 부끄럽고 공부많이 하고 갑니다....
언제 다시 Smart Client 프로젝트를 할진 몰라도 그때 되면 또 자주 들러야 할듯 싶습니다....
8편까지 쓰시느라 엄청 고생많으셨구요..... 이후 내용이 있다면 쭉~~~ 연재가 되길 소망해 봅니다....

글 잘~~ 읽었습니다~~~
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / 김한수 / 2006-08-14 오전 9:29:00
항상 좋은 글 보고있습니다. 스마트 클라이언트 배포하면서 매번 신경써야 했던 부분인데, 많은 도움이 되었네요.
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / 고무신 / 2006-08-16 오전 11:45:00
지난 금욜 우연히 이 사이트를 방문하고
스마트 클라이언트에 관련한 글을 주말 동안 쭈~욱 다 읽어 보았습니다.
참으로 고마운 글... 그 쥔장의 신상이 궁금하여 컨텍어스를 눌러보고 연세(?)를 보니
역시 기술적으로 농 익을 시기이시기에
이런 글을 쓸 수 있었겠다 싶더군요.

"쌉질","맨땅","쥐랄"..... 저 역시 쥔장보다 적은 나이는 아니지만
한때 DCOM을 국내 처음 프로젝트에 적용하면서 겪었던 일들이 새쌈 다시 생각나더군요.
그후 자바로 전환했다가 2년전부터 다시 닷넷에 관심을 가지게 되었습니다.

다시 한번 좋은 글, 고마움을 전하며
쥔장의 무궁한 발전과 건승 기원드립니다.
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / 리키 / 2006-09-08 오후 5:45:00
여기 방문하고 처음 글 남겨봅니다. 쥔장분의 피와땀이 들어간 정말 주옥같은 정보들 감사합니다.

나중에 묶어서 책으로 내셔도 좋을듯..^^ 근데 이런거 다 알려주면 쥔장은 뭐먹고 사시나요? ^^
#re: 스마트 클라이언트, 그것을 알려주마 (VIII) : Assembly Deployment (1) / hwchul / 2007-02-10 오전 9:03:00
이글을 읽기위해 놀토 6시에 일어나게 해주셔서 감사합니다.
지금 9시인데 졸리기 시작하네요~~~ ^^"
책으로는 안내시나요?? 기대 10000빵 입니다~