리눅스 스트리밍 서버에 관한 솔류션 ( Linux Streaming Server Solution )

1. 기본적으로 real 은 되신다는 것을 아실 것이고

2. 미국사이트를 찾아보니 리눅스 스트리밍 전문 서비스들이 있더군요.
http://shoutcast.serverroom.us/?OVRAW=linux%20streaming&OVKEY=linux%20stream%20media%20server&OVMTC=advanced
이곳에서는 nullsoft 의 shoutcast 를 서버로 사용하더군요.
클라이언트는 윈도우미디어 플레이어대신 winamp을 사용하구요. PC, MAC, LINUX 에서 모두 사용되구요. ( http://www.nullsoft.com/ntv/publicaccess/ )
http://www.shoutcast.com/download/broadcast.phtml
가격도 저렴한편이네요. 50메가하드+30기가트래픽에 월11.99달러네요.

3. 오디오스트리밍(MP3) 는 icecast 를 가직고 하나봐요. 셋업하는 방법이 나와있네요 참고하세요.
http://www.yolinux.com/TUTORIALS/LinuxTutorialAudioStreaming.html

4 다음은 MPEG4 스트리밍에 관한 내용이고요
http://www.linuxjournal.com/article/6720

5. BYU브로드캐스팅은 TV 라디오와 웬만하게 알려진 파일들은 대부분 제어하는 것 같습니다. 
http://www.byubroadcasting.org/


6. 요즘 야후블로그의 비디오나 cj쇼핑에서 나오는 실시간방송은 한국에서 만든 건데
seevideo라는 플레이어로 dideonet.com 에서 만들었죠
샘플과 asp파일 자바스크립트 파일을 받으시려면 다음을 방문하세요.
http://www.seemedia.co.kr/
seevideo는 리눅스기반 서버에서만 사용이되고, 클라이언트는 윈도우 사용자들을 위해 개발이 되었는 데, AVI파일을 사용하고 있습니다. 기능은 메디아플레이어에 비해 훨씬 뛰어나지만 플레이중 다른 프로그램을 사용하면 시스템이 불안정해지는 것이 흠이더군요.

7. 가장 강력한 것은 프랑스에서 개발된 VLS streaming 입니다.
VLS는 그간 리눅스의 문제점으로 지적됐던 asf wmv divx avi 등을 스트리밍 할수 있으며, 제작자에의하면 별도의 미디어 서버가 필요없이 리눅스 웹서버에서 바로 작동을 한다고 합니다. VLS는 무료이며 소스가 공개되어 있습니다.
가이드 : http://www.videolan.org/doc/vls-user-guide/en/vls-user-guide-en.html
다운로드 : http://www.videolan.org/streaming/download-vls-sources.html

원문 : http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=44342&sca=%C1%A4%BA%B8&page=3

2007/06/19 15:57 2007/06/19 15:57
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

이클립스를 빠르게. Eclipse IDE Performance Tips

최근 Eclipse 유저가 Netbeans로 이동한다는 몇몇 article을 보면서 eclipse의 속도 문제 등 기사에서 제기한 문제들에 공감을 한다. 하지만 Netbeans보다는 기능의 완성도가 일부 뒤떨어지는 부분도 있지만 확장성이나 UI는 Netbeans 이상이라고 한다. 오랫동안 사용해온 이클립스의 장점은 누리면서도 답답한 속도 문제를 개선할 수 있는 방법은 없을까 이클립스 performace 최적화에 대한 기사가 있어 인용해본다.

JVM Heap memory 설정
JVM은 기본적으로 최소한의 메모리만을 사용하게 된다. 하지만 eclipse 프로젝트가 커지면 100M 이상을 사용하게 되는데 이클립스 실행시 사용할 heap 메모리 사이즈를 지정할 수 있다. eclipse.exe 실행시 -Xms128m -Xmx256m처럼 할당할 메모리를 설정해준다.

Automatic folding 죽이기
Window->Preferences->Java->Editor->Folding 옵션을 모두 해제(disable)한다. 폴딩은 에디터 내에서 코드 블록을 숨기고 펼치는 기능이다.

Automatic Code Insight 죽이기
Window->Preferences->Java->Editor->Code Assist 에서 Enable auto activation 항목을 해제(disable)한다. 자동으로 동작하는 code insight 기능은 죽였지만 ctrl+space러 여전히 code insight를 사용할 수 있다.

Close Projects
현재 작업과 직접 관련이 없는 프로젝트를 모두 닫는다. 이렇게 함으로써 이클립스가 접근하는 파일의 수를 줄여준다.

플러그인 삭제
각종 플러그인의 지원이 이클립스 사용의 혜택이긴 하지만 과도하게 많은 플러그인을 설치하는 것은 이클립스 실행시 각 플러그인들이 초기화 과정을 거치기 때문에 처음 실행시간이 오래 걸리게 된다. 사용하지 않을 플러그인이라면 설치하지 말자.

KeepResident 플러그인
메모리에 여유가 있다면 KeepResident Eclipse plugin for Windows - KeepResident Eclipse plugin 플러그인을 설치한다.
MS Windows에서 이클립스를 사용한다면 이클립스 창을 최소화(minimized)하게되면 Windows는 시스템 자원 사용을 효율화하기 위하여 이클립스의 working set의 크기를 줄여버린다. 이것은 firefox나 netbeans의 경우에도 적용된다. 문제는 최소화된 창을 복구하게 되면 장시간 garbage collection이 진행되게 되는데 이때 이클립스는 때론 몇분 동안 아무런 반응 없이 멈추게 된다. KeepResident 플러그인은 창이 최소화되더라도 working set을 유지시켜 이러한 문제를 차단해준다.

시작을 빠르게
이클립스를 종료할 때 모든 에디터를 닫는다. 이것이 귀찮다면 Window > Preferences > General > Editors > close all editors on exit 항목을 설정(enable)한다.
Window > Preferences > General > Startup and Shutdown에서, 불필요한 플러그인을 startup list에서 제외한다.

2007/06/18 01:29 2007/06/18 01:29
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 좋은 글이네요 제 블로그에 스크랩 해가도 될련지요... 허락안하시면 지우겠습니다 ^^;;

  2. 옙~ 스크랩 해 가셔도 됩니다.
    제 URL을 링크해 주시면 더욱 감사드리겠습니다. ^^

정규식을 이용한 문서 편집

문서편집이나 프로그래밍, 코딩 작업을 할때 단순 반복 작업을 할 경우들이 있다. 편집할 내용이 얼마 안된다면 빠른 손동작으로 수정을 하면 되겠지만 편집할 분량이 많은 때 손동작 만으로 편집을 하게 될 경우 몇날 몇일을 수정하고 확인해야 하는 지루한 작업이 될 수 있다. 어찌 보면 단순 반복작업인데 바꿔야할 내용도 편집할 분량도 많다면 컴퓨터 초보자에게는 난감한 일이 아닐 수 없다. 이럴 경우에 정규식 치환을 이용하는 것이 좋다. 아래 동영상은 에디트플러스(editplus)라는 편집기로 바꾸기를 할때 정규식 체크를 해서 대량의 데이타를 구미에 맞게 변환하는 모습을 보여준다. 몇자 안되는 변환식으로 몇날 몇일 했던 반복 작업을 순식간에 처리할 수 있다. 단, 편집할 내용에 적당한 규칙이 있어야 한다. 그러나 대부분의 반복작업의 경우 규칙이 있게 마련이다. 자유롭게 데이타를 바꾸는 것은 학습이 어느 정도 필요하므로 필요에 따라 정규식을 알고 있는 전문가나 개발자에게 도움을 구하는 것도 현명한 방법일 수 있다.



* 첫번째 바꾸기 변환식) ([a-z]+)\n ===> \1','
  - 배열문에 데이타를 일괄 적용할 때 응용할 수 있다.
* 두번째 바꾸기 변환식) ([a-z]+)\n ===> color_array[]='\1';\n
  - 자바스크립트나 액션스크립트에서 배열문을 만들때 응용할 수 있다.
* 세번째 바꾸기 변환식) ([a-z]+)\n ===> \1='$x_\1',\n
  - PHP에서 SQL 문을 만들때 응용할 수 있다.

처음 정규식을 접하는 분들은 어려워서 배우는 것을 쉽게 포기할 수 있다. 사람은 누구나 필요하면 하게 되 있다. 필요한 것부터 하나 하나 만들거나 배껴 쓰다 보면 어느 순간 전문 편집가가 되어 있을 것이다.
당신이 프로그래머라면 정규식, 스크립트 언어, 데이타베이스, 매크로들을 잘 조합하면 번역기 같은 고난이도 변환 프로그램도 만들수 있을 것이다.

다음 시간에는 실생활에 응용할 수 있는 다양한 정규식에 대해 다뤄보기로 하자!


원문 출처 : http://hompy.info/103
2007/06/08 16:42 2007/06/08 16:42
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

XML문서를 네트워크를 통해 전달하고자 할 경우

XML문자열을 stream으로 그냥 쓰는것 보단

  1. private static void serialize(OutputStream os, Document doc) throws IOException {
  2.     OutputFormat format = new OutputFormat(doc);
  3.     XMLSerializer serial = new XMLSerializer(os, format);
  4.     format.setIndenting(true);
  5.     serial.serialize(doc);
  6. }

와 같이 세련되게~
2007/06/07 12:35 2007/06/07 12:35
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

DB연동이 필요없는 나만의 공짜 온라인 갤러리를 가져보자!

웹상에 사진이나 이미지를 전시하기위해서는 호스팅서비스를 이용하여
계정과 DataBase공간을 할당 받아 잘 알려진 제로보드라든지 여타 게시판 혹은
갤러리기능을 수행할 수 있는 웹어플리케이션을 자신의 계정에 세팅한 후 사용 하는것이 일반적인
절차입니다.

때문에 자신의 계정을 가지고 있지 않은 많은 사람들은 포탈에서 제공하는 게시판,블로그, 혹은
사진전문 사이트 등을 활용하여 자신의 사진을 게시하고 있습니다.

