Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

XMLHTTP 멀티 관련.. (11월 4일 김기룡님의 질문)

475 views
Skip to first unread message

김주현

unread,
Nov 8, 2003, 4:28:13 PM11/8/03
to
먼저 답변이 많이 늦었네요~
저도 비동기처리를 직접 해본적은 없어서 이것 저것 테스트하다보니... 쩝~

[김기룡님의 원래 질문]

안녕하세요.
사이트별 응답시간이 늦어서 응답제한 시간을 이용하기 위해

set HTTP = Server.CreateObject ("MSXML2.ServerXMLHTTP.4.0")
처럼 ServerXMLHTTP를 사용하여

HTTP.setTimeouts 를 이용하여 응답시간 제한을 설정한뒤
Http.Open "GET", URL, False
과 같은 식으로 해서 동기방식으로 처리하였는데 문제가 생겼습니다-_-

우선 처리할 사이트 목록이 DB에 있는데...
Http.Open "GET", URL, False
처럼 동기방식으로 하면 사이트를 모두 처리하는데 처리속도가 너무 늦네요--

뒷부분의 인자를 True로 설정해서 비동기 방식으로 처리하고자 하는데
머리가 딸리는군요-_-


필요한 건...
해당 사이트를 제대로 처리하였는지의 200, 404등과 같은
사이트응답코드와 해당 URL의 HTML 내용이 필요합니다.

이런걸 처리하면서 멀티로 동작 시키려면 어떻게 해야 하는지요?
영어가 딸려서 한달가량 시도하다 포기하고 질문 드립니다-_-

많은 도움 부탁드립니다^^;


[답변]

먼저... 특정 URL에 대한 요청이 제대로 처리되었는지를 확인하시려면
status라는 프라퍼티를 사용하시면 됩니다.
간단하게 예를 들어보면...

Set poster = Server.CreateObject("MSXML2.ServerXMLHTTP.4.0")
poster.Open "GET", URL, False
poster.Send
Response.Write(poster.status)

단, 주의하실 사항 한가지!!!
status 프라퍼티는 반드시 Send 메소드가 성공적으로 수행되어진 다음부터
사용가능합니다.
즉, Send 메소드를 호출하기전에 status 프라퍼티를 읽으려하면 에러가
발생합니다.


그 다음... ServerXMLHTTP 객체의 동기/비동기처리에 대한 이야기를
해보겠습니다.

먼저 동기적으로 처리한다는 말의 구체적인 의미는...
Send 메소드에 대한 리턴이 즉시 돌아오는것이 아니라
응답이 완전히 도착하거나 타임아웃에 의해 정상적으로 응답을 받지 못할때까지
기다린 다음에
Send 메소드에 대한 리턴이 돌아온다는 것을 의미합니다.

그리고 비동기적으로 처리한다는 말의 구체적인 의미는...
동기적으로 처리할때처럼 요청을 받은 서버에서 응답이 올때까지 기다리는게
아니라
Send 메소드가 호출되자마자 즉시 리턴이 돌아오는 것을 의미합니다.
따라서, 비동기적으로 Send 메소드가 호출되고 나면
응답이 도착하지 않더라도 곧바로 다음 루틴이 실행되어지게 되지요.

그렇다면... 비동기적으로 Send 메소드를 호출할 때에는 어떠한 방식으로든
특정 요청에 대한 응답이 도착했다는 것을 알 수 있는 방법과
응답이 도착했을때의 어떻게 처리하라는 루틴을 지정할 수 있는 방법이
필요하겠죠?

먼저 특정 요청에 대한 응답이 도착했다는 것을 알 수 있는 방법은
ServerXMLHTTP 객체의 readyState 프라퍼티를 사용하면 됩니다.
readyState 프라퍼티는 ServerXMLHTTP 객체의 현재 상태를 알 수 있는
프라퍼티로서,
동기, 비동기에 상관없이 모두 사용할 수 있고
객체의 상태에 따라 다음과 같은 5가지의 숫자값을 가집니다.

(1) 0 [UNINITIALIZED] : The object has been created but has not been
initialized because the open method has not been called.
(2) 1 [LOADING] : The object has been created but the send method has not
been called.
(3) 2 [LOADED] : The send method has been called and the status and headers
are available, but the response is not yet available.
(4) 3 [INTERACTIVE] : Some data has been received. You can call responseBody
and responseText to get the current partial results.
(5) 4 [COMPLETED] : All the data has been received, and the complete data is
available in responseBody and responseText.

즉, readyState의 값을 체크해보아서 4 가 되면 응답이 완전히 도착했다는 것을
알 수 있게 됩니다.

