2010년 1월 10일 일요일

Flash Player에서 P2P를? Adobe Stratus에 대해

방장은 누규? 채팅사이트 조이팅스토리를 운영하며 마케팅, 사업 등에 관심이 많은 철이

 

 

Adobe Stratus는 Flash Player 10이상 또는 AIR 1.5 이상에서 RTMFP(Real Time Media Flow Protocol)이라 불리우는 통신프로토콜을 이용하여 클라이언트끼리 Peer to Peer(P2P)가 가능하게한 기술이다. TCP가 아닌 UTP를 기반으로 하기 때문에 통신 속도에는 좋지만 데이타 전송에 대한 신뢰도는 떨어지지 않을까 판단한다. 이러한 이유로 Stratus는 채팅, 각종 미디어 통신, 멀티 게임등을 만드는데 적합하다고 할 수 있다. 

 

위 그림에서 볼 수 있듯이 기존 RTMP는 사용자가 서버를 통해서만 다른 사용자에게 접근이 가능했다. 하지만 Adobe Stratus에서 제공하는 RTMFP를 이용하면 처음 Staratus 서버와 접속하여 인증절차만 완료하면 Flash Player 끼리 P2P통신이 가능해진다. 이렇게 함으로서 서버의 부하를 줄일 수 있게 되었다.

필자는 Adobe에 올라온 예제를 가지고 테스트를 해봤다. 이 예제는 Adobe Stratus를 가지고 어떤 기능까지 가능한가 총체적으로 보여주는 예제이다. 단순한 채팅뿐 아니라 마이크, 스피커, 비디오 예제가 한 소스에 들어가 있다. 예제는 [여기]에서 실행해볼 수 있고 또한 다운로드 받을 수 있다. 

필자는 제공된 Stratus 예제 Flex 애플리케이션을 수정하지 않고 서버측 사용자 등록하는 코드인 reg.cgi를 PHP로만 포팅해서 테스트 해봤다. 

이것을 테스트 하기 위해 다음단계를 거친다. 

  1. Flash Player 10 이상 설치한다.
  2. Flex SDK 3.2 또는 Flash Builder 3.0.2 를 설치한다.
  3. Stratus beta 개발 키를 받는다. Adobe에 가입해야한다.
  4. 참고로 Flash Player 10 API 문서를 본다. (한글은 여기)
  5. “Stratus service for developing end-to-end applications using RTMFP in Flash Player 10” 문서를 본다. 우야꼬님이 번역한 문서는 [여기]를 참고
  6. 예제 프로그램 다운로드
  7. 질문 및 답변은 여기로

 

Stratus는 현재 Adobe측에 서버를 두고 있고 공개하고 있진 않다. 그러므로 자신의 서버에 Stratus를 설치하지는 못한다. 하지만 개발키를 부여하고 있기 때문에 “rtmfp://stratus.adobe.com/개발키” 에 접속해서 언제든지 개발은 가능하다. 아래는 개발키를 가지고 Adobe의 Stratus서버에 접속인증을 하는 예제이다.

 

1.private const StratusAddress:String = "rtmfp://stratus.adobe.com";
2.private const DeveloperKey:String = "your-developer-key";
3.private var netConnection:NetConnection;
4.  
5.netConnection = new NetConnection();
6.netConnection.addEventListener(NetStatusEvent.NET_STATUS,
7.netConnectionHandler);
8.netConnection.connect(StratusAddress + "/" + DeveloperKey);

 

다운로드 받은 예제에서 사용자 등록 웹서비스를 위한 reg.cgi는 python으로 만들어졌다. python에 대해서 아는바가 별로 없어서 이 코드를 PHP에서 동일하게 동작하도록 만들었다. 또한 DB는 간편하게 만들기 위해 SQLite를 이용한다. 