오늘날의 갤러리류의 프로그램들은 DataBase에 설정사항이라든지 게시물에대한 정보를
기록 해 두기 때문에  DataBase없이는 작동을 하지 않습니다.

이 자리에서는 조금 독특한 갤러리 프로그램을 소개 하고자 합니다.
프로그램 이름은 iFoto 입니다.
우선, 아래 링크를 클릭 해 여기서 소개하고자 하는 iFoto 갤러리에대한 감을 잡아보실까요.

http://cucme.1111mb.com/gallery/ 2007.6.28. 현재 접속 불능.
http://kinnerup.com/rasmus/ifoto/

어떠세요? 뭔가 부족해 보이지만 심플함이 느껴지시죠?
화려한 기능으로 무장한 갤러리가 필요없다거나 계정을 구하고 프로그램을 세팅하여
DB와 연동 하는것 까지는 불필요하다고 생각하는 사람들에게 좋은 솔루션일 듯 합니다.

개발자 홈페이지 : http://ifoto.ireans.com/
프로그램 다운로드 : http://sourceforge.net/project/showfiles.php?group_id=160256
프로그램 구동환경 : PHP, GD2

이 프로그램을 이용하여 자신만의 갤러리를 가지기위해서 취해야 하는 행동 단계는 다음과 같습니다.
1. 갤러리 프로그램을 DownLoad 한다. ( 위의 프로그램 다운로드 경로 참조 )

2. 무료 계정을 구한다. ( 아래쪽에 설명이 이어질 것이다. )

3. 무료 계정에  FTP로 접속한다.

4. 1 에서 다운로드 받은 갤러리 프로그램을 압축을 풀어 무료계정에 업로드 한다.

5. 무료 계정에 이미지혹은 사진을 업로드 할 폴더를 만든다.

6. FTP로 사진을 업로드 한다.

7. 갤러리를 브라우저로 접속하여 업로드한 사진을 감상한다.
  ( 덧붙여 주위사람에게 자신의 갤러리를 알린다. ^.~ )

어떤가요? 전혀 복잡하지 않죠?

이제 위 순서 대로 차근차근 하나씩 진행 해 나만의 초간단 갤러리를 소유 해 보시죠.

1. 갤러리 프로그램을  DownLoad한다.
사용자 삽입 이미지

iFoto-1.0.1.zip 파일을 다운로드 한다.

사용자 삽입 이미지



2. 무료계정을 구한다.
  --> 이 부분은 이전 포스팅 '해외 무료(계정) 호스팅 소개' 편을 참조하면 된다.

3. 무료계정에 FTP로 접속한다.
자주 사용하시는 FTP클라이언트 ( 알FTP, filezilla, CuteFTP등 )를 이용하셔서
생성한 계정에 접속 합니다.
ftp 주소 : 신청한ID.1111mb.com
ftp 포트 : 21
아이디 : 신청한ID
패스워드 : 신청시 기입한 패스워드

사용자 삽입 이미지



4. 1에서 다운받은 갤러리프로그램을 압축을 풀어 계정에 업로드한다.

사용자 삽입 이미지

iFoto1.0.1.zip 파일 : gallery 하위 디렉토리에 iFoto 관련 파일들이 들어있다.

사용자 삽입 이미지

계정의 /gallery 에 올렸다.

파일들을 다 올리고 처음 접속하면 아래와 같이 /gallery/include/thumbnail.php 파일에서 문제가 생길 수도 있다.
어쩐일인지 파일이 업로드 되는 도중에 파일내용이 변경되어버린 경우가 대부분일것이다.
이런경우에는 계정에 올라간 thumbnail.php파일을 삭제한 후 다시 올려 올려 보도록 하자.
파일전송을 아스키타입이아닌 바이너리타입으로 세팅하여 업로드 하면 이런 문제는 생기지 않는다.
사용자 삽입 이미지

모든 파일이 정상적으로 업로드 되었다면 아래와같은 페이지가 보일 것이다.
이제 남은 일은 사진들을 올리는 일이 남았다.
사용자 삽입 이미지


5. 무료 계정에 이미지혹은 사진을 업로드 할 폴더를 만든다.

우선 ftp프로그램을 이용하여 계정에 접속 한 후 /gallery/gallery 폴더로 이동 해 보면 위 화면에서 보인 My Shot 과 My Pet 디렉토리가 보일 것이다. 어차피 예제 사진이고 각자가 올릴 사진도 아니니까 두 디렉토리는 지워 준다.
사용자 삽입 이미지

두 디렉토리를 선택해서 삭제!!
사용자 삽입 이미지

그런다음 업로드 할 디렉토리를 생성 해 준다. 이 디렉토리는 갤러리 좌측 메뉴에 그대로 나타나게 되며 디렉토리안에 디렉토리를 생성 해도 된다.
사용자 삽입 이미지

적당히 디렉토리를 만들고..
사용자 삽입 이미지

디렉토리 속성, 혹은 chmod조작으로 755를 만들어 준다.
사용자 삽입 이미지

사용자 삽입 이미지



6. FTP로 사진을 업로드 한다.

갤러리에 전시할 사진을 선택하여 위에서 만들어준 디렉토리에 업로드 한다.
사용자 삽입 이미지

사용자 삽입 이미지


7. 갤러리를 브라우저로 접속하여 업로드한 사진을 감상한다.


업로드가 끝나고 처음 접근하면 아래와 같이 각 사진의 썸네일을 만드는 중이라는 표시가 나타나고,
사용자 삽입 이미지

잠시 후 페이지를 다시열면 아래와같이 이미지들이 보인다.
사용자 삽입 이미지


자, 이로써 간단하게 작동하는 갤러리를 가지게 되었습니다.
이 프로그램을 이용했을경우 장점을 굳이 따지자면 브라우저로 일일이 파일을 업로드 하고 파일에 대한 정보를 기술하지 않아도 됩니다.
그냥 FTP클라이언트를 이용해 서버에 디렉토리를 만들고 이미지를 업로드하면 갤러리 프로그램이 알아서 메뉴와 이미지를 배치합니다.
그 다음으로, 백업과 계정의 이전이 편합니다. 별다른 설정이 없기 때문에 다른 계정으로 옮기고 싶을경우 위 프로그램을 업로드한
디렉토리와 파일을 새로운 계정에 그대로 업로드 하기만 하면 됩니다.
단점을 꼽자면, 한글 파일명이나 한글로 디렉토리를 만들면 글자가 깨져보입니다.( 댓글에는 한글도 잘 보입니다만.. )

몇가지 추가정보..


2007/06/04 02:36 2007/06/04 02:36
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

무료 PDF 파일 생성. 변환기

파워포인트 파일을 게시하기위해 PDF 파일로 변환해야 할 일이 생겼다.
딱히 PDF Writter를 사용하지 않고 있던 나는 구글신의 도움을 받아가며 무료 PDF변환기를
찾아보기 시작했는데...
Software955란 신기한 이름을 가진 회사의 제품중에 PDF955 란 제품이 눈에띄었다.

사이트에서 소개하고있는 955제품시리즈의 특징은
무료 다운로드,
기능 제한이 없는 Free Version 제공,
트라이얼버전이나 날짜제한없음,
사용직전에 스폰서 페이지가 보여짐.
 
으로 소개하고 있다.

다운로드 페이지 : http://www.pdf995.com/download.html

스폰서페이지 한번 보는 조건으로 아무러 기능제한이나 날짜제한없이 사용 할 수 있다는
게 마음에 들어 다운로드 후 사용 해 보았다.

사용 결과 한글처리도 잘 이루어지고 있으며
여타의 쉐어웨어 툴과같은 워터마크 같은 걸 남기지 않아서 마음에든다.


PDF995로 파워포인트 문서를 PDF파일로 변환하는 과정을 보자.

1.변환하고자 하는 PPT 파일을 파워포인트로 연다.
무료 pdf 변환기

2. 파일 -> 인쇄 (Ctrl+print ) 메뉴에 들어가면 디폴트로 지정되어있는 프린터 이름이 나오는데
무료 pdf 변환기

3. 프린터를 PDF955 로 선택 한다.
무료 pdf 변환기

4. 인쇄 버튼을 클릭하면 아래와같은 스폰서 광고가 나온다. Continue using sponsored version 을 클릭.
무료 pdf 변환기


5. 파워포인트를 PDF로 저장하기위한 대화상자가 뜬다. 저장할 PDF파일명을 적고 저장 버튼을 클릭하면 끝.
무료 pdf 변환기



2007/05/23 10:55 2007/05/23 10:55
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Ajax와 XML: 다섯 가지 Ajax 안티 패턴(anti-pattern)

원문출처 : http://www.ibm.com/developerworks/kr/library/x-ajaxxml3/

Ajax 코드의 일반적인 함정 피하기

난이도 : 중급

Jack D Herrington, Senior Software Engineer, Leverage Software Inc.

2007 년 5 월 15 일

어플리케이션들이 어떻게 잘못 되었는지를 이해함으로써 어플리케이션들을 올바르게 수행하는 방법을 배울 수 있습니다. Asynchronous JavaScript™ + XML (Ajax) 애플리케이션들을 작성하는 것에도 올바른 방식과 그릇된 방식이 있습니다.


사람들이 처음부터 모든 것을 잘 했다면 이 세상은 완전히 달라졌을 것이다. Ajax도 마찬가지다. 필자는 Ajax 개발자를 위해서 코딩, 기고, 강연, 지원 등 많은 일들을 해왔다. 이러한 일련의 활동들을 통해서 Ajax를 올바르게 다루는 방법과 잘못 다루는 방법에 대해 배웠다. 지난 기술자료인, 다섯 개의 일반적인 Ajax 패턴: 유용한 Ajax 디자인 패턴들에서, Ajax 애플리케이션을 올바르게 작성하는 다섯 가지 패턴들을 제시했다. 이 글에서는 Ajax 코드에서 자주 볼 수 있는 다섯 가지 안티 패턴(anti-pattern)에 대해 설명하겠다.

