XMLSocket은 뭔가 이상하군요-_-;
그냥 Socket클래스는 그냥 쓰던 소켓같은데 XMLSocket은 삽질한 결과 이상하게 주고 받는 것 같아요.
우선 보낼 때 이상하게 나눠서 보내게 되더라구요.
그리고 \0을 끝으로 인식하는 듯합니다. 그래서 자바서버에서 보낼 때 pw.println("blur~blur~")이렇게 보낼 때에는 blur~blur~\r\n이 가게 되는데 저것이 끝이라고 인식을 못하더라구요.
그래서 보낼 때에는 pw.print("blur~blur~\n\0") 이라고 보내야해요.
그리고,
mudchobo : 안녕하세요\n\0 라고 보내면, 이상하게 나눠서 호출이 되더라구요-_-;
mudchobo : 데이터를 받고, 그다음에 안녕하세요\n\0을 받아요-_-;
왜그럴까요-_-; 어쨌든, 편법으로 만든 채팅프로그램입니다.
서버(JAVA)
ChatServer.java
[code]package com.mudchobo.chat;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class ChatServer {
private ServerSocket server;
void startServer() {
try {
server = new ServerSocket(10001);
System.out.println("접속을 기다립니다.");
HashMap<String, PrintWriter> hashMap =
new HashMap<String, PrintWriter>();
while (true) {
Socket sock = server.accept();
ChatThread chatThread =
new ChatThread(sock, hashMap);
chatThread.start();
} // while
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
ChatServer chatServer = new ChatServer();
chatServer.startServer();
}
}
[/code]
ChatThread.java
[code]package com.mudchobo.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
class ChatThread extends Thread {
private Socket sock;
private String id;
PrintWriter pw;
private BufferedReader br;
private HashMap<String, PrintWriter> hashMap;
public ChatThread(Socket sock, HashMap<String, PrintWriter> hashMap)
throws UnsupportedEncodingException, IOException {
this.sock = sock;
this.hashMap = hashMap;
pw = new PrintWriter(
new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
br = new BufferedReader(
new InputStreamReader(sock.getInputStream(), "UTF-8"));
id = br.readLine();
hashMap.put(id, pw);
broadcast(id + "님이 접속하였습니다.");
System.out.println("접속한 사용자의 아이디는 " + id + "입니다.");
}
public void run() {
try {
String line = null;
while ((line = br.readLine()) != null) {
if (line.equals("/q")) {
break;
} else {
broadcast(id + " : " + line);
}
}
} catch (Exception ex) {
System.out.println(ex);
} finally {
hashMap.remove(id);
broadcast(id + " 님이 접속 종료하였습니다.");
System.out.println(id + " 님이 접속 종료하였습니다.");
try { if (sock != null) sock.close(); } catch (Exception ex) {}
}
}
public void broadcast(String msg) {
Collection<PrintWriter> collection = hashMap.values();
Iterator<PrintWriter> iter = collection.iterator();
while (iter.hasNext()) {
PrintWriter pw = (PrintWriter) iter.next();
pw.print(msg + "\n\0");
pw.flush();
}
}
}
[/code]
저 부분만 바뀌었어요 ^^
이제 클라이언트로-_-;
'플렉스(Flex)'에 해당되는 글 57건
- 2007.11.15 [FLEX] 서버(JAVA)-클라이언트(FLEX) 모델의 채팅프로그램1(XMLSocket이용) 5
- 2007.11.10 [FLEX] 서버(JAVA)-클라이언트(FLEX) 모델의 채팅프로그램2(Socket이용) 12
- 2007.11.10 [FLEX] 서버(JAVA)-클라이언트(FLEX) 모델의 채팅프로그램1(Socket이용) 8
- 2007.11.04 [FLEX] FlexComponent 플렉스2차과정 2일차 후기 및 내용정리2
- 2007.11.04 [FLEX] FlexComponent 플렉스2차과정 2일차 후기 및 내용정리1
이번에는 클라이언트를 보겠습니다.
참고로 예제로 배우는 플렉스2에 있는 CODE7_13을 참고했습니다.
(틀만 가져다가 썼습니다 ^^)
FLEX3 BETA2에서 테스트해봤습니다.
클라이언트(FLEX)
ChatClient_Flex.mxml
[code]<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp()">
<mx:Script>
<![CDATA[
private var socket:Socket = new Socket();
[Bindable]
public var userId:String;
private function initApp():void {
currentState = "logon";
}
public function logon():void {
socket = new Socket("127.0.0.1", 10001);
socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
userId = tUserId.text;
socket.writeUTFBytes(userId + "\n");
socket.flush();
currentState = "chat";
}
private function socketDataHandler(event:ProgressEvent) :void {
var str:String = socket.readUTFBytes(socket.bytesAvailable);
trace(str);
trace("음");
var trimstr:String = str.substr(0, str.indexOf("\r\n"));
log.text += trimstr + "\n";
}
public function send():void {
socket.writeUTFBytes(msg.text + "\n");
socket.flush();
msg.text = "";
}
]]>
</mx:Script>
<mx:Panel id="panel" width="100%" height="100%" verticalAlign="middle"
horizontalAlign="center">
<mx:ControlBar id="cb" height="44" />
</mx:Panel>
<mx:states>
<mx:State name="logon">
<mx:AddChild relativeTo="{panel}">
<mx:HBox>
<mx:Label text="User Id:" />
<mx:TextInput id="tUserId" enter="logon()" />
<mx:Button label="Logon" click="logon()" />
</mx:HBox>
</mx:AddChild>
</mx:State>
<mx:State name="chat">
<mx:SetProperty target="{panel}" name="title"
value="접속자 ID : [{userId}]" />
<mx:AddChild relativeTo="{panel}">
<mx:TextArea id="log" width="100%" height="100%" editable="false"/>
</mx:AddChild>
<mx:AddChild relativeTo="{cb}">
<mx:HBox width="100%" paddingTop="0" paddingBottom="0">
<mx:TextInput id="msg" enter="send()" width="100%" />
</mx:HBox>
</mx:AddChild>
</mx:State>
</mx:states>
</mx:Application>
[/code]
처음에 소켓이 조금 헷깔렸는데-_-; 이제 좀 알것같네요.
우선 아이디를 입력하고 로그인을 클릭하면 logon함수를 실행하는데 socket에 이벤트리스너를 등록해요.
socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
이거를 등록하게 되면, 서버쪽에서 데이터를 받게 되면 이벤트가 발생되는데 socketDatahandler라는 함수를 호출하라는 얘기죠.
서버가 데이터를 던져주게되면 저함수를 호출해서 readUTFBytes를 호출하면 데이터를 받아올 수 있죠.
※readMultiByte(socket.bytesAvailable, "euc-kr") 이렇게하면
서버쪽에서 UTF-8로 안만들어도 되는데요.
UTF-8이 대세기때문에-_-; UTF-8을 활용합시다-_-;
채팅프로그램은 LCDS를 이용해서 메시지서비스를 하게 되면 매우 간단하게 작성할 수 있습니다.
하지만, 뭔가 자유도가 부족하군요-_-; 그래서 서버를 자바로하고 클라이언트를 FLEX로 한 프로그램을 만들어봤습니다.
플렉스 소켓으로 삽질하시는 분들께 도움이 되고자--;(뭐 도움은 안되겠지만-_-;)
JAVA 6.0에서 테스트했습니다.
서버(JAVA)
ChatServer.java 와 ChatThread.java 두개의 파일입니다.
ChatServer클래스에는 main클래스가 있으며, accept()를 호출해서 클라이언트의 접속을 기다리다가 접속이 되면 스레드를 시작을 하게 되는 구조입니다.
ChatServer.java
[code]package com.mudchobo.chat;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class ChatServer {
private ServerSocket server;
void startServer() {
try {
server = new ServerSocket(10001);
System.out.println("접속을 기다립니다.");
HashMap<String, PrintWriter> hashMap =
new HashMap<String, PrintWriter>();
while (true) {
Socket sock = server.accept();
ChatThread chatThread =
new ChatThread(sock, hashMap);
chatThread.start();
} // while
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
ChatServer chatServer = new ChatServer();
chatServer.startServer();
}
}
[/code]
우선 startServer를 보시면, ServerSocket을 생성합니다. 그리고, HashMap을 하나 생성하는데 이것은 id와 PrintWriter, 즉, 해당 스레드마다 각각의 PrintWriter를 저장해서 다른 클라이언트에게 뿌려줄 때 사용됩니다.
그래서 Thread만들 때 hashMap을 같이 넘겨주도록 합니다.
ChatThread.java
[code]package com.mudchobo.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
class ChatThread extends Thread {
private Socket sock;
private String id;
PrintWriter pw;
private BufferedReader br;
private HashMap<String, PrintWriter> hashMap;
public ChatThread(Socket sock, HashMap<String, PrintWriter> hashMap)
throws UnsupportedEncodingException, IOException {
this.sock = sock;
this.hashMap = hashMap;
pw = new PrintWriter(
new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
br = new BufferedReader(
new InputStreamReader(sock.getInputStream(), "UTF-8"));
id = br.readLine();
hashMap.put(id, pw);
broadcast(id + "님이 접속하였습니다.");
System.out.println("접속한 사용자의 아이디는 " + id + "입니다.");
}
public void run() {
try {
String line = null;
while ((line = br.readLine()) != null) {
if (line.equals("/q")) {
break;
} else {
broadcast(id + " : " + line);
}
}
} catch (Exception ex) {
System.out.println(ex);
} finally {
hashMap.remove(id);
broadcast(id + " 님이 접속 종료하였습니다.");
System.out.println(id + " 님이 접속 종료하였습니다.");
try { if (sock != null) sock.close(); } catch (Exception ex) {}
}
}
public void broadcast(String msg) {
Collection<PrintWriter> collection = hashMap.values();
Iterator<PrintWriter> iter = collection.iterator();
while (iter.hasNext()) {
PrintWriter pw = (PrintWriter) iter.next();
pw.println(msg);
pw.flush();
}
}
}
[/code]
생성자를 보게 되면 해당클라이언트와 통신을 하도록 하는 PrintWriter와 BufferedReader를 만듭니다.
우선 접속하게 되면 클라이언트쪽에서 id를 보내도록 되어있죠.(나중에 클라이언트할때 설명-_-;)
그리고, run메소드를 보시게 되면, BuferedReader에서 readLine을 하게 되어서, 채팅데이터를 받게 되면, broadcast함수를 호출하게 되어, 연결되어 있는 모든 클라이언트에게 채팅데이터를 보냅니다.
hashmap에 printwriter를 저장해서 가능하죠 ^^
※플렉스는 UTF-8로 데이터를 전송하게 됩니다. 그래서 데이터를 받을 때 UTF-8로 받아야겠죠?
[code]pw = new PrintWriter(
new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
br = new BufferedReader(
new InputStreamReader(sock.getInputStream(), "UTF-8"));
[/code]
위와 같이 "UTF-8"이라고 해주면 돼요 ^^
UTF-8빼면 한글이 깨져버려요 ^^
길이너무 길어져서 다음 글로-_-;
Array랑 ArrayCollection이 차이가 없는건지-_-; 뭐가 다른건지-_-;
ActionScript에는 배열이라는 게 없다더군요.
어떤 타입이든 다 넣을 수 있는 Collection이라고 하네요.
즉, 자바에서 벡터, 리스트 뭐 이런건가요? ^^
ArrayCollection은 데이터가 바뀌는 것을 모니터링이 가능하답니다.
바인딩해주면 값 바뀌면 자동으로 바뀐다 이런 얘기를 했는데 뭔가 테스트가 필요하겠군요.
DataGrid
요거이도 빠지면 Flex가 아닌 것입니다 ^^ 마스터 하도록 해야합니다!^^
dataProvider라는 것에 값을 넣으면 DataGrid에 값이 표현됩니다.
또한 DataGrid는 자유로워서 콤보박스, 체크박스 등도 넣을 수 있더군요(첨 알았음 ^^)
DataGrid를 이용해서 구구단을 출력해봅시다!
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="setGuGuDan()"
backgroundColor="0xffffff" backgroundImage="">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.controls.Alert;
[Bindable]
public var dp:ArrayCollection = new ArrayCollection();
public function setGuGuDan():void {
for (var i:int=1; i<=9; i++) {
var obj:Object = {};
for (var j:int=2; j<=9; j++){
obj["dan"+j] = j + " X " + i + " = " + (j*i);
}
dp.addItem(obj);
}
}
]]>
</mx:Script>
<mx:DataGrid id="dg" width="100%" height="100%" dataProvider="{dp}">
<mx:columns>
<mx:DataGridColumn headerText="2단" dataField="dan2"/>
<mx:DataGridColumn headerText="3단" dataField="dan3"/>
<mx:DataGridColumn headerText="4단" dataField="dan4"/>
<mx:DataGridColumn headerText="5단" dataField="dan5"/>
<mx:DataGridColumn headerText="6단" dataField="dan6"/>
<mx:DataGridColumn headerText="7단" dataField="dan7"/>
<mx:DataGridColumn headerText="8단" dataField="dan8"/>
<mx:DataGridColumn headerText="9단" dataField="dan9"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
[/code]
DataGrid를 하나 선언해서 dg라는 id를 줬네요. dataProvider는 dp(ArrayCollection)입니다.
바인딩할 때에는 {}를 붙여주는 거라고 하네요.
DataGrid안에 columns태그를 넣어주고 이 태그안에는 DataGridColumn해서 2단부터 9단까지 넣어줬습니다.
headerText는 실제 출력되는 이름을 말하는 것이구요. dataField는 해당 필드의 이름을 말하는 겁니다.
위에 as를 보도록 합시다.
만약 정적으로 넣게 된다면 이렇게 되겠죠.
{dan2: "2 x 1 = 2", dan3: "3 x 1 = 3", dan4: "4 x 1 = 4"},
{dan2: "2 x 2 = 4", dan3: "3 x 2 = 6", dan4: "4 x 2 = 8"},
{dan2: "2 x 3 = 6", dan3: "3 x 3 = 9", dan4: "4 x 3 = 12"},
쭈우우욱~
동적으로 넣게 되면 저 {} 이게 하나의 object가 됩니다.
그래서 object를 하나 선언해서 obj["dan2"] = 2 x 1 = 2; 해버리면 dan2: 2 x 1 = 2가 생기고,
obj["dan3"] = 3 x 1 = 3; 하면 dan3: 3 x 1 = 3이 생기고 그럽니다 ^^
이렇게 9단까지 만든 한줄의 object를 ArrayCollection에 addItem해버리면 됩니다.
ActionScript는 배열의 개념이 아니기때문에 가능한 것이라고 하더군요 ^^
어쨌든 굉장히 유연해요-_-;
차트를 보도록합시다.
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%" height="100%">
<mx:XML id="results" xmlns="">
<gen>
<result month="Jan-03">
<apple>200781</apple>
<orange>225971</orange>
<banana>161280</banana>
</result>
<result month="Feb-03">
<apple>188249</apple>
<orange>179611</orange>
<banana>150795</banana>
</result>
<result month="Mar-03">
<apple>229774</apple>
<orange>214767</orange>
<banana>189889</banana>
</result>
</gen>
</mx:XML>
<mx:ColumnChart id="chart" dataProvider="{results.result}"
showDataTips="true" width="100%" height="100%">
<mx:horizontalAxis>
<mx:CategoryAxis dataProvider="{results.result}"
categoryField="@month" />
</mx:horizontalAxis>
<mx:series>
<mx:Array>
<mx:ColumnSeries
yField="apple" displayName="Apple" />
<mx:ColumnSeries
yField="banana" displayName="Banana" />
<mx:ColumnSeries
yField="orange" displayName="Orange" />
</mx:Array>
</mx:series>
</mx:ColumnChart>
</mx:Application>
[/code]
가장 일반적인 컬럼차트인데요. dataProvider는 results의 result로 지정했네요.
horizontalAxis는 가로값은 month로 "Jan-03", "Feb-03", "Mar-03" 으로 나오구요.
series안에 ColumnSeries가 있는데 3가지가 있네요.
apple, banana, orange 값을 보여주는데 displayName은 앞글자는 대문자로 표기를 합니다 ^^
다른 차트도 해보시면 알겠지만 사용법은 비슷합니다.
여러개의 차트를 섞어서도 사용할 수 있습니다.
LineChart와 PlotChart를 동시에 사용할 수 있습니다. 라인차트는 줄만 나와서 그 해당 값이 어딘지 정확하게 집어줄 수 없는데 PlotChart는 가능하기 때문에 섞을 수 있습니다 ^^
마지막에 sprite했는데 졸려서 소스를 못 담아왔군요-_-;
여기까지-_-;
오늘은 컴포넌트(Component)에 대해서 집중적으로 다뤄봤는데요.
직접 사용해봐야지 완벽하게 익힐 수 있을 듯하네요 ^^
우선 크게 Container와 Control로 나뉘는군요.
Container는 VBox, HBox, Canvas, ViewStack 등등~
Control은 Button, DataGrid, Aleart 등등~
Container는 무엇을 담을 수 있는 건데요.
레이아웃형태로는 VBox, HBox, Canvas가 있구요.
VBox는 컴포넌트들을 세로로 정렬하는 거구요. HBox는 반대로 가로로 정렬하겠죠?
Canvas는 좌표값을 줘가면서 원하는 위치에 컴포넌트를 가져다가 놓는거에요.
대신 브라우저창 크기가 변경이 되면, Canvas는 그 위치를 지킨다는 것 같군요.
네비게이터형태로는 ViewStack, Tabnavigator, Arccordion이 있어요.
ViewStack이 빠진 Flex는 Flex가 아니래요 ^^
숙제를 내줬는데 UIComponent의 모든 property, method, event, style 등등의 속성들을 다 한번씩 써보고 느낌점을 정리해보라는군요. 작살나게 많군요-_-; 그래도 다 해봐야겠습니다 ^^
Sprite라는 것은 눈에 보이는 최소단위의 컨테이너라고 하는데 잘 이해가 가지 않아요 ^^
오늘 마지막 시간에 Sprite로 라인도 긋고 그랬는데 해봐야겠습니다 ^^
스타일지정하는법!
[code]해당컴포넌트.setStyle('backgroundGradientColors', [0xCCCCCC, 0xCCCCCC]);
[/code]
앞에 Style속성이름을 넣구, 뒤에는 값을 넣으면 되더군요!
property는 그냥 해당컴포넌트.x = 500; 이런식으로 넣어주면 돼요!
ViewStack
유용하고 자주 쓰는 컴포넌트랍니다 ^^
[code]뷰스택ID.SelectedChild = 해당컴포넌트ID;
or
뷰스택ID.SelectedIndex = 0~~;
[/code]
클랙했을 때 저렇게 SelectedChild에 컴포넌트id를 넣어주면 화면이 다른건 숨기고 그 해당 컴포넌트를 보여지게 되죠. 이 컴포넌트들은 당연히 ViewStack태그 안에 있어야 겠죠?
ViewStack속성에 creationPolicy라고 해서 생성할 때 정책을 말하는 건데 보통 ViewStack은 auto가 기본값으로 되어있어서 첫번째 놈만 먼저 생성되고 나머지는 SelectedChild에 들어가게 되면 생성하게 되는데요.
이렇게 되면 그 두번째, 세번째 컴포넌트들은 아직 안만들어져서 거기에 있는 것을 컨트롤하려고 하면 null에러 같은 것을 낸다는군요.
all로 하면 한꺼번에 다 생성하긴 하는데, 가능하면 피하라고 하는군요 ^^
Spacer
요고이는 처음 봤는데 별거 아니더군요. 예를 들어서-_-;
[code]<mx:HBox width="800">
<mx:Label text="Spacer전에오는버튼" />
<mx:Spacer width="100%" />
<mx:Button label="Spacer다음에오는버튼"/>
</mx:HBox>
[/code]
그냥 HBox의 width가 800이면 Label앞에 두고, 중간에 여백을 어느정도 주는 거죠 ^^
100%니까 Label하고 Button보여주고 남은 것은 다 공백으로해서 컨테이너 끝에 붙어있겠죠? ^^
뭔가 열심히 적어왔는데 이번주는 너무 피곤했군요-_-;
빡쎘습니다-_-;