먼저 개인 리눅스 서버에 sqlite를 설치했다.(안녕리눅스 pkgadd를 이용해서 간편하게 설치함 ^^). 다른 환경이라면 그 환경에 맞게 설치하면 되겠다.(http://www.sqlite.org/ 에서 다운로드 받아 설치한다.)

 

# pkgadd sqlite

Zend Optimizer requires Zend Engine API version 220051025.

The Zend Engine API version 220060519 which is installed, is newer.

Contact Zend Technologies at http://www.zend.com/ for a later version of Zend Optimizer.

sqlite          : Install 성공

 

sqlite는 아래처럼 mysql과 비슷하게 사용이 가능하다.

# sqlite test.db

SQLite version 2.8.17

Enter ".help" for instructions

sqlite> create table test(idx integer);

sqlite> .table

test

sqlite> insert into test(idx) values(1);

sqlite> insert into test(idx) values(2);

sqlite> insert into test(idx) values(3);
sqlite> select * from test;

1

2

3

sqlite> .quit

 

여기서 사용할 DB를 만들기 위해 아래와 같이 원하는 폴더에 staratus_registration.db를 만들자. 만들고 그냥 저장하면 된다.

 

vi staratus_registration.db

 

아래는 만들어진 SQLite DB(staratus_registration.db )를 이용해 사용자 접속 처리를 하는 PHP(reg.php) 코드이다. 참고로 PHP 5.2 이상 환경이고 이 환경에서는 SQLite에 대한 API를 제공하고 있다.

 

001.<?php
002.    $_METHOD = $_GET; // $_GET 또는 $_POST;
003.    $username = $_METHOD['username'];
004.    $identity = $_METHOD['identity'];
005.    $friends = $_METHOD['friends'];
006.  
007.    header("Content-type:text/plain;charset=utf-8");
008.    header("Cache-Control: no-cache, must-revalidate");
009.    header("Pragma: no-cache");
010.  
011.    echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
012.    echo "<result>";
013.  
014.    //DB 열기
015.    $db = @sqlite_open('stratus_registrations.db', 0777, $error);
016.    if( $db )
017.    {
018.        //Table 존재 확인
019.        $result = @sqlite_query($db, "SELECT name FROM sqlite_master WHERE type='table' AND name='registrations'");
020.        $tables = @sqlite_fetch_all( $result );
021.  
022.        $exist_table = true;
023.  
024.        //테이블이 존재하지 않는다면 테이블을 생성함
025.        if( count($tables) == 0 )
026.        {
027.            //Table 생성
028.            $query = "CREATE TABLE registrations (
029.                            m_username VARCHAR COLLATE NOCASE,
030.                            m_identity VARCHAR,
031.                            m_updatetime DATETIME,
032.                            PRIMARY KEY (m_username) );
033.                    CREATE INDEX registrations_updatetime ON registrations (m_updatetime ASC);";
034.            if( !@sqlite_exec($db, $query, $error) )
035.            {
036.                echo "<error>$error</error>";
037.                $exist_table = false;
038.            }
039.        }
040.  
041.        //Table이 존재하는 경우만 실행
042.        if( $exist_table )
043.        {
044.            //개인접속
045.            if( $username )
046.            {
047.                //기존 사용자 있는지 확인
048.                $select_query = "SELECT m_username, m_identity FROM registrations WHERE m_username = '$username'";
049.                $result = @sqlite_query($db, $select_query);
050.                $array = @sqlite_fetch_array($result);
051.  
052.                //사용자 추가 및 업데이트
053.                if( $array )
054.                {
055.                    $update_query = "update registrations SET m_identity='$identity', m_updatetime=datetime('now') where m_username='$username';";
056.                    //echo "<update_query>$update_query</update_query>";
057.                    if( sqlite_exec($db, $update_query$error) )
058.                    {
059.                        echo "<update>true</update>";
060.                    }
061.                    else
062.                    {
063.                        echo "<update>false</update>";
064.                        echo "<error>$error</error>";
065.                    }
066.                }
067.                else
068.                {
069.                    $insert_query = "insert into registrations (m_username, m_identity, m_updatetime) values ( '$username', '$identity', datetime('now'))";
070.                    //echo "<insert_query>$insert_query</insert_query>";
071.                    if( sqlite_exec($db, $insert_query, $error) )
072.                    {
073.                        echo "<update>true</update>";
074.                    }
075.                    else
076.                    {
077.                        echo "<update>false</update>";
078.                        echo "<error>$error</error>";
079.                    }
080.                }
081.            }
082.            //친구연결요청(1시간 동안 접속을 하지 않은 사람은 무시)
083.            else if( $friends )
084.            {
085.                $f = trim($friends);
086.                echo "<friend><user>$f</user>";
087.                $select_query = "SELECT m_identity from registrations where m_username = '$f' and m_updatetime > datetime('now', '-1 hour')";
088.                $result = @sqlite_query( $db, $select_query );
089.                $array = @sqlite_fetch_array($result);
090.                if( $array )
091.                {
092.                    echo "<identity>$array[m_identity]</identity>";
093.                }
094.                echo "</friend>";
095.  
096.            }
097.  
098.        }
099.    }
100.    else
101.    {
102.        echo "<error>$error</error>";
103.    }
104.  
105.    echo "</result>";
106.?>

 

“http://당신의 Domain/경로/reg.php?user=jidolstar&identity=발급받은개발키” 로 접속해보자. 아래와 같이 나오면 정상이다. 이것은 처음 사용자가 접속했을때 인증하기 위한 것이다.

 

에러가 발생하면 PHP파일과 DB가 같은 폴더에 있는지 확인하고 그래도 문제가 있다면 DB를 포함하는 폴더의 권한을 777로 바꿔보자.

 

 

이번에는 http://당신의 Domain/경로/reg.php?friends=jidolstar 로 접속해보자. 아래와 같이 나오면 정상이다. 이것은 상대방이 접속요청을 할때 인증하기 위한 것이다.

 

 

다운 받은 Flex코드를 새 Flex 프로젝트를 만들어 복사한뒤 Application내에 개발키와 웹서비스 URL를 설정한뒤 실행한다.

 

1.// stratus address, hosted by Adobe
2.[Bindable] private var connectUrl:String = "rtmfp://stratus.adobe.com"
3.  
4.// developer key, please insert your developer key here
5.private const DeveloperKey:String = "Adobe에서 발급받은 개발키"
6.  
7.// please insert your webservice URL here for exchanging
8.private const WebServiceUrl:String = "http://당신의 URL/설치디렉토리/reg.php";

 

성공한다면 아래처럼 시원하게 채팅이 가능할거다. 물론 웹캠과 마이크가 있다면 더욱 완벽한 테스트가 가능하다.

 

 

필자가 못생겨서 더이상 읽고 싶지 않나? 할 수 없다. 이미 더 이상 쓸 말도 없다. ㅋ

 

출처: http://blog.jidolstar.com/498?expandComment=1

 

 

 

 

 



P 이경철님의 파란블로그에서 발행된 글입니다.

댓글 없음:

댓글 쓰기