안티 패턴이란 무엇인가? 안티 패턴은 문제가 될 가능성이 짙은, 모든 사람들이 주의해야 할 애플리케이션 디자인의 결함이다. 이 글에서는 고급 주제에 대해 이야기 하겠다. 신택스 에러와 링커(linker) 문제는 언급하지 않겠다.

대부분의 개발자들은 안티 패턴의 대표적인 예라 할 수 있는, 웹 사이트에서 "SQL Injection attack" 이라는 결과를 만들어 내는 Structured Query Language (SQL) 라이브러리의 오용에 대해 알고 있을 것이다. 이러한 안티 패턴은 기업의 매출에 타격을 가하고, 고객의 기록을 노출 하기도 하며, 모든 프로그래밍 언어에서 발생할 수 있다. 따라서, 왜 이러한 일이 발생하는지, 어떻게 발생하는지, 이러한 문제를 어떻게 피하는지를 이해하는 것이 중요하다.

이 글에서는 Ajax 안티 패턴에 대해 살펴볼 것이다. 필자는 지금 기업에 수십억 달러 정도의 매출의 손실이 있다는 것을 이야기하려는 것은 아니다. 이러한 안티 패턴들이 서버를 충돌시키거나 형편없는 사용자 경험을 제공하고, 이 두 가지 모두 실망스럽고 비용이 많이 들 수 있다는 것을 이야기 하려는 것이다.

무엇인가 잘못 될 수 있다는 것을 이해한다면 많은 것을 배울 수 있다. 가끔 사람들은 Ajax을 페이지가 로딩된 후에 서버에서 XML을 보내는 유일한 방법으로 생각하고 있다. 이것은 매우 제한된 시각이며, 이것이 잘못 적용된다면 애플리케이션에 성능 문제를 일으킬 수 있다. 이 글에서, 왜 이것이 잘못 되었으며 이를 수정하는 방법을 설명하겠다.

굳이 그럴 필요가 없는데도 타이머에 폴링(poll)하기

필자가 생각하기에 많은 Ajax 문제들은 JavaScript 언어에 있는 타이머 기능의 오용과 관련이 있다. 핵심 메소드는 window.setInterval()이다. 이 메소드를 볼 때마다 여러분의 마음속에 작은 경각심이 생긴다. 왜 이 사람은 타이머를 사용하고 있을까? 틀림없이, 타이머에는 예를 들어 애니메이션과 같은 타이머의 본래 목적이 있을 것이다.

window.setInterval() 메소드는 특정 간격(매 초(second))마다 특정 함수를 콜백(call back)하도록 페이지에 명령한다. JavaScript 언어가 단일 쓰레드이기 때문에, 대부분의 브라우저들은 이러한 타이머를 거의 실행하지 않는다. 여러분이 1초를 요청하면 1초 또는 1.2초 또는 9초 또는 다른 시간으로 콜백을 얻게 된다.

타이머가 확실히 필요하지 않는 한 부분은 완료 할 Ajax 요청을 찾는 부분이다. Listing 1의 예를 보자.


Listing 1. Antipat1a_polling.html
                
<html><script>
var req = null;

function loadUrl( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.open('GET', url, true);
    req.send('');
  }
}

window.setInterval( function watchReq() {
    if ( req != null && req.readyState == 4 && req.status == 200 ) {
      var dobj = document.getElementById( 'htmlDiv' );
      dobj.innerHTML = req.responseText;
      req = null;
   }
 }, 1000 );

var url = window.location.toString();
url = url.replace( /antipat1a_polling.html/, 'antipat1_content.html' );
loadUrl( url );
</script><body>
Dynamic content is shown between here:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div>And here.</body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1a_polling.html 보기 링크 antipat1a_polling.html의 온라인 버전을 참조하라.

setInterval 호출에 도달할 때까지 모든 것이 좋아 보인다. 이 호출은 요청의 상태를 관찰 할 타이머를 설정하고 다운로드 된 자료에서 페이지의 내용을 설정한다.

요청이 짧게 완료될 때를 규명할 수 있는 문제에 대한 솔루션을 설명하겠다. Listing 2는 이 페이지가 요청하는 파일을 보여주고 있다.


Listing 2. Antipat1_content.html
                
<b>Hello there</b>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1_content.html 보기 링크 antipat1_content.html의 온라인 버전을 참조하라.

그림 1은 필자의 브라우저에 나타나는 페이지 모습이다.


그림 1. HTML 문서
HTML 문서

"그런데 이것은 잘 작동하지 않습니까? 깨짐 현상도 없는데 픽스가 왜 필요한가요?"라고 물을 수도 있겠다. 실제로 이것은 깨졌다. 매우 느리기 때문이다. 타이머 설정을 1초 간격으로 하면 요청은 잘 진행된다. 따라서 먼저, 비어있는 박스와 함께 페이지가 나타나고, 1초를 기다리면 내용이 나타난다.

솔루션은 무엇인가? Ajax는 본질적으로 비동기식(asynchronous)이다. 요청이 언제 끝났는지를 보기 위해 폴링 루프가 필요하지 않을까?

그렇게 필요한 것은 아니다. Listing 3에서 보듯, 모든 XMLHTTPRequest 객체가 제공하는 것은 onreadystatechange라고 하는 콜백 메커니즘이다. (얼마나 아름다운 이름인가, VAX PDP/11s를 연상시키는 이름이다.)


Listing 3. Antipat1a_fixed.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) {
  ...
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /antipat1a_fixed.html/, 'antipat1_content.html' );
loadUrl( url );
</script>
...

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1a_fixed.html 보기 링크 antipat1a_fixed.html의 온라인 버전을 참조하라.

이 새로운 코드는 onreadystatechange 콜백에 대한 응답으로 요청 객체가 변했는지의 여부를 본다. 그런 다음, 이것이 완료되면 페이지를 업데이트 한다.

결과는 매우 빨라진 페이지 로드이다. 페이지가 나타나면, 거의 동시에 새로운 콘텐트로 박스가 채워진다. 왜? 요청이 완료되자마자, 이 코드가 호출되고 필자는 페이지를 채우기 때문이다. 바보 같은 타이머 때문에 혼란스러워 할 필요가 없다.

또 다른 폴링 안티 패턴은 한 페이지가 요청을 서버로 반복해서 바운스(bounce) 할 때이다. 심지어 요청이 변경되지 않았음에도 그렇게 하는 경우이다. Listing 4의 검색 페이지 예제를 보자.


Listing 4. Antipat1b_polling.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) {
  ...
}

window.setInterval( function watchSearch() {
  var url = window.location.toString();
  var searchUrl = 'antipat1_content.html?s='+searchText.value;
  url = url.replace( /antipat1b_polling.html/, searchUrl );
  loadUrl( url );
 }, 1000 );

</script><body><form>
Search <input id="searchText" type="text">:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div></form></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1b_polling.html 열기 링크 antipat1b_polling.html의 온라인 버전을 참조하라.

그림 2에서는 필자의 브라우저에서 이 페이지가 실행되는 모습이다.


그림 2. 동적인 응답 영역을 가진 검색 영역
동적인 응답 영역을 가진 검색 영역

얼마나 아름다운가? 이 페이지는 이치에 맞는다. 필자가 검색 텍스트를 바꾸면, 결과 영역은 새로운 기준에 근거하여 바뀐다. (실제로는 그렇지 않지만 막후에 실제 검색 엔진이 있었다면 그렇게 했을 것이다.)

문제는 JavaScript 코드가 window.setInterval을 사용하여 계속해서 요청을 만든다는 것이다. 심지어 검색 필드의 콘텐트가 바뀌지 않았음에도 말이다. 이는 네트워크 대역폭을 잠식하고 서버 시간을 잠식한다. 대중적인 사이트의 경우 이것은 치명적이다.

솔루션은 검색 박스에 이벤트 콜백을 사용하는 것이다. (Listing 5)


Listing 5. Antipat1b_fixed.html
                
<html><script>
var req = null;
function processReqChange() { ... }
function loadUrl( url ) { ...  }

var seachTimer = null;
function runSearch()
{
  if ( seachTimer != null )
    window.clearTimeout( seachTimer );
  seachTimer = window.setTimeout( function watchSearch() {
    var url = window.location.toString();
    var searchUrl = 'antipat1_content.html?s='+searchText.value;
    url = url.replace( /antipat1b_fixed.html/, searchUrl );
    loadUrl( url );
    seachTimer = null;
   }, 1000 );
}
</script><body><form>
Search <input id="searchText" type="text" onkeyup="runSearch()">:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div></form></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1b_fixed.html 열기 링크 antipat1b_fixed.html의 온라인 버전을 참조하라.

여기에서 필자는 runSearch() 함수를 검색 박스의 onkeyup() 메소드로 연결했다. 이러한 박식으로 사용자가 검색 박스에 무엇인가 입력하면 콜백을 받도록 한다.

runSearch()가 수행하는 것은 매우 똑똑하다. 1초 간의 단일 타임아웃을 설정하고 이 시간안에 서버를 호출하고 검색을 실행하도록 한다. 그리고 이것을 설정하기 전에 시간이 경과되지 않았다면 그 타임아웃을 삭제한다. 왜? 이것은 사용자가 많은 텍스트를 입력하도록 허용하기 때문이다. 그런 다음, 사용자가 마지막 키를 누른 후 1초 만에 검색이 실행된다. 이러한 방식으로 사용자는 계속적으로 깜박거리는 디스플레이 때문에 신경 쓰지 않아도 된다.






콜백에서 리턴 결과 검사하지 않기

많은 Ajax 안티 패턴은 XMLHTTPRequest 객체의 메커니즘에 대한 오해에서 기인한다. 필자가 종종 목격하게 되는 것 중 하나는 사용자가 콜백에서 객체의 readyState 또는 status 필드를 검사하지 않을 때이다. Listing 6을 보자.


Listing 6. Antipat2_nocheck.html
                
<html><script>
var req = null;
function processReqChange() {
  var dobj = document.getElementById( 'htmlDiv' );
  dobj.innerHTML = req.responseText;
}
...

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat2_nocheck.html 열기 링크 antipat2_nocheck.html의 온라인 버전을 참조하라.

