AMFPHP, OpenAMF, XML,JSON,TEXT에 대한 전체 속도 테스트에 관련된 내용은 http://blog.jidolstar.com/167 를 참고한다.
Flex 와
AMFPHP(http://www.amfphp.org/) 간에 데이터 전송속도를 확인했다.
AMFPHP는 PHP를 이용해
Array형태로 객체형태로 데이터를 전송하기 위해 사용한다. 가볍고 사용하기 편할 뿐만 아니라
무료이기
때문에 실무에도 많이 쓰이고 있다고 들었다.
AMFPHP는 ActionScript
Message
Format(AMF)의 형태로 데이터를 하나의 객체로 송수신하는 형태를 가진다. LCDS(구, FDS),
BlazeDS,
OpenAMF를 이용하면 AMF형태로 송수신할 수 있다. 그런데 이들은 Java로 작성되어
있기
때문에 PHP환경에서 하려면 AMFPHP를 이용해야할 것이다.
이미 사용하신 분들이라면
다들
아는 내용이긴 하지만 관련 한글로된 문서도 없고 개인적으로 AMFPHP에 대해서
알
필요가 있어서 직접 테스트 해보았다.
Mike Potter의
"PHP and Flex - JSON, XML or AMFPHP?" 에서는
XML, JSON, AMFPHP에서 Array를 이용하여 건당 Load속도를 체크했다. 나는 이와
더불어
보통 TEXT와 AMFPHP에서 String방식으로 전송했을 때를 추가했다.
지금부터
테스트
환경을 구축하고 실제 결과를 보여주도록 하겠다.
AMF 다운로드
및 설정 먼저
AMFPHP 1.9 Beta 2를 다운로드 받아 웹디렉토리에 위치시킨다.
amfphp/browser/service-config.xml을 아래와 같이 수정한다.
services-config.xml 중... (Language : xml)
<channels> <channel-definition id ="my-amfphp" class ="mx.messaging.channels.AMFChannel" > <endpoint uri ="http://[도메인 또는 IP]/디렉토리/amfphp/gateway.php" class ="flex.messaging.endpoints.AMFEndpoint" /> </channel-definition> </channels>
만약 한글을
써야한다면 amfphp/gateway.php 에서 $gateway->setCharsetHandler() 함수를 아래와 같이 수정한다.
gateway.php 중 (Language : php)
$gateway ->setCharsetHandler ( "iconv" , "euc-kr" , "utf-8" ) ;
테스트용 PHP 프로그램
아래 print_xml.php, print_json.php, print_text.php를
웹디렉토리 안에 위치시킨다. JSON 데이타를 만들기 위해 ZEND 프레임워크 에 있는 Json
encode()를 사용했다.
print_xml.php (Language : php)
<? print "<rows>" ;
for ( $i =
0 ;
$i <
500 ;
$i ++
) { print "<row><col1>This is row " .
$i .
"</col1><col2>10000000</col2><col3>More text to add to this row.</col3></row>" ;
} print "</rows>" ;
?>
print_json.php (Language : php)
<? include ( "Zend/Json.php" ) ;
for ( $i =
0 ;
$i <
500 ;
$i ++
) { $Col1 =
"This is row " .
$i ;
$Col2 =
"10000000" ;
$Col3 =
"More text to add to this row." ;
$ThisRow =
array ( "col1" =>
$Col1 ,
"col2" =>
$Col2 ,
"col3" =>
$Col3 ) ;
$TotalArray [ ] =
$ThisRow ;
//print "<row><col1>This is row ".$i."</col1><col2>10000000</col2><col3></col3></row>"; } print Zend_Json::
encode ( $TotalArray ) ;
?>
print_text.php (Language : php)
<? for ( $i =
0 ;
$i <
500 ;
$i ++
) { print "This is row " .
$i .
"|10000000|More text to add to this row.\n " ;
} ?>
아래 sample.php는 amfphp/service/ 폴더에 위치시킨다.
sample.php
(Language : php)
<?php // Create new service for PHP Remoting as Class class sample
{ function sample
( ) { // Define the methodTable for this class in the constructor $this ->
methodTable =
array ( "getData" =>
array ( "description" =>
"Return a list of data" ,
"access" =>
"remote" ,
"returns" =>
"string" ) ) ;
} function getData
( $obj ) { $num =
500 ;
if ( $obj [ 0 ] [ 'bText' ] ==
false ) { for ( $i =
0 ;
$i <
$num ;
$i ++
) { $Col1 =
"This is row " .
$i ;
$Col2 =
"10000000" ;
$Col3 =
"More text to add to this row." ;
$ThisRow =
array ( "col1" =>
$Col1 ,
"col2" =>
$Col2 ,
"col3" =>
$Col3 ) ;
$TotalArray [ ] =
$ThisRow ;
} return $TotalArray ;
} else { $str =
"" ;
for ( $i =
0 ;
$i <
$num ;
$i ++
) { $Col1 =
"This is row " .
$i ;
$Col2 =
"10000000" ;
$Col3 =
"More text to add to this row." ;
$ThisRow =
$Col1 .
"|" .
$Col2 .
"|" .
$Col3 .
"\n " ;
$str .=
$ThisRow ;
} return ( $str ) ;
} } } ?>
Flex 소스
아래는 Flex 코드이다. AmfPhpSpeedTest 이름으로
프로젝트를 생성후 아래 2개 파일을 프로젝트 폴더에 위치시킨다.만약
JSON Lib가 없는 경우 http://labs.adobe.com/wiki/index.php/ActionScript_3:resources:apis:libraries#corelib 에서 corelib를 다운로드 받아서 corelib.swc파일을 자신의
프로젝트 라이브러리에 추가해야 한다. 이와 관련된 내용는 http://tong.nate.com/lhs0806/28443586 를 참고한다.
RemotingConnect.as (Language : xml)
package { import flash.net.NetConnection; import flash.net.ObjectEncoding; public class RemotingConnection extends NetConnection { public function RemotingConnection( sURL:String ) { objectEncoding = ObjectEncoding.AMF0; if (sURL) connect( sURL ); } public function AppendToGatewayUrl( s : String ) : void { // } } }
AmfPhpSpeedTest.mxml (Language :
xml)
<?xml version ="1.0" encoding ="utf-8" ?> <mx:Application xmlns:mx ="http://www.adobe.com/2006/mxml" layout ="absolute" > <mx:Script> <![CDATA[ import mx.collections.ArrayCollection; import mx.rpc.events.ResultEvent; import com.adobe.serialization.json.JSON; public var gateway : RemotingConnection; private var bText:Boolean = false; [Bindable] public var startTime:Date; [Bindable] public var endTime:Date; [Bindable] public var elapsedTime:Number; public var applicationData:ArrayCollection; public function sendXML():void { startTime = new Date(); http_service_xml.send(); } public function sendJSON():void { startTime = new Date(); http_service_json.send(); } public function sendTEXT():void { startTime = new Date(); http_service_text.send(); } public function sendAMFPHP( bText:Boolean ):void { this.bText = bText; startTime = new Date(); gateway = new RemotingConnection( "http://192.168.0.200/ZendFlex_PHPPrintXML/amfphp/gateway.php " ); gateway.call( "sample.getData", new Responder(onResult, onFault), new Array({"bText":bText})); } public function handleXML(event:ResultEvent):void { datagrid.dataProvider = event.result.rows.row; endTime = new Date(); elapsedTime = endTime.getTime() - startTime.getTime(); } public function handleTEXT(event:ResultEvent):void { var arr:Array = new Array(); var line:Array = String(event.result).split("\n"); var col1:String; var col2:String; var col3:String; for( var i:int; i < line.length; i++) { var temp:Array = line[i].split("|"); arr.push( {"col1":temp[0], "col2":temp[1], "col3":temp[2] } ) } datagrid.dataProvider = new ArrayCollection( arr ); endTime = new Date(); elapsedTime = endTime.getTime() - startTime.getTime(); } public function handleJSON(event:ResultEvent):void { //get the raw JSON data and cast to String var rawData:String = String(event.result); //decode the data to ActionScript using the JSON API //in this case, the JSON data is a serialize Array of Objects. var arr:Array = (JSON.decode(rawData) as Array); //create a new ArrayCollection passing the de-serialized Array //ArrayCollections work better as DataProviders, as they can //be watched for changes. var dp:ArrayCollection = new ArrayCollection(arr); //pass the ArrayCollection to the DataGrid as its dataProvider. datagrid.dataProvider = dp; endTime = new Date(); elapsedTime = endTime.getTime() - startTime.getTime(); } public function onResult( result:* ) : void { if( true == bText ) { var arr:Array = new Array(); var line:Array = String(result).split("\n"); var col1:String; var col2:String; var col3:String; for( var i:int; i < line.length; i++) { var temp:Array = line[i].split("|"); arr.push( {"col1":temp[0], "col2":temp[1], "col3":temp[2] } ) } datagrid.dataProvider = new ArrayCollection( arr ); } else { datagrid.dataProvider = new ArrayCollection( result as Array ); } endTime = new Date(); elapsedTime = endTime.getTime() - startTime.getTime(); } public function onFault( fault : String ) : void { trace( fault ); } ]]> </mx:Script> <mx:HTTPService result ="handleXML(event)" url ="http://192.168.0.200/ZendFlex_PHPPrintXML/print_xml.php " id ="http_service_xml" > </mx:HTTPService> <mx:HTTPService result ="handleJSON(event)" url ="http://192.168.0.200/ZendFlex_PHPPrintXML/print_json.php " id ="http_service_json" > </mx:HTTPService> <mx:HTTPService result ="handleTEXT(event)" url ="http://192.168.0.200/ZendFlex_PHPPrintXML/print_text.php " id ="http_service_text" > </mx:HTTPService> <mx:DataGrid id ="datagrid" right ="10" left ="10" top ="50" bottom ="100" > <mx:columns> <mx:DataGridColumn headerText ="Column 1" dataField ="col1" /> <mx:DataGridColumn headerText ="Column 2" dataField ="col2" /> <mx:DataGridColumn headerText ="Column 3" dataField ="col3" /> </mx:columns> </mx:DataGrid> <mx:Text text ="{startTime}" x ="6" bottom ="74" /> <mx:Text text ="{endTime}" x ="10" bottom ="48" /> <mx:Text text ="{elapsedTime}" x ="10" bottom ="18" /> <mx:Button x ="11" y ="10" label ="Call XML" click ="sendXML()" /> <mx:Button x ="91" y ="10" label ="Call JSON" click ="sendJSON()" /> <mx:Button x ="178" y ="10" label ="Call TEXT" click ="sendTEXT()" /> <mx:Button x ="403" y ="10" label ="Call AMFPHP-Array" click ="sendAMFPHP(false)" /> <mx:Button x ="265" y ="10" label ="Call AMFPHP-TEXT" click ="sendAMFPHP(true)" /> </mx:Application>
위 코드에서 빨간색으로 되어진
부분은 해당 주소로 변경해준다. 만약 php소스가 로컬에 위치하지 않는다면 아래와
같은 crossdomain.xml 를 웹디렉토리에 위치시킨다.
crossdomain.xml (Language : xml)
<?xml version ="1.0" ?> <cross-domain-policy> <allow-access-from domain ="*" /> </cross-domain-policy>
실행결과
분석결과
아래 표에 나온 데이타는 해당 건당 각 방식의 데이타 Load완료 시간이다.
시간은 10번씩 테스트 해서 나온 평균 시간이다. 단위는 ms(1000ms = 1sec)이다.
XML
JSON
TEXT
AMFPHP-TEXT
AMFPHP-ARRAY
30000건
6017
9273
640
697
6649
20000건
3719
6003
418
384
4331
10000건
1890
2965
193
209
2067
5000건
915
1469
103
103
1036
1000건
177
359
40
53
175
500건
99
184
40
47
131
보는바와 같이 AMFPHP가 Array 방식으로 쓰는 장점이 있는 것 외에는
속도면에서
좋은 포퍼먼스를 보여주지 못한다. 오히려 XML로 전송했을때보다 속도면에서 좋지 못하다.
보통 TEXT방식으로 전송할때와 AMFPHP를 이용해 TEXT로 전송할때를 보면
별로 차이가
없다는
것을 발견할 수 있다.
결론을 말하자면
순수하게
구분자(| 나 \n 등)를 이용한 순수 TEXT방식으로 데이타를 전송하는 것이 가장
좋은 포퍼먼스를 보인다. 속도를 위해서라면 순수 TEXT방식을 사용하자.
대용량 데이타
전송시 AMFPHP를 사용하는 것은 적절하지 못하다.
데이타에 대한 표준규약이
관계가 있을때만 XML 또는 JSON을 사용한다.
Array형태로 데이타를 전송할 필요가
있을때 AMFPHP를 사용하면 편하다.
데이타 전송속도를 최상으로 올리기 위해서는 FDS(Flex
Data Service)를 사용한다. 하지만 유료라는거... ㅡㅡ;
더욱 세밀하게
테스트 하기 위해서는 데이타를 만드는 시간과 Flex에서 이를 Parsing하는 시간도 Check해야한다.
그리고 만약 데이타베이스에서 읽어올 때는 데이타베이스 접속시간과 Query수행시간도 고려해야할 것이다. 참고로 위의 테스트 결과는 100MB의 LAN환경에서 시험해본 것이기 때문에 실제론 저
시간보다 더 걸린다.
테스트 소스 다운로드 소스는 아래
링크에서
다운로드 받을 수 있다.
참고사이트 AMFPHP 공식사이트 -
http://amfphp.org/ Amfphp 1.9 beta 2 -
ridiculously
faster -
http://www.5etdemi.com/blog/archives/2007/01/amfphp-19-beta-2-ridiculously-faster/ PHP and Flex - JSON, XML
or
AMFPHP? -
http://blogs.adobe.com/mikepotter/2006/07/php_and_flex_js.html Using Flex2 and AMFPHP :
http://www.adobe.com/devnet/flex/articles/flex2_amfphp.html Using Amfphp 1.9 with the Adobe Flex 2 SDK :
http://howtoforge.com/amfphp_adobe_flex2_sdk Flex RemoteObject and AMFPHP 1.9 :
http://www.sephiroth.it/tutorials/flashPHP/flex_remoteobject/ Zend
Framework
:
http://framework.zend.com/home 글쓴이 : 지돌스타(
http://blog.jidolstar.com/164 )