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[code]<?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>
[/code]
그냥 코드만 봐도 그리 어렵지 않아요.
서버소켓을 생성하고, 연결되는 소켓들은 list(Vector)에 추가해서 관리하게 되고, 끊어지면 list에서 빼버리고, 대화요청이 들어오면 받아서 모두에게 뿌려주면 돼요.
여기서 제가 만든 클래스가 하나 있는데요. SocketPolicyUtil클래스인데, 크로스 도메인을 위한 클래스입니다. 아래에서 설명을....-_-
크로스 도메인 설정 클래스여기서 제가 보안샌드박스를 위한 클래스를 하나 만들었는데요. 크로스도메인에서 socket요청이 들어온 경우에는 crossdomain.xml을 넘겨줘야하는데, 그것도 air에서 다 할 수 있습니다.
타 도메인에서 요청하는 경우, 클라이언트 측에서는 843포트를 통해 crossdomain.xml을 요청하게 되어있습니다. 물론 클라이언트에서 843이 아닌 다른 포트로 요청을 원하면 바꿀 수 있지요.
클라이언트 측에 이런 코드를 넣으면 되죠. 그러면 10001로 포트를 요청하죠.
[code]Security.loadPolicyFile("xmlsocket://127.0.0.1:10001");[/code]
SocketPolicyUtil.as[code]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);
}
}
}[/code]
중요한 점은 policy.xml파일 날릴 때 마지막에 writeByte(0)으로 끝을 맺어줘야한다는...
이 클래스를 보면 policy.xml파일은 File.applicationDirectory에서 찾고 있으니 이걸 src폴더에다가 넣어버리고 패키지할 때 같이 묶어버리면 됩니다. 그리고 그냥 843포트로 열어서 crossdomain.xml파일을 그냥 전송해주기만 하면 되죠. *는 권장사항이 아니니...-_- 해당 도메인이랑 포트번호를 정확히 입력하는게...-_-
policy.xml[code]<?xml version='1.0' encoding='UTF-8'?>
<cross-domain-policy>
<allow-access-from domain='*' to-ports='*'/>
</cross-domain-policy>[/code]
아래는 클라이언트 코드
ClientSocketTest.mxml[code]<?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>[/code]
아래 프로그램 설치하고 실행시켜놓은 뒤, 아래사이트를 접속해서 테스트할 수 있어요. 아이피는 127.0.0.1로 하드코딩되어있기 때문에 자기 pc에서 띄워놓고 자기가 접속한 클라이언트에서만 가능해요^^
클라이언트 접속
http://mudchobo.tomeii.com/swf/ClientSocketTest.swf
댓글을 달아 주세요
happykju1218@naver.com
제아이팟은 탈옥했는데요 인증서꼭있어야되나요? 지금 그인증서살 여건이안되어든여
출시할것도아니고 그냥 해볼려는건데 인증어생성하라고 플래시에서 막그러네요 ....
메일로 알려주시면 감사하겠스빈다 ㅠㅠ
탈옥했다면 아무 .p12인증서로 해도 됩니다~
인증서가 안되서그러는데 자세히 알려주시거나 보내주시면안될까요????? ;;
happykju1218@naver.com
저는 탈옥한 것이라 아무 .p12인증서로 했습니다ㅠㅠ
휴,...이제 인증에 성공했습니다...감사합니다.^^ 그런데 성능이 썩...(_ _) 기대치 만큼에 많이 못미치네요....오히려 안드로이드에서 더 좋은 성능을 보이네요.... 물론 다 테스트해본것은 아니지만 Alternativa3d로 만들어서 안드로이드와 아이폰 두대에 넣어봤는데....아이폰은 안습이네요..(_ _)
암튼 감사합니다. ^___________^
저 맥북이 없어서그런데
p12 하구 mobileprovision 보내주심 안될까요?
kju1218님 저도 빌려서 사용하는지라 드리기가 어렵네요... 아는 업체꺼 빌려쓰고 있거든요..
그런데 제 아이폰 개발 기기 등록해서 내려받은거라서 님께서 컴파일은 하신다 해도 아이폰에
설치가 안될겁니다....물론...탈옥하셨다면...가능할거 같지만요..^^ 죄송합니다. ^^
제 경우엔 .p12 파일과 .mobileprovision 파일 모두 정상적으로 넣고 제작해도 ipa 파일이 생성이 안되네요.
오류가 나는건 아닌것 같고 뭔가 만들다 마는거 같은데...
결과물에
.xml
air어쩌구.tmp
AOTBuildOutput어쩌구.tmp 폴더 만 생겼는데 ipa는 안 생기는군요.
혹시 왜 그런지 아시는분~ cs5는 구매한 정식 한글판입니다.
모든 업데이트 완료했구요.
음.....저도 정확한 원인은 잘 모르겠네요ㅠㅠ
저도 많이 안해봐서ㅠㅠ
비밀댓글입니다
아이폰용은 무료로 안되지만,
안드로이드는 무료로 만들 수 있는데....
그 eclipse에 안드로이드용 인증서 생성하는거 검색해보시면... 나올겁니다^^
마침, 찾고 있었는데 올려 주신 글이 도움이 됐습니다. 감사합니다.
안녕하세요 flash 로 아이폰 공부를 해보려고해서 탈옥하고 하려는데요
.p12는 그냥 인터넷 검색해서 만들었는데 .mobileprovision는 어떻게 만드나요?
구글링 해도 잘 못찾아서 그런데 조언좀 부탁드립니다. 아무 .mobileprovision 만드는 법좀 ㅠㅜ
한가지 질문하겠습니다. p12 파일을 안드로이드꺼 사용해도 어짜피 mobileprovision은 개발자 등록해야 생성할 수 있는거 아닌가요?