모든 것이 멀쩡한 것처럼 보인다. 작은 요청이지만, 일부 브라우저에서는 이것으로 족하다. 하지만, 대부분의 요청들은 onreadystatechange 핸들러로 여러 호출을 요청해야 할 정도로 크다. 따라서 여러분의 콜백은 불완전한 데이터로 작동하게 된다.

이를 수행하는 올바른 방법은 Listing 7에 나타나 있다.


Listing 7. Antipat2_fixed.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}
...

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat2_fixed.html 열기 링크 antipat2_fixed.html의 온라인 버전을 참조하라.

더 많은 코드가 생긴 것은 아니지만 모든 브라우저에서 작동한다.

Windows® Internet Explorer® 7에서 이러한 문제가 다른 브라우저에서 보다 중요하다는 것을 깨달았다. Internet Explorer 7은 onreadystatechange로 많은 콜백을 한다. 심지어는 작은 요청에도 정말 많다. 따라서, 핸들러를 올바르게 작성하는 것이 중요하다.






HTML이 더 나은 선택임에도 불구하고 복잡한 XML 실행하기

필자가 일했던 한 회사에서, "intelligence at the edge of the network"라는 말을 자주 사용했다. 서버에서 모든 일을 수행하는 대신 데스크탑에서 브라우저 기능을 사용하라는 의미이다.

하지만, 페이지에 많은 정보를 넣으면 그곳에는 많은 JavaScript 코드가 놓이게 된다. 이것은 큰 단점이 된다. 바로 브라우저 호환성이다. 실제로 모든 대중적인 브라우저에서 JavaScript 코드의 모든 중요한 라인을 테스트 해야 한다. 적어도 고객이 사용할 것 같은 브라우저에서도 그렇게 해야 한다. 그래야 의미가 통한다. 복잡한 Ajax 예를 보자. (Listing 8)


Listing 8. Antipat3_complex.html
                
<html><head><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 && req.responseXML ) {
    var dtable = document.getElementById( 'dataBody' );
    var nl = req.responseXML.getElementsByTagName( 'movie' );
    for( var i = 0; i < nl.length; i++ ) {
      var nli = nl.item( i );
      var elYear = nli.getElementsByTagName( 'year' );
      var year = elYear.item(0).firstChild.nodeValue;
      var elTitle = nli.getElementsByTagName( 'title' );
      var title = elTitle.item(0).firstChild.nodeValue;

      var elTr = dtable.insertRow( -1 );

      var elYearTd = elTr.insertCell( -1 );
      elYearTd.innerHTML = year;

      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = title;
} } }

function loadXMLDoc( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /antipat3_complex.html/, 'antipat3_data.xml' );
loadXMLDoc( url );
</script></head><body>
<table cellspacing="0" cellpadding="3" width="100%"><tbody id="dataBody">
<tr>
  <th width="20%">Year</th>
  <th width="80%">Title</th>
</tr>
</tbody></table></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat3_complex.html 열기 링크 antipat3_complex.html의 온라인 버전을 참조하라.

이 코드는 Listing 9에 나타난 XML에서 데이터를 읽고 이를 테이블로 포맷팅 한다.


Listing 9. Antipat3_data.xml
                
<movies>
  <movie>
    <year>1993</year>
    <title>Jurassic Park</title>
  </movie>
  <movie>
    <year>1997</year>
    <title>The Lost World: Jurassic Park</title>
  </movie>
  <movie>
    <year>2001</year>
    <title>Jurassic Park III</title>
  </movie>
</movies>

그림 3과 같은 결과를 보게 된다.


그림 3. 복잡한 영화 리스팅 페이지
복잡한 영화 리스팅 페이지

이것은 절대로 나쁜 코드가 아니다. 실제로는 비교적 단순한 태스크를 수행하는 많은 코드일 뿐이다. 결과 페이지는 전혀 복잡하지 않다. 클라이언트 측에서는 정렬되거나 검색될 수 없다. 사실, XML과 HTML간 이러한 복잡한 변환을 할 이유가 전혀 없다.

서버가 XML 대신 HTML을 리턴 하도록 하는 것이 더 간단하지 않을까? (Listing 10)


Listing 10. Antipat3_fixed.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'tableDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) { ... }

var url = window.location.toString();
url = url.replace( /antipat3_fixed.html/, 'antipat3_content.html' );
loadUrl( url );
</script><body><div id="tableDiv"></div></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat3_fixed.html 열기 링크 antipat3_fixed.html의 온라인 버전을 참조하라.

정말로 더 간단해졌다. 모든 복잡한 테이블 행과 셀 생성 코드는 <div> 태그의 innerHTML로 대체된다. à!

서버에서 리턴된 HTML은 Listing 11을 참조하라.


Listing 11. Antipat3_content.html
                
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody">
<tr>
  <th width="20%">Year</th>
  <th width="80%">Title</th>
</tr>
<tr>
  <td>1993</td>
  <td>Jurassic Park</td>
</tr>
<tr>
  <td>1997</td>
  <td>The Lost World: Jurassic Park</td>
</tr>
<tr>
  <td>2001</td>
  <td>Jurassic Park III</td>
</tr>
</tbody>
</table>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat3_content.html 열기 링크 antipat3_content.html의 온라인 버전을 참조하라.

모든 것이 그렇듯, 서버와 클라이언트 중 어디에서 처리할 것인지를 선택하는 것은 작업의 특성에 달려있다. 이 경우, 작업은 비교적 단순했다. 영화 테이블을 채우는 것이다. 작업이 더 복잡했다면, 다시 말해서, 정렬, 검색, 추가 또는 삭제, 영화를 클릭하면 더 많은 정보로 가게 되는 동적 인터랙션 같은 기능이 있다면 클라이언트에 보다 복잡한 코드가 실행되는 것을 볼 수 있다. 사실, 이 글 후반에 가서는 클라이언트에서의 정렬(sorting)을 설명할 것이다. 여기에서 서버에 너무 많은 부하를 주는 요소에 대해서 이야기 할 것이다.

이것에 대한 가장 완벽한 예제는 아마도 Google Maps일 것이다. Google Maps는 서버 측에서 리치 클라이언트 측 코드와 지능형 매핑 엔진을 혼합하는 고급스러운 작업을 수행한다. 필자는 이 서비스를 거기에서 어떤 프로세싱을 수행할 것인지를 결정하는 방법 예제로서 사용해 보겠다.






JavaScript 코드를 전달해야 할 때 XML 전달하기

웹 브라우저가 XML 데이터 소스를 읽고 이를 동적으로 실행한다는 모든 가설을 기반으로, 여러분은 이것이 사용할 수 있는 유일한 메소드라고 생각할 것이다. 하지만, 여러분의 생각은 틀리다. 매우 똑똑한 엔지니어들은 Ajax 전송 기술을 사용하여 XML 대신 JavaScript 코드를 보내기 때문이다. Listing 12에서 영화 테이블 예제를 보도록 하자.


Listing 12. Antipat4_fixed.html
                
<html><head><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dtable = document.getElementById( 'dataBody' );
    var movies = eval( req.responseText );
    for( var i = 0; i < movies.length; i++ ) {
      var elTr = dtable.insertRow( -1 );
      var elYearTd = elTr.insertCell( -1 );
      elYearTd.innerHTML = movies[i].year;
      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = movies[i].name;
} } }

function loadXMLDoc( url ) { ... }

var url = window.location.toString();
url = url.replace( /antipat4_fixed.html/, 'antipat4_data.js' );
loadXMLDoc( url );
</script></head><body>
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody"><tr>
  <th width="20%">Year</th>
  <th width="80%">Title</th>
</tr></tbody></table></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat4_fixed.html 열기 링크 antipat4_fixed.html의 온라인 버전을 참조하라.

서버에서 XML을 읽는 대신, JavaScript 코드를 읽는다. 이 코드는 JavaScript 코드에 있는 eval() 함수를 사용하여 데이터를 얻는데, 이는 테이블 구현에 사용할 수 있다.

JavaScript 데이터는 Listing 13에 나타나 있다.


Listing 13. Antipat4_data.js
                
[ { year: 1993, name: 'Jurassic Park' },
  { year: 1997, name: 'The Lost World: Jurassic Park' },
  { year: 2001, name: 'Jurassic Park III' } ]

이러한 기능은 JavaScript 언어로 서버와 통신하도록 해야 한다. 하지만, 그렇게 큰 일은 아니다. 대부분의 대중적인 웹 언어들은 이미 JavaScript Object Notation (JSON) 아웃풋을 지원한다.

효과는 명확하다. 이 예제에서 JavaScript 언어를 사용함으로써 클라이언트로 다운로드 된 데이터의 크기가 52%나 줄었다. 성능 역시 증가했다. JavaScript 버전을 읽는 것도 9%나 빨라졌다. 9%는 그렇게 큰 비율은 아니지만, 이 예제는 매우 기본적인 예제라는 것을 기억하라. 더 큰 데이터 블록이나 더 복잡한 구조는 더 많은 XML 파싱 코드를 요구할 것이지만, JavaScript 코드는 바뀌지 않는다.






서버에서 너무 많은 일을 수행하기

서버에서 적은 일을 수행해야 할 카운터 인자가 서버에서 너무 많은 일을 수행한다. 앞서 언급했지만, 이것은 균형을 맞추기 위한 작동이다. 하지만, 서버에서 작업을 분산하는 방법에 대한 설명으로서 클라이언트에서 영화 테이블을 정렬하는 방법을 설명하겠다.

Listing 14에는 정렬 가능한 영화 테이블이 나타나 있다.


Listing 14. Antipat5_sort.html
                
<html><head><script>
var req = null;
var movies = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    movies = eval( req.responseText );
    runSort( 'year' );
} }

