ServerSocket이라는 것이 Adobe AIR 2에서 생겼는데요.
뭐 특별히 제약사항같은 것은 없는 것 같군요. 그냥 서버소켓 만들어서 쓰면 됩니다.

우선 Adobe AIR 2 셋팅Flash Builder를 다운로드

서버소켓 생성하는 방법은
new ServerSocket();
serverSocket.bind(포트, "아이피");
serverSocket.listen();
하면 서버소켓이 생성됩니다.

Event.Connect를 이벤트 추가하면 상대방이 연결해왔을 때 호출이 됩니다.
보통 Java에서는 Thread를 통해서 하게 되는데, Actionscript3는 특성상 이벤트기반이기에... 그냥 여러개가 연결이 되도 이벤트가 발생하고, 그 발생한 이벤트객체에서 socket이 들어있어서 그걸 이용하면 되구요.

그 소켓에 다시 이벤트를 걸어주면 됩니다. 그 소켓은 client와 연결된 소켓! 기존 client소켓처럼 쓰면 됩니다^^
데이터는 read, write로 주고 받으면 되죠.

아래는 간단한 예제를....-_-
ServerSocketTest.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
applicationComplete="windowedapplication_applicationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.ServerSocketConnectEvent;
import flash.net.ServerSocket;
import flash.net.Socket;

import mx.events.FlexEvent;

private var socketPolicyUtil:SocketPolicyUtil;

private var serverSocket:ServerSocket;
private var listSocket:Vector.<Socket>;

protected function windowedapplication_applicationCompleteHandler(event:FlexEvent):void
{
socketPolicyUtil = new SocketPolicyUtil();

// 소켓리스트 초기화
listSocket = new Vector.<Socket>;

serverSocket = new ServerSocket();

serverSocket.addEventListener(Event.CONNECT, connectHandler);
serverSocket.addEventListener(Event.CLOSE, onClose);

serverSocket.bind(10000, "127.0.0.1");

serverSocket.listen();
trace("Listening on " + serverSocket.port);
}

private function connectHandler(event:ServerSocketConnectEvent):void
{
// The socket is provided by the event object
var socket:Socket = event.socket as Socket;
listSocket.push(socket);

socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
socket.addEventListener(Event.CLOSE, onClientClose);
socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);

socket.writeUTFBytes("Connected.");
socket.flush();

trace("Sending connect message");
}

private function socketDataHandler(event:ProgressEvent):void
{
var socket:Socket = event.target as Socket;

// Read the message from the socket
var message:String = socket.readUTFBytes(socket.bytesAvailable);
trace("Received: " + message);

// 등록된 소켓에 모두 전송
for each (var s:Socket in listSocket)
{
s.writeUTFBytes(message);
s.flush();
}
}

private function onClientClose(event:Event):void
{
trace("Connection to client closed");
var socket:Socket = event.target as Socket;

// 등록된 소켓 삭제
var i:int = 0;
for each(var s:Socket in listSocket)
{
if (s == socket)
{
trace("같음");
listSocket.splice(i, 1);
return;
}
i++;
}
}

private function onIOError(event:IOErrorEvent):void
{
trace("IOError: " + event.text);
}

private function onClose(event:Event):void
{
trace("Server socket closed by OS.");
}
]]>
</fx:Script>

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:WindowedApplication>

그냥 코드만 봐도 그리 어렵지 않아요.
서버소켓을 생성하고, 연결되는 소켓들은 list(Vector)에 추가해서 관리하게 되고, 끊어지면 list에서 빼버리고, 대화요청이 들어오면 받아서 모두에게 뿌려주면 돼요.

여기서 제가 만든 클래스가 하나 있는데요. SocketPolicyUtil클래스인데, 크로스 도메인을 위한 클래스입니다. 아래에서 설명을....-_-