다음으로 readyState 값이 4일때 어떻게 처리하라는 루틴을 지정하는 방법이
필요한데 이것은...
ServerXMLHTTP에 있는 onreadystatechange라는 프라퍼티를 사용하면 됩니다.
이 프라퍼티는 readyState 프라퍼티의 값이 변경될때 발생되어지는
이벤트에 대한 핸들러를 지정하는데 사용하는 것인데...
안타깝게도 이 프라퍼티를 지정할 때에는 VBScript를 사용할 수 없고
현재는 JScript에 대해서만 지원하고 있습니다.

자... 이제 지금까지 지루하게 설명한 것을 토대로
ServerXMLHTTP의 비동기 처리에 대해서 간단하게 예를 들어겠습니다...

<< AsyncTest-1.asp >>
<%@ Language="JScript" %>
<%
var poster = new ActiveXObject("MSXML2.ServerXMLHTTP.4.0");
poster.onreadystatechange = readystatechange_Handler; // 이벤트 핸들러
지정
poster.open("GET", URL, true); // 비동기 처리
poster.send();

function readystatechange_Handler()
{
Response.Write("readyState = " + poster.readyState + "<br>");
if (poster.readyState == 4)
{
Response.Write("HTTP status code = " + poster.status + "<br>");
Response.BinaryWrite(poster.responseBody);
poster = null; // 메모리 해제
}
}
%>

위의 코드를 복사해서 open 메소드의 URL 부분을 원하는 URL로 수정한 다음
테스트해보면 달랑 readyState = 1 이라는 응답만이 나타납니다.
이것은 비동기적으로 send() 메소드를 호출게 되면 리턴이 즉시 발생하게 되고
위의 코드에서는 send() 메소드 뒤에 수행되어질 코드가 없기 때문에
스크립트가 곧바로 종료되기 때문인거 같습니다.
(참고로 Client-side 스크립트에서는 위와 같은 방식으로만 해도 정상적으로
처리가 되더라구요)

따라서, ASP와 같은 Server-side 스크립트 환경에서
비동기적으로 send() 메소드를 호출할 때에는
응답이 완전히 도착할때까지 기다리라고 해주어야합니다.
이때 사용하는 메소드가 waitForResponse 메소드입니다.
(참고로 이 메소드는 XMLHTTP 객체에는 없고 ServerXMLHTTP 객체에만 포함되어
있는 메소드입니다)

위의 AsyncTest-1.asp 코드를 waitForResponse 메소드를 사용하여
수정한 예는 다음과 같습니다.

<< AsyncTest-2.asp >>
<%@ Language="JScript" %>
<%
var poster = new ActiveXObject("MSXML2.ServerXMLHTTP.4.0");
poster.onreadystatechange = readystatechange_Handler; // 이벤트 핸들러
지정
poster.open("GET", URL, true); // 비동기 처리
poster.send();

var time1 = new Date();
Response.Write("first send time = " + time1.toTimeString() + "<br>");

while (poster.readyState != 4)
{

var time2 = new Date();
Response.Write("wait time = " + time2.toTimeString() + "<br>");
poster.waitForResponse(1000); // 응답이 완전히 도착할때까지 1000초간
기다려라!!!
}

function readystatechange_Handler()
{
var time3 = new Date();
Response.Write("readyState = " + poster.readyState + "; Event time = " +
time3.toTimeString() + "<br>");
if (poster.readyState == 4)
{
Response.Write("HTTP status code = " + poster.status + "<br>");
Response.BinaryWrite(poster.responseBody);
poster = null; // 메모리 해제
}
}
%>

이 코드를 가지고 테스트를 해보시면 정확히 4개의 readyState와
HTTP status code, 그리고 URL의 내용을 확인할 수 있을 것입니다.
정확히 비동기적으로 처리되는지 확인할 수 있도록
중간중간 Date 객체를 이용해서 시간을 찍어보았습니다.
(개발중에만 확인용도로 사용하면 되겠죠?)

근데... 조금 이상하죠?
이렇게 응답이 완전히 도착할때까지 기다리도록 처리하면
동기적으로 처리할때와 동일한게 아닌가라는 질문이 생기실겁니다.
ServerXMLHTTP 객체에서 동기/비동기의 차이는 단 하나!!!
응답이 올때까지 아무 일도 못하고 기다려야 하는가와(동기)
응답이 오기까지 다른 일을 할 수 있는가(비동기)의 차이뿐인거 같습니다.
(위의 두번째 코드 경우에는 응답이 오기전에 Date 객체를 생성해서 시간을
찍도록 하고 있는것처럼)