function runSort( key )
{
  if ( key == 'name' )
    movies.sort( function( a, b ) {
      if ( a.name < b.name ) return -1;
      if ( a.name > b.name ) return 1;
      return 0;
    } );
  else
    movies.sort( function( a, b ) {
      if ( a.year < b.year ) return -1;
      if ( a.year > b.year ) return 1;
      return 0;
    } );
  var dtable = document.getElementById( 'dataBody' );
  while( dtable.rows.length > 1 ) dtable.deleteRow( 1 );
  for( var i = 0; i < movies.length; i++ ) {
    var elTr = dtable.insertRow( -1 );
    var elYearTd = elTr.insertCell( -1 );
    elYearTd.innerHTML = movies[i].year;
    var elTitleTd = elTr.insertCell( -1 );
    elTitleTd.innerHTML = movies[i].name;
  }
}

function loadXMLDoc( url ) { ... }

var url = window.location.toString();
url = url.replace( /antipat5_sort.html/, 'antipat4_data.js' );
loadXMLDoc( url );
</script></head><body>
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody"><tr>
  <th width="20%"><a href="javascript: void runSort('year')">Year</a></th>
  <th width="80%"><a href="javascript: void runSort('name')">Title</a></th>
</tr></tbody></table></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat5_sort.html 열기 링크 antipat5_sort.html의 온라인 버전을 참조하라.

이것은 매우 간단한 예제이다. 이 페이지에 나타날 것 같은 특별히 긴 영화 리스트에는 작동하지 않는다. 하지만, 페이지 리프레시 없이도, 서버가 많은 일을 수행하지 않아도 빠르게 정렬하는 테이블을 만들 수 있다.






결론

필자는 Ajax에 대한 많은 글을 써왔고 많은 Ajax를 수행했다. 필자는 Ajax forum on IBM developerWorks의 Ajax 포럼을 운영한다. 따라서 Ajax에 대한 한 두 가지의 일쯤은 알고 있고 이것이 어떻게 사용되고 어떻게 오용되는지도 알고 있다. 필자가 자주 목격하게 되는 것 중 하나는 개발자들이 Ajax의 복잡성을 오해하고 있다는 것이다. 개발자들은 Ajax가 XML, JavaScript, HTML 코드를 브라우저로 보내는 것 정도로 생각하고 있다. 필자는 Ajax 플랫폼을 완전한 브라우저로 보고 있다. 사실, 대중적인 브라우저들의 전체라고 볼 수 있다.

결론은 다음과 같이 내릴 수 있겠다. Ajax에 대해 배워야 할 것은 많이 있고 이와 관련한 실수들도 많이 한다. 바라건데, 이 글이 빠지기 쉬운 함정을 피하는데 지침이 되었기 바란다. 성공을 통해 많은 것을 배울 수도 있지만 실수를 통해서도 많은 것을 배우기 마련이다.

기사의 원문보기


필자소개

Jack D. Herrington은 20년 경력을 지닌 소프트웨어 엔지니어이다. Code Generation in Action, Podcasting Hacks, PHP Hacks 의 저자이다. 30개 이상의 기술자료를 기고했다. (jherr@pobox.com)

2007/05/17 23:11 2007/05/17 23:11
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

AJAX와 XML: 다섯 개의 일반적인 Ajax 패턴

원문출처 : http://www.ibm.com/developerworks/kr/library/x-ajaxxml2/

유용한 Ajax 디자인 패턴들

난이도 : 중급

Jack D Herrington, Senior Software Engineer, Leverage Software Inc.

2007 년 4 월 10 일

Asynchronous JavaScript + XML (Ajax)은 단연 2006년의 화두였고, 2007년에도 이러한 기조를 이어갈 전망입니다. 하지만 이것이 여러분의 애플리케이션에는 어떤 영향을 미칠까요? Ajax 애플리케이션에 사용되는 일반적인 아키텍처 패턴에는 무엇이 있을까요? 이 글에서는 다섯 가지 Ajax 디자인 패턴을 소개합니다.

확실히, Ajax는 모든 사람들이 자신들의 사이트에 채택하고 싶어하는 Web 2.0 용어이다. 하지만, 이것이 진정으로 의미하는 것은 무엇일까? 엔지니어들은 아키텍처 레벨에서 이것을 자신들의 사이트에 어떻게 통합할까? 이 글에서, Ajax의 기초를 설명하고, Ajax 개발에서 베스트 프랙티스로 입증된 몇 가지 Ajax 디자인 패턴을 소개하겠다.

Ajax는 Dynamic HTML (DHTML)과 XMLHTTPRequest 객체를 포함한 일련의 기술들을 포괄하는 기술이다. DHTML은 세 가지 엘리먼트들, Hypertext Markup Language (HTML), JavaScript 코드, Cascading Style Sheets (CSS)의 결합이다. 웹 페이지에서 JavaScript 코드를 사용하면서, 콘텐트를 추가, 제거, 수정하기 위해 페이지를 동적으로 수정할 수 있다. 바로 이것이 DHTML의 동적인 요소이다. JavaScript 코드는 XMLHTTPRequest 객체를 사용하여 페이지가 로딩된 후에 서버에서 데이터를 요청한다.

서버에서 데이터를 요청하는 것과, 그 데이터를 사용하기 위해 페이지를 수정하는 것, 이 두 가지 요소들의 결합이 Ajax의 정수이자 Web 2.0 사이트의 동적인 본성이다.

하지만, 이러한 기능들이 실제 세계에서 어떻게 사용되고, 사이트에서 이들을 어떻게 사용하는지에 대해서는 정확히 알 수 있다. 따라서 간단한 디자인 패턴(design patterns.)이 필요하다. 이 용어가 생소하다면, 같은 이름의 책을 참조하기 바란다. (참고자료) 이 책에서는 엔지니어들이 접하는 공통의 태스크에 대한 구현 패턴을 설명하고 있다. 이 책에서는 시스템을 디자인하는 방법에 대한 베스트 프랙티스 뿐만 아니라, 엔지니어들이 사용할 수 있는 용어도 설명한다.

이 글에서는 다섯 가지 일반적인 Ajax 디자인 패턴을 소개한다. HTML, XML, JavaScript 코드를 사용하여 서버에서 데이터를 얻는 방법이 다양하다. 서버에서 새로운 HTML로 페이지를 업데이트 하는 가장 단순한 패턴부터 시작하겠다.

Pattern 1. HTML 세그먼트 대체하기

아마도 가장 일반적인 Ajax 태스크는 서버에서 업데이트 된 HTML을 요청하여, 이것을 사용하여 페이지의 한 부분을 업데이트 하는 것이다. 예를 들어, 주식 시세를 업데이트 하기 위해 이를 주기적으로 수행할 수 있다. 또는, 검색 요청에 대한 응답으로, 온 디맨드(on demand) 방식으로 업데이트 할 수 있다.

Listing 1의 코드는 서버에서 페이지를 요청한 다음 콘텐트를 페이지의 바디에 있는 <div> 태그에 배치하는 부분이다.


Listing 1. Pat1_replace_div.html
				
<html>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /pat1_replace_div.html/, 'pat1_content.html' );
loadUrl( url );
</script>
<body>
Dynamic content is shown between here:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div>
And here.<br/>
</body>
</html>

Listing 2는 코드가 요청하고 있는 콘텐트이다.


Listing 2. Pat1_content.html
				
HTML encoded content goes here.

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat1_replace_div.html의 온라인 버전을 참조하라.pat1_replace_div.html 새 창으로 보기 링크

이 페이지를 Firefox에 로딩할 때, 그림 1과 같은 결과를 볼 수 있다.


그림 1. <div> 태그가 있는 페이지
태그 페이지

Listing 1의 코드로 가서 몇 가지를 살펴보자. 첫 번째로 알아야 할 것은 loadUrl() 함수인데, 이것은 서버에서 URL을 요청한다. 이 함수는 XMLHTTPRequest 객체를 사용하여 서버에 새로운 콘텐트를 요청한다. 또한, 브라우저가 콘텐트를 받을 때 호출되는 콜백 함수(이 경우, processReqChange)도 지정한다.

processReqChange 함수는 객체를 검사하여 요청이 완료되었는지 여부를 확인한다. 완료되었다면, 이 함수는 페이지의 <div> 태그의 innerHTML을 응답 텍스트에 설치한다.

동적 콘텐트용 플레이스홀더로서 <div> 태그를 사용하는 것은 Ajax 코드의 주요한 특징이다. 이 태그는 (여러분이 보더 같은 것을 추가하지 않는 한) 눈에 띠는 특징은 없지만 콘텐트가 어디로 가야 할 지를 알려주는 좋은 마커로서 작동한다. 엔지니어들은 대체 가능한 세그먼트에 <span> 태그를 사용한다. 나중에 설명하겠다. <div><span> 태그의 차이점은 전자가 라인 브레이크(패러그래프)를 사용하는 반면, 후자는 인라인 텍스트의 섹션을 정확하게 구분한다는 점이다.

잠시, processReqChange 함수로 가서, 함수가 statusreadyState 값을 체크하는 것이 중요하다. 일부 브라우저는 요청이 완료될 때에만 함수를 호출하지만, 다른 브라우저는 요청이 실행 중이라는 것을 나타내면서 지속적으로 콜백한다.

Tab 디스플레이 변수

이 패턴의 또 다른 변종은 Tab 스타일의 디스플레이를 생성하는 것이다. Listing 3은 Tab Ajax 인터페이스이다.


Listing 3. Pat1_tabs.html
				
<html>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'tabDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( tab ) {
  var url = window.location.toString();
  url = url.replace( /pat1_tabs.html/, tab );
  ...
}

function tab1() { loadUrl( 'pat1_tab1_content.html' ); }
function tab2() { loadUrl( 'pat1_tab2_content.html' ); }
tab1();
</script>
<body>
<a href="javascript: void tab1();">Tab 1<a> 
<a href="javascript: void tab2();">Tab 2<a>
<div id="tabDiv" style="border:1px solid black;padding:10px;">
</div>
</body>
</html>

Listing 4는 첫 번째 탭의 콘텐트이다.


Listing 4. Pat1_tab1_content.html
				
Tab 1 content

Listing 5는 두 번째 탭의 콘텐트이다.


Listing 5. Pat1_tab2_content.html
				
Tab 2 content

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat1_tabs.html의 온라인 버전을 참조하라.pat1_tabs.html 새 창으로 보기 링크