크로스 도메인 설정 클래스
여기서 제가 보안샌드박스를 위한 클래스를 하나 만들었는데요. 크로스도메인에서 socket요청이 들어온 경우에는 crossdomain.xml을 넘겨줘야하는데, 그것도 air에서 다 할 수 있습니다.
타 도메인에서 요청하는 경우, 클라이언트 측에서는 843포트를 통해 crossdomain.xml을 요청하게 되어있습니다. 물론 클라이언트에서 843이 아닌 다른 포트로 요청을 원하면 바꿀 수 있지요.
 클라이언트 측에 이런 코드를 넣으면 되죠. 그러면 10001로 포트를 요청하죠.
Security.loadPolicyFile("xmlsocket://127.0.0.1:10001");

SocketPolicyUtil.as
package
{
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.ServerSocketConnectEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.ServerSocket;
import flash.net.Socket;

public class SocketPolicyUtil
{
private var serverSocket:ServerSocket;

public function SocketPolicyUtil(port:int = 843)
{
serverSocket = new ServerSocket();
serverSocket.bind(port, "127.0.0.1");
serverSocket.listen();
serverSocket.addEventListener(Event.CONNECT, connectHandler);
serverSocket.addEventListener(Event.CLOSE, onClose);
}

private function connectHandler(event:ServerSocketConnectEvent):void
{
var socket:Socket = event.socket as Socket;

socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
socket.addEventListener(Event.CLOSE, onClientClose);
socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);

trace("Policy Connected.");
}

private function socketDataHandler(event:ProgressEvent):void
{
var socket:Socket = event.target as Socket;

var message:String = socket.readUTFBytes(socket.bytesAvailable);
trace("Policy received : " + message);

var file:File = new File(File.applicationDirectory.nativePath + File.separator + "policy.xml");
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
var data:String = stream.readUTFBytes(stream.bytesAvailable);
trace("policy data = " + data);
socket.writeUTFBytes(data);
socket.writeByte(0);
socket.flush();
}

private function onClientClose(event:Event):void
{
trace("Policy close");
removeClientSocketEvent(event.target as Socket);
}

private function onIOError(event:IOErrorEvent):void
{
trace("ioerror = " + event.text);
}

private function onClose(event:Event):void
{
trace("Server socket closed by OS.");
}

private function removeClientSocketEvent(socket:Socket):void
{
socket.removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
socket.removeEventListener(Event.CLOSE, onClientClose);
socket.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
}
}
}

중요한 점은 policy.xml파일 날릴 때 마지막에 writeByte(0)으로 끝을 맺어줘야한다는...
이 클래스를 보면 policy.xml파일은 File.applicationDirectory에서 찾고 있으니 이걸 src폴더에다가 넣어버리고 패키지할 때 같이 묶어버리면 됩니다. 그리고 그냥 843포트로 열어서 crossdomain.xml파일을 그냥 전송해주기만 하면 되죠. *는 권장사항이 아니니...-_- 해당 도메인이랑 포트번호를 정확히 입력하는게...-_-
policy.xml
<?xml version='1.0' encoding='UTF-8'?>
<cross-domain-policy>
<allow-access-from domain='*' to-ports='*'/>
</cross-domain-policy>


아래는 클라이언트 코드
ClientSocketTest.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768"
applicationComplete="application1_applicationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;

private var socket:Socket;

protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
//Security.loadPolicyFile("xmlsocket://127.0.0.1:10001");
}

protected function btnDisconnect_clickHandler(event:MouseEvent):void
{
if (inputId.text.length < 1)
{
Alert.show("아이디를 입력하세요");
return;
}
socket = new Socket("127.0.0.1", 10000);
socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
currentState = "connect";
labelId.text = inputId.text;
}

protected function btnConenct_clickHandler(event:MouseEvent):void
{
socket.close();
currentState = "disconnect";
}


private function socketDataHandler(event:ProgressEvent):void
{
var message:String = socket.readUTFBytes(socket.bytesAvailable);
trace("message = " + message);
taChat.text += message + "\n";
}

protected function inputChat_enterHandler(event:FlexEvent):void
{
if (inputChat.text.length < 1)
{
return;
}
socket.writeUTFBytes("[" + labelId.text + "] : " + inputChat.text);
socket.flush();
inputChat.text = "";
}