MSXML 4.0 SDK 문서에도 사실 아주 상세하게 다루고 있지 않아
하나 하나 테스트해보고 제 나름대로 내린 결론이라 명확한 용어를 사용하지 않고
"-것 같습니다"라고 말하고 있습니다.
따라서 혹시 저의 결론이 틀리다면 다른 고수분들께서
정확한 이해를 할 수 있도록 정정해주시길 부탁드립니다~ ^-^

그럼 이제 최종적으로 김기룡님이 질문하신대로
여러 URL에 대해서 비동기적으로 멀티 처리하려면 다음과 같이 하면 됩니다.

<< AsyncTest-3.asp >>
<%@ Language="JScript" %>
<%
var poster = new ActiveXObject("MSXML2.ServerXMLHTTP.4.0");
poster.onreadystatechange = readystatechange_Handler; // 이벤트 핸들러
지정
poster.open("GET", FirstURL, true); // 첫번째 URL 주소에 대해 비동기 처리
poster.send();

var time1 = new Date();
Response.Write("first send time = " + time1.toTimeString() + "<br>");

while (poster.readyState != 4)
{

var time2 = new Date();
Response.Write("first wait time = " + time2.toTimeString() + "<br>");
poster.waitForResponse(1000); // 응답이 완전히 도착할때까지 1000초간
기다려라!!!
}

poster.open("GET", SecondURL, true); // 두번째 URL 주소에 대해 비동기
처리
poster.send();

var time3 = new Date();
Response.Write("second send time = " + time3.toTimeString() + "<br>");

while (poster.readyState != 4)
{

var time4 = new Date();
Response.Write("second wait time = " + time4.toTimeString() + "<br>");
poster.waitForResponse(1000); // 응답이 완전히 도착할때까지 1000초간
기다려라!!!
}

poster = null; // 모든 URL에 대해 처리가 끝난후에 메모리 해제

function readystatechange_Handler()
{
var time5 = new Date();
Response.Write("readyState = " + poster.readyState + "; Event time = " +
time5.toTimeString() + "<br>");
if (poster.readyState == 4)
{
Response.Write("HTTP status code = " + poster.status + "<br>");
Response.BinaryWrite(poster.responseBody);
}
}
%>

실제 이러한 방식으로의 처리가 김기룡님이 처음에 의도했던대로
얼마만큼의 성능상의 향상을 가져올지는 알 수 없지만
실제로 한번 비교해보시는게 가장 정확할거 같습니다.

그럼 조금이나마 도움이 되셨기를~~


김기룡

unread,
Nov 9, 2003, 6:12:49 AM11/9/03
to
안녕하세요~
먼저 자세한 설명과 답변에 진심으로 감사드립니다.
jscript외에는 처리 방법이 없었나 보네요~^^
몇달전 힘겹게 검색해서 XMLHTTP에 대해 알아내고--
MS에서 제공되는 소스를 해봤지만 능력상.. 실행이 안되고...
멀티쪽에선 이벤트 처리를 어떻게 해야 할지 몰라서--
동기화쪽으로 했었는데....
중간에 응답이 느린 사이트가 가로막으면 좀 느리더라구요^^;

아래는 제가 그당시 찾았던 MS사이트의 관련 글과 소스입니다.

"XML 및 Exchange 2000을 사용하여 웹 응용 프로그램 개발"이라는
제목으로 올라온 설명에있던 내용인데 VBScript로 되어 있어서
ASP에서 될줄알고 해봤는데 에러 나더라구요^^
Exchange 2000과는 크게 연관이 없을듯 싶었는데...

http://www.microsoft.com/korea/msdn/library/techart/devwebapps.htm

자세한건 위 사이트를 참고하시면 될 듯 싶습니다.
XMLHTTP에 대해서 상당히 자세히 나온거 같아서
저 내용으로 공부했었거든요^^;
(결국 머리속에 든건 아무것도 없었지만....)

소스를 보면 이벤트를 getRef() 를 이용해서 설정해주던데..
getRef()가 어떤역할을 하는지 구체적으로 모르겠고...
대충 함수를 참조하는 역활로 동작하는거 같은데 능력부족...
설명글에서는 결과가 제대로 출력되는거 같은데..
제 컴에서는 이상하게 안되더라구요^^:

그래도 미련을 갖고-_- 몇주 더 메달리다 포기하고를 반복한듯--
(ㅎㅎㅎ... 같은 소스로 계속 실행하니 큰 차이는 없는듯..^^)

혹시 윗 글이 VBScript에서 도움이 될지 몰라 링크를 남겨봅니다*^^*
답변 다시한번 감사드립니다.