이 페이지를 브라우저에 로딩하면, 그림 2와 같은 첫 번째 탭을 볼 수 있다.


그림 2. 첫 번째 탭의 콘텐트
첫 번째 탭의 콘텐트

두 번째 탭 링크를 클릭한다. 브라우저는 두 번째 탭의 콘텐트를 가져와서, 이를 탭 영역에 보여준다. (그림 3)


그림 3. 두 번째 탭의 콘텐트
두번째 탭의 콘텐트

사용자에게서 요청을 가져와서 새로운 내용으로 디스플레이의 일부를 업데이트 하는 것, 이 경우에는 Tab 디스플레이를 만드는 것이야 말로 이 디자인 패턴의 전형적인 사용법이다. 애플리케이션 측에서 얻을 수 있는 가치는 사용자에게 훨씬 가벼운 페이지를 제공할 수 있고, 사용자는 자신들이 원하는 자료들에 온 디맨드 방식으로 액세스 할 수 있다.

Ajax 이전의 일반적인 기술은 페이지에 두 개의 탭을 두고, 온 디맨드 방식으로 이들을 숨기거나 보여주는 것이었다. 다시 말해서, 두 번째 탭용 HTML은 결코 보이지 않더라도 생성되었으며, 서버 시간과 대역폭의 낭비만 초래했다. 이제 새로운 Ajax 방식으로, 두 번째 탭용 HTML은 사용자가 요청할 때에만 생성된다.

Read more 변형

실제 환경에서는 어떻게 보이는지 알고 싶다면 의 온라인 버전을 참조하라. pat1_readmore.html pat1_readmore.html 새 창으로 보기 링크

또 하나의 예로 Read more 링크를 들 수 있다. (그림 4)


그림 4. 내 지루한 블로그 엔트리의 Read more 링크
Read more 링크

강아지 산책에 대해 더 읽고 싶다고 가정해 보자. Read more 링크를 클릭하고 그 링크를 전체 스토리로 대체할 수 있다. (그림 5)


그림 5. Read more 링크를 클릭한 후의 페이지 모습
Read more 클릭 후

사용자들은 페이지 리프레시 없이도 더 많은 자료들을 볼 수 있다.

Listing 6은 이 페이지에 대한 코드이다.


Listing 6. Pat1_readmore.html
				
<html>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( "moreSpan" );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) { ... }

function getMore()
{
  var url = window.location.toString();
  url = url.replace( /pat1_readmore.html/, 'pat1_readmore_content.html' );
  loadUrl( url );
}
</script>
<body>
<h1>Walking the dog</h1>
I took my dog for a walk today. 
<span id="moreSpan">
<a href="javascript: void getMore()">Read more...</a>
</span>
</body>
</html>

Listing 7은 "read more" 섹션에 대한 콘텐트이다.


Listing 7. Pat1_readmore_content.html
				
It was a nice day out. Warm and sunny. My dog liked getting out for a stretch.

이 코드는 <div> 태그 대신 <span> 태그의 사용법을 보여준다. 사용 방법은 사용자 인터페이스(UI)의 요구 사항에 따라 다르다. 여러분도 보다시피 어떤 방법이든 사용하기 쉽다.

이 페이지에 새로운 HTML을 만드는 것은 해결되었고, JavaScript가 데이터를 사용하여 보다 지능적인 작업을 수행하도록 하려면? 구조적인(structured) 방법으로 데이터를 브라우저에 어떻게 가져올 것인가? 당연히, XML이 필요하다.






Pattern 2. XML 데이터 읽기

몇 가지 이유로, Ajax는 XML의 동의어처럼 되어버렸다. XML은 절대로 그렇지 않은데 말이다. 위 예제에서 보듯, 텍스트 또는 HTML 조각 또는 Extensible HTML (XHTML) 코드를 리턴할 수 있다. 하지만 XML을 보내도 응답을 받을 수 있다.

Listing 8은 서버에서 책에 대한 기록을 요청하고, 페이지 내의 테이블에 그 데이터를 디스플레이 하는 Ajax 코드이다.


Listing 8. Pat2_xml.html
				
<html>
<head>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 && req.responseXML ) {
    var dtable = document.getElementById( 'dataBody' );
    var nl = req.responseXML.getElementsByTagName( 'book' );
    for( var i = 0; i < nl.length; i++ ) {
      var nli = nl.item( i );
      var elAuthor = nli.getElementsByTagName( 'author' );
      var author = elAuthor.item(0).firstChild.nodeValue;
      var elTitle = nli.getElementsByTagName( 'title' );
      var title = elTitle.item(0).firstChild.nodeValue;

      var elTr = dtable.insertRow( -1 );

      var elAuthorTd = elTr.insertCell( -1 );
      elAuthorTd.innerHTML = author;

      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = title;
} } }

function loadXMLDoc( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /pat2_xml.html/, 'pat2_xml_data.xml' );
loadXMLDoc( url );
</script>
</head>
<body>
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody">
<tr>
  <th width="20%">Author</th>
  <th width="80%">Title</th>
</tr>
</tbody>
</table>
</body>
</html>

Listing 9는 이 페이지의 데이터이다.


Listing 9. Pat2_xml_data.xml
				
<books>
  <book>
    <author>Jack Herrington</author>
    <title>Code Generation in Action</title>
  </book>
  <book>
    <author>Jack Herrington</author>
    <title>Podcasting Hacks</title>
  </book>
  <book>
    <author>Jack Herrington</author>
    <title>PHP Hacks</title>
  </book>
</books>

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat2_xml.html의 온라인 버전을 참조하라.pat2_xml.html 새 창으로 보기 링크

이 페이지를 브라우저에 로딩하면, 그림 6과 같은 결과를 볼 수 있다.


그림 6. XML 디스플레이 페이지
XML 디스플레이 페이지

이 페이지와 이전 패턴의 페이지와의 큰 차이는 processReqChange 함수에 있다. responseText를 보는 대신, 이제는 서버에서 온 응답이 XML로 올바르게 인코딩 될 경우에만 사용할 수 있는 XML Document Object Model (DOM)인 responseXML을 본다.

responseXML을 사용하여, XML 문서에서 <book> 태그들의 리스트를 요청한다. 이들 각각에 대해 <title><author> 엘리먼트를 받는다. 그런 다음, 각 책의 테이블에 행을 추가하고, 각 행에 셀을 추가하여 저자와 제목 데이터를 포함시킨다.

이는 전형적인 XML 데이터의 사용법이다. 보다 고급의 JavaScript 코드는 리턴된 데이터에 기반하여 클라이언트 측 소팅(sorting) 또는 검색을 수행한다.

안타깝게도, XML 데이터를 전송할 때의 단점은 브라우저가 XML 문서를 파싱하는데 시간이 걸린다는 점이다. 또한, XML에서 데이터를 찾는 JavaScript 코드는 복잡해 질 수 있다. (Listing 8) 대안은 서버에서 JavaScript 코드를 요청하는 것이다.






Pattern 3. JavaScript 데이터 읽기

서버에서 JavaScript 데이터를 요청하는 것은 JavaScript Object Notation (JSON)으로 통용되는 기술이다. JavaScript 데이터를 리턴하면 브라우저가 효율적으로 JavaScript 데이터 구조를 파싱하고 생성할 수 있고, 사용이 훨씬 쉬워진다.

서버에서 XML 데이터를 읽는 Listing 8의 코드를 서버에서 JavaScript 데이터를 읽는 것으로 수정했다. 새로운 코드는 Listing 10과 같다.


Listing 10. Pat3_js.html
				
<html><head><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dtable = document.getElementById( 'dataBody' );
    var books = eval( req.responseText );
    for( var b in books ) {
      var elTr = dtable.insertRow( -1 );

      var elAuthorTd = elTr.insertCell( -1 );
      elAuthorTd.innerHTML = books[b].author;

      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = books[b].title;
} } }

...

모든 HTML 코드는 같다. processReqChange 함수는 JavaScript 데이터가 서버에서 리턴했던 eval을 읽기 위해 변경된다. 이 함수는 eval에서 나온 JavaScript 객체들을 데이터 소스로서 사용하고, 이것은 테이블에 추가된다.

Listing 11은 서버에서 온 JavaScript 데이터이다.


Listing 11. Pat3_js_data.js
				
[ { author: 'Jack Herrington', title: 'Code Generation in Action' },
{ author: 'Jack Herrington', title: 'Podcasting Hacks' },
{ author: 'Jack Herrington', title: 'PHP Hacks' }
]

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat3_js.html의 온라인 버전을 참조하라. pat3_js.html 새 창으로 보기 링크

왜 많은 Ajax 애플리케이션 엔지니어들이 데이터를 인코딩할 때 XML 대신 JavaScript를 선호하는지를 쉽게 알 수 있다. JavaScript 코드는 읽기와 관리하기가 더 쉽고 브라우저가 처리하기에도 더 쉽다.

데이터 수집과 디스플레이도 중요하지만, Ajax의 핵심은 현재 데이터의 디스플레이이다. 여기에서는 현재(current.)가 중요하다. 여러분은 서버에서 늘 새로운 데이터를 가져오고 있다고 어떻게 확신할 수 있는가?






Pattern 4. 브라우저 캐시 피하기

브라우저는 웹 트래픽을 최적화하려고 하므로, 같은 URL을 두 번 요청하면, 페이지를 다시 요청하는 대신, 브라우저 캐시에 저장된 페이지를 사용하게 될 것이다. 따라서, Ajax 애플리케이션의 또 다른 패턴은 URL에서 무작위 엘리먼트를 사용하여 그 브라우저가 캐싱된 결과를 리턴하지 않도록 하는 것이다.

내가 좋아하는 방법은 현재 시간의 숫자 값을 URL에 추가하는 것이다. Listing 12는 그 방법이다.


Listing 12. Pat4_cache.html
				
<html>
<script>
...

function loadUrl( url ) {
  url = url + "?t="+((new Date()).valueOf());
  ...
}

...

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat4_cache.html의 온라인 버전을 참조하라.pat4_cache.html 새 창으로 보기 링크