protected function btnChat_clickHandler(event:MouseEvent):void
{
if (inputChat.text.length < 1)
{
return;
}
socket.writeUTFBytes("[" + labelId.text + "] : " + inputChat.text);
socket.flush();
inputChat.text = "";
}
]]>
</fx:Script>
<s:states>
<s:State name="disconnect"/>
<s:State name="connect"/>
</s:states>

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>

<s:TextInput id="inputId" x="231" y="10" includeIn="disconnect"/>
<s:Button id="btnConenctClose" x="367" y="11" label="접속" label.connect="종료"
click.connect="btnConenct_clickHandler(event)" click.disconnect="btnDisconnect_clickHandler(event)"/>
<s:Label id="labelId" includeIn="connect" x="211" y="10" width="159" height="21"/>

<s:TextArea id="taChat" includeIn="connect" x="10" y="49" width="621" height="402"/>
<s:TextInput id="inputChat" includeIn="connect" x="10" y="459" width="507" enter="inputChat_enterHandler(event)"/>
<s:Button id="btnChat" includeIn="connect" x="526" y="459" label="Button" click="btnChat_clickHandler(event)"/>
</s:Application>


아래 프로그램 설치하고 실행시켜놓은 뒤, 아래사이트를 접속해서 테스트할 수 있어요. 아이피는 127.0.0.1로 하드코딩되어있기 때문에 자기 pc에서 띄워놓고 자기가 접속한 클라이언트에서만 가능해요^^
클라이언트 접속 http://mudchobo.tomeii.com/swf/ClientSocketTest.swf


머드초보 이 작성.

당신의 의견을 작성해 주세요.

  1. Comment RSS : http://mudchobo.tomeii.com/tt/rss/comment/454
  2. 지돌스타 2009/11/26 02:08  편집/삭제  댓글 작성  댓글 주소

    멋지고 좋은 글입니다. 잘보고 갑니다.

  3. 푸카 2009/11/29 07:37  편집/삭제  댓글 작성  댓글 주소

    빠른 좋은글 감사합니다^^. 잘보고 갑니다.

  4. z 2010/02/18 15:55  편집/삭제  댓글 작성  댓글 주소

    zzzzzzzzzzzzzzzzzzzzzz

[로그인][오픈아이디란?]
Adobe AIR 2.0 Beta가 Release되었네요.
Adobe AIR Team 블로그 글 - http://blogs.adobe.com/air/2009/11/adobe_air_2_beta_now_available.html

릴리즈노트는 여기서 - http://labs.adobe.com/wiki/index.php/AIR_2:Release_Notes#Overview

저의 짧은 실력의 릴리즈 노트를 보면......-_-

1. 해당 파일에 대한 기본 애플리케이션으로 지정된 프로그램을 실행할 수 있습니다. 이게 뭔 얘기냐면 doc파일이 word에 지정되어있으면 doc파일을 열어서 word를 실행할 수 있는 기능인 듯-_-

2. 마이크 데이터 엑세스. 마이크 데이터를 저장하고 뭐 삽질할 수 있나봅니다.

3. 대용량 저장소에 대한 발견이 가능해졌는데요. 예를 들어 USB를 연결하게 되면 그걸 AIR프로그램에서 인식할 수 있습니다.

4. 업데이트된 WebKit version. air에서 사용하는 브라우저엔진이 그냥 업데이트 됐다는 것 같은.....

5. 글로벌 에러 핸들링은 뭐지.....

6. 새로운 네트워크 지원. AIR프로그램이 서버프로그램이 될 수 있게 ServerSocket을 지원하네요. 그 외에 UDP랑 TLS/SSL도 지원한다고 써있지만, UDP빼곤 잘 몰라서-_-
아.....네트워크 인터페이스 목록이라는 부분은 그거 같은데, 네트워크 정보를 얻어올 수 있는 그런거. 맥어드레스같은 거 AIR에서 못 읽어왔는데, 읽어올 수 있나봅니다.

7. EXE파일의 PACKAGING이 가능. 원래 AIR파일이 나오는데, 이제 exe파일로도 패키징을 할 수 있습니다.