(추신) 지금 다시 실행하니 약간 오동작하는게 있긴하지만...
동작은하는거 같습니다.
참고로 제 컴에 스크립트5.6 버전이 설치되어 있습니다.
getREF()가 VBScript 5.5이상부터 나온건지 몰라서^^:


[이하 소스]
<script language=vbscript>
Dim Oxmlhttp
Dim xmlDoc

Sub cmdListItems_OnClick()
strURL = document.all.URL.Value
if strURL = "" then
msgbox "You must enter a " & _
"valid URL"
exit sub
end if
'Check to see if URL has HTTP://
'in the beginning
if UCASE(Left(strURL,7)) <> _
"HTTP://" then
msgbox "The application is " & _
"adding HTTP:// to your URL."
strURL = "HTTP://" & strURL
document.all.URL.Value = strURL
end if

xsldest.innerHTML = "<B>Please " & _
"wait...Loading</b>"

Set oXMLHTTP =
CreateObject("MSXML2.ServerXMLHTTP")
oXMLHTTP.Open "PROPFIND", strURL, _
True
oXMLHTTP.setRequestHeader _
"Content-type:", "text/xml"
oXMLHTTP.setRequestHeader _
"Depth", "1"
oXMLHTTP.onreadystatechange = _
getRef("XMLHTTPStateChange")

oXMLHTTP.send ("")

End Sub

Sub XMLHTTPStateChange
dim errText
if (oXMLHTTP.readystate <> 4) then
exit sub
end if
if(oXMLHTTP.status <> 207) then
xsldest.innerText = "Error, " & _
status = " & _
CStr(oXMLHTTP.status) " & _
oXMLHTTP.statusText
errText = "Error!"

else
document.all.XMLResponse. _
value = oXMLHTTP.ResponseText
if errText = "" then
document.all.XMLStatus. _
value = oXMLHTTP.status _
& " " & _
oXMLHTTP.statusText
else
document.all.XMLStatus. _
value = errText
end if
Set xmlDoc = oXMLHTTP.responseXML

xsldest.innerHTML = _
xmlDoc.transformNode _
(calxsl.documentElement)
end if
End Sub

김주현

unread,
Nov 9, 2003, 9:09:29 AM11/9/03
to
아~~~ GetRef() 가 있었군요...

GetRef()는 특정 이벤트와 함수(또는 프로시저)를 연결시켜주는 역할을 하는
함수로
스크립트 5.0 버전에서부터 지원되는 함수네요.

김기룡님의 말을 듣고 VBScript로 다시 해보았습니다. 잘 되네요~ ^-^

다음은 저의 3번째 예제를 VBScript로 다시 작성한 예입니다.

<< AsyncTestVB-3.asp >>
<%@ Language="VBScript" %>
<%


Set poster = Server.CreateObject("MSXML2.ServerXMLHTTP.4.0")

poster.onreadystatechange = GetRef("readystatechange_Handler") ' 이벤트
핸들러 지정
poster.open "GET", "http://www.naver.com", True ' 첫번째 URL 주소에 대해
비동기 처리
poster.send

Response.Write "first send time = " & Now() & "<br>"

Do While poster.readyState <> 4
Response.Write "first wait time = " & Now() & "<br>"
poster.waitForResponse(1000)
Loop

poster.open "GET", "http://www.freechal.com", True ' 두번째 URL 주소에
대해 비동기 처리
poster.send

Response.Write "second send time = " & Now() & "<br>"

Do While poster.readyState <> 4
Response.Write "second wait time = " & Now() & "<br>"
poster.waitForResponse(1000)
Loop

Set poster = Nothing ' 모든 URL에 대해 처리가 끝난후에 메모리 해제

Sub readystatechange_Handler
Response.Write "readyState = " & poster.readyState & "; Event time = " &
Now() & "<br>"
If poster.readyState = 4 Then
Response.Write "HTTP status code = " & poster.status & "<br>"
Response.BinaryWrite poster.responseBody
End If
End Sub
%>

그리고 김기룡님이 말씀하셨던 소스는 Client-Side 스크립트라서...
그런 경우에는 waitForResponse 메소드를 사용하지 않아도
비동기 처리가 정상적으로 수행이 됩니다.

하지만, 제가 직접 테스트를 해보니까 Server-Side 스크립트 환경에서는
waitForResponse 메소드를 사용하지 않으면 정상적으로 수행이 되지 않더라구요.

그럼 좋은 결과가 있기를~


"김기룡" <xfold...@hanfos.korea.com> wrote in message
news:uKszkJrp...@tk2msftngp13.phx.gbl...

0 new messages