이 것은 Listing 1에서 참조한 코드이지만, URL 스트링에서 JavaScript 텍스트가 추가되었다. 시간 값을 갖고 있는 t라고 하는 새로운 매개변수를 URL에 추가했다. 서버가 그 값을 인지하는지 여부는 상관 없다. 이것은 브라우저가 URL 기반 페이지 캐시를 무시하는지를 확인하는 방법일 뿐이다.






Pattern 5. 여러 HTML 세그먼트 대체하기

마지막 패턴은 첫 번째 패턴의 고급 버전이라고 볼 수 있다. <div> 태그를 서버에서 가져온 콘텐트로 대체하는 것이다. 웹 애플리케이션의 일반적인 문제는 사용자 인풋에 응답할 때, 여러 디스플레이 영역들이 업데이트되어야 한다는 점이다. 예를 들어, 주식 시세 애플리케이션에서, 디스플레이의 한 부분이 최신 시세를 보여주고, 또 다른 부분은 최신 가격 리스트를 보여준다.

디스플레이의 여러 부분들을 업데이트 하기 위해, 두 섹션에 대한 데이터를 포함하고 있는 서버에서 XML 응답을 사용한다. 정규식을 사용하여 응답에서 개별 섹션들을 분리한다. Listing 13은 그 방법이다.


Listing 13. Pat5_multi_segment.html
				
<html>
<head>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var one = req.responseText.match( /\<one\>(.*?)\<\/one\>/ );
    document.getElementById( 'divOne' ).innerHTML = one[1];
    var two = req.responseText.match( /\<two\>(.*?)\<\/two\>/ );
    document.getElementById( 'divTwo' ).innerHTML = two[1];
} }

function loadXMLDoc( url ) { ... }

var url = window.location.toString();
url = url.replace( /pat5_multi_segment.html/, 'pat5_data.xml' );
loadXMLDoc( url );
</script>
</head>
<body>

This is the content for segment one:<br/>
<div id="divOne" style="border:1px solid black;padding:10px;">
</div>
And segment two:<br/>
<div id="divTwo" style="border:1px solid black;padding:10px;">
</div>

</body>
</html>

Listing 14는 서버에서 가져온 데이터이다.


Listing 14. Pat5_data.xml
				
<segments>
  <one>Content for segment one</one>
  <two>Content for segment <b>two</b></two>
</segments>

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat5_multi_segment.html의 온라인 버전을 참조하라. pat5_multi_segment.html 새 창으로 보기 링크

이 코드를 브라우저에 로딩하면 그림 7과 같은 결과를 볼 수 있다.


그림 7. 서버에서 온 데이터로 업데이트 된 두 세그먼트
두 세그먼트 디스플레이

페이지 코드에서, 서버에서 리턴된 자료는 유효 XML이기 때문에 XML 응답을 사용할 수도 있었따. 하지만, XML 코드에서 개별 세그먼트를 크래킹 하는 대신 정규식을 사용하는 것이 더 쉬웠다.


결론

Ajax는 강력한 만큼, 오용 및 오해의 여지도 많이 있다. 이 글에서 내가 설명한 패턴들은 웹 애플리케이션에서 Ajax를 사용하는데 좋은 지침이 될 것이다. 이 글에서 제공한 코드를 사용하는 것 외에도, Ajax에서 파생된 Ajax와 Web UI 라이브러리도 사용해 보는 것도 좋다. 이중 가장 중요한 것은 Prototype.js 라이브러리로서, 서버에서 데이터를 쉽게 가져올 수 있으며, 크로스 브라우저 호환 방식을 사용하여 웹 페이지 콘텐트를 업데이트 한다. 이 라이브러리를 사용하면 전담 엔지니어들은 다양한 브라우저와 플랫폼에서 이들을 관리 및 테스트 할 수 있다.

Ajax에는 여러분의 애플리케이션에 동적인 작동을 추가할 수 있는 분명 무엇인가가 있다.

기사의 원문보기

필자소개

Jack D. Herrington은 20년 경력을 지닌 소프트웨어 엔지니어이다. Code Generation in Action, Podcasting Hacks, PHP Hacks 의 저자이다. 30개 이상의 기술자료를 기고했다. (jherr@pobox.com)

2007/05/17 23:10 2007/05/17 23:10
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

해외 무료(계정) 호스팅 소개

2007.6.28. 갱신 : 현재 1111mb.com 사이트가 열리지 않고 있습니다.
대안으로 www.freeweb7.com 을 이용하실 수 있습니다.
가입 절차는 1111mb 와 유사하기때문에 아래 글 대로 진행 하시면 됩니다.

오늘 소개하고자 하는건 무료로 웹계정과 트래픽을 제공하는 괜찮은 호스팅 사이트입니다.

제가 처음 이곳을 알게된건 촬영한 사진을 웹상에 게시하는데 사용중인 계정에서 상당한 트래픽 압박을 받고 있어서 입니다.

국내의 모 호스팅 서비스를 이용하고 있는데..( 지금 보시는 서비의 다락방과 서비의 photo gallery 는 해외 유료 계정입니다.^^ )
 그 당시 일트래픽 1.5gb를 신청한 상태였고(지금은 재 신청을 통해 500mb짜리로 돌려 놓았습니다만..)
평소에는 과분할 정도의 트래픽이지만 특정일 혹은 특정 게시물이 있거나 회원수가 꽤 되는 동호회에 이미지를 게시 할 경우 트래픽이 모자란 경우를 자주
당하게 됩니다.
트래픽을 늘이면 되지만 그때까지도 상당히 트래픽을 늘인 상태였고 단지 하루 ,이틀 폭주하는 트래픽을 감당하기위해 트래픽을 더 늘이는건
돈낭비 라는 생각이 들었습니다.

그런때에 이 호스팅을 찾게 된 겁니다.

사이트 주소는 http://www.1111mb.com http://www.freeweb7.com 입니다.
사이트명이 1111mb 이건 이 서비스가 처음 생겼을때는 무료로 1111mb의 계정을 주었던 듯합니다.

1111mb.com


사이트에서 밝히고 있는 특징은

  • 5000mb 용량제공(무려 5gb).
  • 월 50000mb 트래픽( 50gb ).
  • 광고 없음.
  • 계정id.1111mb.com 도메인 제공.
  • FTP 이용 가능.
  • PHP 4 지원.
  • 10mb MySql. 10개의 MySQL DB( 용량제한 없음 )
  • 99.9% 업타임 지원.
  • 등등..


입니다.

제가 처음 가입할 당시에는 계정은 2gb를 제공 했으며 html파일을 업로드하고 브라우저에서
열어보면 위아래로 광고가 붙어 있었는데 지금은 용량도 늘고, 광고도 사라졌습니다.

무료계정치곤 꽤 괜찮다는 생각이 들어 가입절차를 밟았습니다.

가입에 필요한 정보는 id, password 그리고 계정 활성알림 메일을 받을
email 주소가 다입니다.

가입 페이지


간단한 가입절차를 끝내면 등록한 메일주소로 안내 메일이 오게되는데
그거 확인 하시고 로그인 하면 아래와 같은 화면을 보실 수 있습니다.

로그인 후


우측에 전체 용량중에 사용중인 용량과 당월에 사용한 트래픽을 그래프로
보여 줍니다.