8. native process API. 이건 다른 프로그램을 AIR프로그램이 실행할 수 있는 API인데, 조금 삽질해보니 제약이 좀 있음. 패키징할 때 지정한 것만 되는 것 같음. 좀 더 삽질을 해봐야할 듯 ^^ 암튼, 프로그램을 제약적이지만 실행할 수 있어요.

9. 데이터베이스 트랜젝션 어쩌구 하는데 잘 모르겠음

다 적으려니까 디게 많네.....-_-
그냥 그외에, 향상된 IPv6을 지원하고, Native Window의 최대사이즈를 증가시켰고, 멀티터치지원하고, IME향상시켰고....영어공부해야겠다.

구축하기에 앞서 Flash Builder 4 Beta 2 다운로드

1. 개발환경 구축
사실 개발환경 구축이라고 하기에는 너무나 간단하지만....-_- 그냥 AIR SDK받아서 Flash Builder 4가 설치된 폴더 안에 있는 sdk에 덮어 씌우면 됩니다.
우선 Adobe AIR 2 Beta SDK와 Runtime 다운로드 - http://labs.adobe.com/downloads/air2.html
받은 sdk파일 (air2_b1_sdk_win_11709.zip)을 Flash Builder 2 sdk폴더에 압축을 덮어씌워서 풀어버립니다. 저의 경로는 아래와 같군요.
C:\Program Files (x86)\Adobe\Adobe Flash Builder Beta 2\sdks\4.0.0

2. 개발하면 돼요-_-

3. 예제 작성
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
width="500" height="500"
applicationComplete="windowedapplication1_applicationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import flash.events.StorageVolumeChangeEvent;
import mx.events.FlexEvent;

protected function windowedapplication1_applicationCompleteHandler(event:FlexEvent):void
{
StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT, mountHandler);
StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT, unmountHandler);
}

private function mountHandler(event:StorageVolumeChangeEvent):void
{
trace(event.rootDirectory.nativePath);
taInfo.text += "drive = " + event.storageVolume.drive + ", type = " +
event.storageVolume.fileSystemType + ", name = " + event.storageVolume.name + "\n";
}

private function unmountHandler(event:StorageVolumeChangeEvent):void
{
taInfo.text += event.rootDirectory.nativePath + " 제거됨\n";
}
]]>
</fx:Script>
<s:TextArea id="taInfo" x="6" y="10" width="484" height="480" verticalScrollPolicy="on"/>
</s:WindowedApplication>


핵심은 StorageVolumeInfo클래스랑 StorageVolumeChangeEvent클래스입니다. 그냥 MOUNT, UNMOUNT이벤트 걸어주면 지가 알아서 다함^^
사용자 삽입 이미지
참조사이트
http://www.adobe.com/devnet/air/flex/articles/exploring_file_capabilities.html
머드초보 이 작성.

당신의 의견을 작성해 주세요.

  1. Comment RSS : http://mudchobo.tomeii.com/tt/rss/comment/452
  2. 지돌스타 2009/11/18 14:10  편집/삭제  댓글 작성  댓글 주소

    좋은 예제 잘보고 가요~ 트랙백 걸고 갑니다.

  3. OpenID Logo hansoo 2010/02/09 12:01  편집/삭제  댓글 작성  댓글 주소

    좋은 예제 잘 익히고 갑니다~

[로그인][오픈아이디란?]
테스트의 중요성은 저번 스프링 강의시간에 충분히 느꼈습니다. 하지만, 역시 귀차니즘 때문에 잘 안만들게 되는 게 테스트인 듯 합니다. 하지만, 한번 만들어놓으면 이래저래 매우 유용한 것이 테스트죠.

다운로드는 여기서....-_-


Java에서는 Junit이라는 것이 있는데, 4버전에서는 Annotation(@)을 이용해서 쉽게 테스트를 만들곤 했는데요. Flex에서도 비슷한 기법을 이용합니다. 메타데이터를 위에다가 붙여서-_- 손쉽게 테스트를 만들 수 있습니다.
[Test]
public function testMyTest():void
{
}