계정 생성이 끝난 후 신청id.1111mb.com ( 전 http://cucme.1111mb.com ) 으로 접속 하시면
아래와 같은 화면을 보실 수 습니다. 이제 html, 이미지파일등을 올리셔서 링크를 거셔도 되고 그냥 자료실로만 사용 하셔도 됩니다. ^^;;

첫화면


파일 관리는 웹상의 파일매니저를 통해서도 가능하고 ftp클라이언트를 통해서도 가능합니다.

ftp클라이언트를 통한 접속화면


단점이라면 업로드 가능한 최대 단일파일 크기가 5mb(웹의 파일매니저,ftp클라이언트 모두) 로 제한 되어 있다는점
( 한번에 올릴수 있는 용량은 무제한 입니다. 단지 파일 하나크기제한이 5mb 란거지요. ) 과 스트리밍파일은 업로드 할 수 없다는점 정도입니다.


이미지나 html파일을  올릴 마땅한 공간은 필요하지만 유료 호스팅 서비스를 받기엔 비용때문에
고민이셨던 분들이라면 한번쯤 이용 해도 괜찮은 서비스인듯 합니다.
그래도 무료 계정이니.. 백업은 선택이 아닌 필수!! 임도 명심 하셔야 겠죠?

2007/04/23 13:28 2007/04/23 13:28
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 와~ 좋은 정보네요. 고맙습니다^^

  2. 우담아빠님 산모와 뱃속의 아기모두 건강 하시지요?
    도움이 되셨다니 저도 기쁩니다. ^^

  3. Blog Icon
    승혁아빠

    가입까지는 성공을 했는데...화일이 업로드가 안됩니다...다른 분들은 이상이 없나요?

  4. 미디어 파일류나 zip파일등 업로드 파일 확장자에
    제한이 있습니다.
    txt,html,php 나 이미지 파일등이 가능합니다.

    꼼수라면 올리시고자 하는 파일 확장자를 jpg등으로 바꾸어
    올리는 방법이 있겠지만 불편한건 사실 입니다.

    요즘은 일반적인 zip이나 문서파일 업로드가 가능한
    무료 계정을 찾아보고 있습니다.

    좋은 소식 기대 해 주세요.

  5. 음 이 소개하신 사이트....웹 메니저로는 파일 업로드가 되는데, FTP로는 모든 파일이 디스크풀 에러가 나더군요. 그 문제로 몇달째 포럼에 원성이 자자..

  6. 그런가요? 지금 확인 해 보니 정말 파일이 안올라 가는군요..
    제가 ftp 클라이언트로 마지막으로 파일 업로드 한게 6월 3일이니
    그 이후에 문제가 생겼군요.. 꽤 오래 전에도 용량이랑 트래픽 늘이는
    작업 중에 접속이 안되고 그랬는데 이번엔 뭔지..
    석달정도 잘 돌아가는거 확인하고 쓴 글인데.. 그래도 문제가 생기는 군요..

    지금은 freeweb7쪽 계정으로 2달째 테스트 중에 있습니다.
    (지난달엔 11.89G, 이번달은 오늘까지 39.44G의 트래픽을 소모하고 있습니다.)
    freeweb7 측은 아시아문자(특히 중국)를 사용하면 계정 없애겠다고
    메인화면에 공지하고 있는데.. 포럼 쪽 보면 인도쪽이에서
    계정 쓸 수 있게 해달라고 하니까 허락 해 주곤 하더라구요..
    물론 저도 포럼을 통해 허락을 얻어 한글 사이트를 돌리면서 확인 해 보고 있습니다.

    적당한 때가 되면 이쪽 관련하여 글을 포스팅 하겠습니다.

  7. Blog Icon
    여기가짱이죠

    파일 저장 목적이 아닌, 배포 목적으로 4Gb까지 제공해 주는 사이트를 우연찬게 찾았네요.

    현재 베타 인 것 같기도 하지만, 파일 업로드되고 다운로드 되네요.

    제가 1기가 영화 파일 올려서 영국 친구들한테 보라고 하니깐 잘 나온다고 하네요.

    사이트 명은 www.ufreeus.com이고 가시면 그리드 방식으로 최대 4Gb까지 배포할 수 있다고 합니다.

    한번 방문해 보세요, 저도 올려서 친구들에게 파일 날려 주는데, 고화질 영화는 스트리밍으로도 되고, 일반 파일은 인터넷 다운로드 창으로 되고, 다운로드 받는 사람만 클라이언트를 까는데, 설명 보니깐, 이상한 것 같지는 않고요.

    해외 친구들이 매우 좋아합니다.

    가입도 간단하게 이메일 주소로 끝나고요.

    짱입니다 짱!

    이 사이트 운영자는 돈이 무지 많던가 아니면 제품 홍보를 하는건지, 하여간 고용량 파일 배포는 이 사이트가 현재까지 공짜로서는 최고네요.

    강추합니다.

    그리고 이 글은 절대 광고글 아닙니다.

    좋은 정보 있으시면, kokodon@naver.com으로 보내주세요. 꾸벅

  8. Blog Icon
    파도

    근데 생각보다
    웹사용자가 얼마 되지를 않나봅니다
    제가 만든 검색엔진으로 전세계를 조회 해보았지만
    1달가량 검색을 해도 대부분 죽은사이트 아니면 특정업체가 독점을 하고 있든데요
    1년 가량 모아야 다찾을려나
    계중에 혹시 telnet 도 되고 ftp 도 되는 그런사이트 찾을수도 있지 않을까요?

WATIR javascript alert 창 처리하는 법

ruby 소스

# test.rb

require 'watir'
include Watir

test_site = 'http://localhost/test.html'

ie = IE.new

ie.goto(test_site)

Thread.new { system("rubyw \"jscriptExtraAlert.rb\"") }

ie.button(:id, 'btnAlert').click

ie.close


# jscriptExtraAlert.rb

require 'watir/WindowHelper'

helper = WindowHelper.new
helper.push_alert_button()


HTML

<HTML>

 <HEAD>
 
  <TITLE> New Document </TITLE>
 
  <script type="text/javascript">
    function test(){
        alert('test');
    }
  </script>
 </HEAD>

 <BODY>
 
 <form>
        <input type="button" id="btnAlert" value="clickMe" OnClick="test();" />
       
 </form>       
 
 </BODY>

</HTML>

2007/02/26 22:35 2007/02/26 22:35
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Javascript Array 의 유용한 메소드들

Java 의 Vector 클래스는 내부적으로 배열을 사용하고 있다. 따라서 Vector 의 자바스크립트 버전을 만들기 위해서는 Array 객체에 대한 빵빵한 지식이 필요하다 (없어도 된다. 그러나 있으면 매우 좋다). 자! 배열의 기초와 유용한 메쏘드들을 살펴보자.

배열의 생성
1. 생성자를 이용한 생성
- new Array(arrayLength)
ex) friends = new Array(3); // 크기가 3 인 배열 생성
- new Array(element0, element1, ... , elementN)
ex) friends = new Array("개똥이", "소똥이", "말똥이"); // 크기 3인 배열 생성(값이 채워짐)
2. 직접 생성
friends = ["개똥이", "소똥이", "말똥이"];

간접적인 배열 길이의 증가
배열의 길이는 현재 배열의 길이보다 큰 인덱스를 사용하면 자동으로 증가한다. 아래는 배열의 길이가 0 인 객체 생성 후 99번째 요소에 값을 할당하여 배열의 길이가 100 으로 증가한 예이다.
friends = new Array();
friends[99] = "새똥이";

메쏘드 종류
concat : 두개의 배열을 합쳐 새로운 배열을 리턴한다. 원본 배열은 변하지 않는다.
문법
arrayName.concat(arrayName2, arrayName3, ... , arrayNameN)
인자
arrayName2, ... , arrayNameN - 합쳐질 인자들
예제
두 배열을 합치는 예
alpha = new Array("a", "b", "c");
numeric = new Array(1, 2, 3);
alphaNumeric = alpha.concat(numeric); // ["a", "b", "c", 1, 2, 3] 배열 생성

join : 모든 요소가 구분자로 이어진 문자열을 리턴한다. 디폴트 구분자는 comma(,) 이다.
문법
arrayName.join(separator)
인자
separator 요소와 요소 사이에 사용될 구분자 문자열
예제
friends = new Array("소똥이", "개똥이", "말똥이");
strFriends1 = friends.join(); // 소똥이,개똥이,말똥이
strFriends2 = friends.join(", "); // 소똥이, 개똥이, 말똥이
strFriends3 = friends.join(" + "); // 소똥이 + 개똥이 + 말똥이

pop : 배열의 마지막 요소를 삭제한 후 그 값을 리턴하고 배열의 크기를 줄인다.
문법
arrayName.pop()
인자
없음
예제
// 말똥이가 pop 되고 배열에는 "개똥이", "소똥이"만 남는다.
// 배열크기도 2로 줄어든다.
friends = ["개똥이", "소똥이", "말똥이"];
popped = friends.pop(); // popped 에 말똥이가 할당된다.

push : 배열에 하나 또는 여러개의 값을 넣고 새로운 배열의 길이를 리턴한다.(배열길이 증가)
문법
arrayName.push(element1, element2, ... , elementN)
인자
element1, element2, ... , elementN - 추가될 요소들
예제
friends = ["개똥이", "소똥이"];
pushed = friends.push("말똥이", "새똥이"); // ["개똥이", "소똥이", "말똥이", "새똥이"]
alert(pushed); // 4

reverse : 배열 요소를 역순으로 재배치한다(첫번째 요소는 마지막으로, 마지막 요소는 처음으로).
문법
arrayName.reverse()
인자
없음
예제
myArray = new Array("1", "2", "3");
myArray.reverse(); // ["3", "2", "1"]

shift : 첫번째 요소를 삭제하고 배열의 길이를 하나 줄인 후, 삭제된 요소를 리턴한다.
문법
arrayName.shift()
인자
없음
예제
friends = ["개똥이", "소똥이", "말똥이"];
shifted = friends.shift(); // ["소똥이", "말똥이"]
alert("삭제된 요소는 " + shifted + " 입니다."); // 개똥이

slice : 얇게 썬 슬라이스 치즈가 생각난다(^^). 배열의 일부를 잘라내어 새로운 배열을 리턴한다.
문법
arrayName.slice(begin[,end]) : [] 은 선택사항임
인자
begin - 0보다 큰 시작 인덱스 (필수)
end - 0보다 큰 끝 인덱스 (선택). 지정되지 않으면 배열의 끝까지 복사된다.
예제
numbers = ["0", "1", "2", "3", "4"];
sliced1 = numbers.slice(2, 3); // ["2"]
sliced2 = numbers.slice(2); // ["2", "3", "4"]

sort : 배열의 요소를 정렬한다.
문법
arrayName.sort([compareFunction])
인자
compareFunction - 정렬방법을 지정한 함수.
생략시에는 요소들의 toString() 값을 사전순서(Dictionary order) 대로 정렬한다.
compareFunction(a, b) 에서
1) a > b : 0 보다 큰 값 리턴
2) a = b : 0 리턴
3) a < b : 0 보다 작은 값 리턴
예제
// 역행 정렬
function descComparator(a, b) {
return b - a;
}

// 순행 정렬
function ascComparator(a, b) {
return a - b;
}

numbers = ["0", "1", "2", "3", "4"];
numbers.sort(); // ["1", "2", "3", "4", "5"]
numbers.sort(ascComparator); // ["1", "2", "3", "4", "5"]
numbers.sort(descComparator); // ["4", "3", "2", "1", "0"]

splice : 이전 배열요소를 삭제하고 새로운 내용물을 추가하는 형태로 배열 내용을 변경한다. 삭제된 요소들은 리턴된다. Vector 와 유사한 기능을 하므로 숙지하자.
문법
arrayName.splice(index, howMany, [element1][, ..., elementN])
인자
index - 변경하고자 하는 요소의 시작 인덱스
howMany - 삭제하고자 하는 이전 배열요소 갯수.
element,...,elementN - 추가하고자 하는 배열 요소들
예제
// numbers[2]부터 2개("2", "3")를 삭제하고 그 자리에 "5"와 "6" 을 삽입한다.
numbers = ["0", "1", "2", "3", "4"];
spliced = numbers.splice(2, 2, "5", "6"); // ["0", "1", "5", "6", "4"]
alert(spliced); // "2", "3"

unshift : 하나 또는 여러개의 요소를 배열의 왼쪽에 추가한다. 배열길이는 증가한다.
문법
arrayName.unshift(element1,..., elementN)
인자
element1,...,elementN - 배열의 앞쪽에 들어갈 요소들
예제
numbers = ["0", "1", "2"];
numbers.unshift("-2", "-1"); // ["-2", "-1", "0", "1", "2"]

출처 : http://blog.empas.com/jjh7266/6264266
2007/02/26 22:32 2007/02/26 22:32
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다