와....Flash Builder를 보면 Java를 많이 따라한 것을 볼 수 있습니다. 예전엔 폴더생성으로만 만들 수 있었던 패키지가 직접적인 패키지 생성메뉴를 만들어서 Package Explorer에서 패키지형태로 볼 수 있습니다.
암튼, 자바와 닮아가는 듯-_-

1. 간단한 프로젝트 생성
Flex Project하나 생성.

2. 서비스 클래스 생성
덧셈 뺄셈 클래스하나 작성
com.mudchobo.test패키지의 Calc클래스 생성
Calc.as
package com.mudchobo.test
{
public class Calc
{
public function Calc()
{
}

public function addition(a:Number, b:Number):Number
{
return a + b;
}

public function subtraction(a:Number, b:Number):Number
{
return a - b;
}
}
}


3. 테스트 생성
New -> Test Case Class -> New FlexUnit 4 test선택. Name은 CalcTest로하고 Finish.
CalcTest.as
package flexUnitTests
{
import com.mudchobo.test.Calc;

import flexunit.framework.Assert;

public class CalcTest
{
private var calc:Calc;

public function CalcTest()
{
}

[Before]
public function before():void
{
calc = new Calc();
}

[Test]
public function testAddition():void
{
var result:Number = calc.addition(50, 50);
Assert.assertEquals(result, 100);
}

[Test]
public function testSubtraction():void
{
var result:Number = calc.subtraction(50, 50);
Assert.assertEquals(result, 0);
}
}
}

여기까지 작성하면 FlexUnitCompiler.mxml이라는 파일이 자동으로 생겼을겁니다. 이건 건드리지 않습니다. 검색해보니 이전방식으로 core생성해서 UIListener를 넣어서 하려고했는데, 이거 그렇게 하는게 아니더군요-_-
심지어 UIListener클래스는 없습니다-_-

4. 테스트 실행
테스트 실행은 package explorer에서 테스트클래스의 오른쪽 마우스버튼을 누르면 "Execute FlexUnit Tests"라는 메뉴가 있습니다. 그걸 선택하면 테스트가 됩니다. FlexUnitApplication.mxml파일도 같이 생기는군요.
테스트단축키는 Alt + Shift + E, F입니다....-_- 해당 편집파일에서 누르면 됩니다.
사용자 삽입 이미지
테스트 결과는 Junit처럼 이렇게 보여줍니다.
사용자 삽입 이미지
Junit이랑 똑같네.

5. 테스트 Suite 생성
이건 테스트를 다 모아서 실행하는 건데, 통합테스트를 할 때 사용하는 듯-_-
New -> Test Suite Class -> New FlesxxUnit4 test 하면 include할 테스트를 패키지에서 선택할 수 있습니다. 선택 후 Finish.
SuiteTest.as
package flexUnitTests
{
import flexUnitTests.CalcSecondTest;
import flexUnitTests.CalcTest;

[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class SuiteTest
{

public var test1:flexUnitTests.CalcSecondTest;
public var test2:flexUnitTests.CalcTest;
}
}

그냥 저렇게 선언해두고, 오른쪽버튼 눌러서 "Execute FlexUnit Tests" or 알트 + 쉬프트 + E, F하면 통합테스트를 합니다.

6. 그외의 기능
저도 더 써봐야 알 것 같은데, Flex는 이벤트기반이다보니 Async와 UI구조가 많은데요. Async구조도 손쉽게 테스트를 할 수 있습니다.
[Test(async,ui)]

이런식으로 하면 될 듯 한데, 안해봐서 잘 모르겠네요-_-

참고자료
http://www.insideria.com/2009/05/flashbuilder4-will-support-fle.html
http://balajisridhar.wordpress.com/2009/10/05/flexunit-integration-in-flash-builders-new-awatar-in-beta2/
머드초보 이 작성.

당신의 의견을 작성해 주세요.

[로그인][오픈아이디란?]
« Prev : 1 : 2 : 3 : 4 : Next »