SlideShare une entreprise Scribd logo
1  sur  51
www.javaspecialist.co.kr
www.javaspecialist.co.kr
www.javaspecialist.co.kr 2
www.javaspecialist.co.kr
www.javaspecialist.co.kr
Communication API
윈도우 객체를 통한 페이지 사이의 메시지 전달에 대하여 알아본다.
3
www.javaspecialist.co.kr
www.javaspecialist.co.kr
커뮤니케이션 API
MessageEvent와 postMessage() 메시지 송수신 주체
메시지 송수신
크로스 도큐먼트 메시징
채널 메시징
www.javaspecialist.co.kr
1. 커뮤니케이션 API
• 배경
– 실행중인 브라우저에서 프레임, 탭, 그리고 윈도우 사이의 통신은 보안상의 이유로 모두
제한되어 있다.
– 브라우저는 다른 도메인에서 로드된 컨텐츠를 획득하거나 수정할 경우 보안 예외를 발생
시키고 작동을 차단한다.
– 브라우저 제작사와 표준화 단체는 다른 도메인 문서 사이에 메시징 기능 필요함을 서로 합
의하여 다른 도메인 문서 사이에 메시징을 이용할 수 있도록 했다.
– 이로 인해 탄생한 것이 Communication API이며 이를 이용하면 iframe, 탭, 윈도우 사이에
보안 통신이 가능하다.
• Communication API
– 커뮤니케이션 API는 단지 웹 페이지 사이의 통신을 위한 API는 아님.
– 메시지를 보내는 표준 방식은 postMessage API로 정의
– postMessage() 메서드를 이용하면 자바스크립트 컨텍스트 사이에 비동기 메시지 통신을
제공
– postMessage() 메서드는 같은 도메인 문서 사이의 통신에도 사용되지만 브라우저의 동일
도메인 정책(Cross-Origin Resource Sharing policy)에 의해 허용되지 않는 문서 사이의 통
신에 더욱 유용하게 사용
• 용도
– Cross-document 통신
– 웹 워커와 같은 자바스크립트 컨텍스트간의 통신
– SSE(Server-Sent Event) 통신
5
www.javaspecialist.co.kr
2. MessageEvent와 postMessage()
• 메시지 송신
– 메시지를 보내는 표준 방식은 postMessage API로 정의
– 메시지를 보낼 때 postMessage(data, [port], targetOrigin)으로 보냄
• 메시지 수신 처리
– 메시지가 도착하면 message 이벤트 발생
– MessageEvent는 메시지 수신측에서 사용하는 이벤트 객체
– 메시지 수신처리하는 콜백함수 인자로 MessageEvent 객체가 전달됨
– MessageEvent 객체의 속성을 통해 수신되는 데이터를 알 수 있음
속성 설명
data 수신되는 데이터가 저장되어 있다.
origin
메시지 송신처의 도메인이다. 신뢰할 수 없는 도메인에서 온 메시지는 무시할 수
있다.
source 메시지를 보내는 윈도우 객체이다.
ports 메시지 송신 시 지정한 포트의 복사본이다. Channel Messaging에서 사용한다.
lastEventId 마지막 이벤트 ID이다. Server-Sent Event에서 사용한다.
MessageEvent 속성
6
www.javaspecialist.co.kr
3. 메시지 송수신 주체
• 커뮤니케이션 API에서 통신의 종류별로 postMessage() 메서드와 message 이벤트를 사용하는 객
체가 다릅니다.
• 각 통신 종류별 사용되는 객체
– Cross document : window 객체
• 보내거나 받는 쪽은 상대방의 윈도우 객체를 알아야 함
• targetWindow.postMessage(data, "*");
• sourceWindow.onmessage = function(){};
– Channel : MessagePort 객체
• channel.port1.postMessage(data, "*");
• channel.port2.onmessage = function(){};
– Web Workers : Worker 객체
• worker.postMessage(data, "*");
• worker.onmessage = function(){};
• 워커에서 메시지를 주고받을 때에는 window 객체를 이용함
– Server-Sent Events : EventSource 객체
• 서버로부터 수신 이벤트 처리
• eventSource.onmessage = function(){};
7
www.javaspecialist.co.kr
4. 메시지 송수신
• 메시지 송신
– 메시지를 보내는 쪽에서는 postMessage(data, [ports,] targetOrigin) 메서드를 사용.
– postMessage() 메서드의 각 파라미터는 다음과 같다.
• data : 송신할 메시지(자바스크립트 객체)이다.
• ports : 채널 메시지 전송 시 공유할 포트배열이며, 생략 가능하다.
• targetOrigin : 수신처의 도메인이다.
• var targetWindow = window.parent.frames[1]
• targetWindow.postMessage(position, "*")
• 메시지 수신
– 메시지 수신측에서는 메시지를 수신할 때 발생하는 message 이벤트를 이용.
– message 이벤트 핸들러 메서드의 인자로 넘어오는 MessageEvent 객체의 속성을 이용하
여 수신된 메시지를 사용
window.onmessage = function(event){
// 원하는 도메인에서만 오는 경우만 처리하고자 할 경우
if(event.origin =="http://localhost"){
document.getElementById("display").innerHTML = event.data;
}
};
8
www.javaspecialist.co.kr
5. 크로스 도큐먼트 메시징
• 크로스 도큐먼트 메시징
– 둘 이상의 웹 페이지가 서로 데이터를 주고 받을 수 있
음
– 수신 측 윈도우의 postMessage() 호출
– 자신의 window 에 대해 message 이벤트 핸들러를 지
정하면 됨
• CORS(Cross-Origin Resource Sharing) policy 해결
– CORS 정책(동일 도메인 정책)은 HTML문서 내에서 자
기가 속해있는 도메인이 아닌 다른 도메인의 자원을 호
출하면 브라우저 마다 약간의 차이가 있지만 요청자체
를 브라우저에서 차단한다.
– Communication API를 이용하면 내부 프래임들이 서로
다른 도메인에 존재하더라도 내부의 다른 도메인 프래
임들끼리 데이터를 주고받을 수 있다.
– 프레임을 포함하는 메인 윈도우 객체를 통해서 프레임
윈도우 객체를 얻을 수 있기 때문에 가능하다.
– CORS(동일 도메인 정책)는 Ajax에서 자세하게 다룬다.
9
www.javaspecialist.co.kr
예제코드
• Cross document 예제
– Communication/cross-document/sender.html
– Communication/cross-document/receiver.html
• 새로운 프로젝트 생성 후 테스트 할 수 있음
• 동일도메인정책 회피 예제
– Communication/cross-domain/index.html
– Communication/cross-domain/left.html
– Communication/cross-domain/right.html (다른 애플리케이션의 파일임을 가정한다.)
• 새로운 프로젝트 생성 후 테스트 할 수 있음
10
www.javaspecialist.co.kr
6. 채널 메시징
• 채널 메시징은 다대다 메시지 통신을 실현하기 위한 API
• MessageChannel(채널)이라는 채널을 통해 메시지를 송수신
– MessageChannel은 메시지 송수신을 중개하는 객체
– new MessageChannel()로 생성
– 채널 메시징에서 채널의 메시지 출입구를 나타내는 포트는 MessagePort에 정의
– MessagePort는 채널의 메시지 출입구를 나타내는 객체
• 포트 공개
– 메시지 수신측의 포트를 송신측에 전달하면 송신측에서는 수신자가 누구인지 알 필요 없이 전달
받은 포트에 메시지만 전송하면 되므로 publish/subscribe 형태의 일대 다 통신이나 범용적인 라
이브러리 구현에 적합
– 수신측에서는 postMessage() 메서드의 두 번째 인자로 포트의 배열을 지정하여 전달하면 됨
속성과 메서드 설명
start() 포트를 이용할 수 있도록 지정한다.
close() 포트를 닫는다.
postMessage() 메시지 송신에 사용한다.
message
메시지 수신 시 발생하는 이벤트이다. 여러 개의 핸들러를 지정하면 다대다
메시지 통신 구현도 가능하다.
MessagePort의 이벤트속성과 메서드
11
www.javaspecialist.co.kr
예제코드
• 포트 공개 예제
– Communication/one2many/publisher.html
– Communication/one2many/subscriber.html
12
www.javaspecialist.co.kr
www.javaspecialist.co.kr
Web Worker
워커를 이용해 백그라운드에서 작업을 실행할 수 있다.
백그라운드 작업 처리 결과는 통신 API를 이용해 UI 스레드에게 전달해
야 한다.
13
www.javaspecialist.co.kr
www.javaspecialist.co.kr
전용 워커
워커
공유 워커
Lab - 백그라운드로 작업하기
www.javaspecialist.co.kr
1. Web Workers
• 자바스크립트 코드를 백그라운드에서 실행시키기 위한 기술이다.
• 오래 걸리는 작업 수행 시 워커를 이용할 수 있다.
• 워커로는 DOM 조작이 불가능하다.
• 워커가 실행하는 자바스크립트 코드의 저장 인코딩방식은 utf-8이다.
11. Web Workers
DOM UI 스레드
worker
postMessage()
postMessage()
new
UI 변경
메시지를 통해
데이터를 주고받
음
워커로 DOM
을 조작할 수
없음
15
www.javaspecialist.co.kr
2. 전용 워커와 공유 워커
• 워커
– 워커 객체와 백그라운드 프로세스가 일대일로 대응.
– interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
– void postMessage(in any message, in optional sequence<Transferable> transfer);
– attribute Function? onmessage;
– };
• 공유 워커
– 여러 객체가 하나의 백그라운드 프로세스를 공유하는 모델.
– interface SharedWorkerGlobalScope : WorkerGlobalScope {
– readonly attribute DOMString name;
– readonly attribute ApplicationCache applicationCache;
– attribute Function? onconnect;
– };
11. Web Workers
Worker1
(scriptURL = worker.js, "wk")
워커 프로세
스
Worker2
(scriptURL = worker.js, "wk")
워커 프로세
스
Worker1
(scriptURL = worker.js, "wk")
Worker2
(scriptURL = worker.js, "wk")
워커 프로세
스
16
www.javaspecialist.co.kr
Worker interface
SharedWorker interface
3. Worker API
속성/메서드/이벤트 설명
postMessage(message, [ports])
워커에 메시지를 전송한다. postMessage() 메서드는 port의 메서드를 사
용한다.
terminate() 워커를 강제로 종료한다.
error 에러가 발생된 것을 알리는 이벤트이다.
message 워커로부터 메시지가 전달됬을 경우 발생하는 이벤트이다.
port 공유 워커와 통신할 수 있는 MessagePort 객체이다.
connect SharedWorker 객체 생성 시 발생한다.
속성/메서드/이벤트 설명
postMessage(message) 워커에 메시지를 전송한다.
terminate() 워커를 강제로 종료한다.
error 에러를 포착하기 위한 이벤트 핸들러이다.
message 워커로부터 전달되는 메시지를 포착하기 위한 이벤트 핸들러이다.
17
www.javaspecialist.co.kr
4. 전용 워커 사용하기
• 1. 워커 생성(UI JS에서)
– var worker = new Worker("worker.js");
• 2. 워커에 메시지 보내기(UI JS에서)
– 워커가 작업을 시작하도록 할 수 있음
– worker.postMessage(data);
• 3. 워커에서 메시지 수신 처리(워커 JS에서)
– window.onmessage = function(me) {}
• 4. 워커에서 작업 완료 후 결과를 UI에 전송(워커 JS에서)
– window.postMessage(result);
• 5. 워커로부터 메시지를 받은 수신측에서 message 이벤트 처리(UI JS에서)
– worker.onmessage = function(me) { }
var worker = new Worker("worker.js");
UI의 자바스크립트 코드 Worker 가 실행시키는 자바스크립트 코드
5
1
worker.postMessage(data);2 onmessage = function(me) {
//백그라운드 작업
postMessage(result);
};
3
4worker.onmessage = function(me) {
var result = me.data;
}
18
www.javaspecialist.co.kr
Lab
• 백그라운드로 계산한 결과를 반환하는 워커의 자바스크립트 코드를 작성하라.
– 워커 자바스크립트
• worker.js
• UI로부터 메시지를 받으면 2초간 기다린 다음 데이터를 처리함
• 처리 결과는 UI에게로 보내져야 함
– UI 자바스크립트
• main.js
• 계산 버튼이 클릭되면 입력필드의 값을 워커에게 전송, 버튼은 비활성화 되도록 함
• 작업중임을 이미지로 보여줌
• 작업 종료 후 버튼활성화, 이미지 제거
• 제공되는 파일
– wookertest.html
– clock.js
• 아날로그 시계
– worker.png
• 작성해야 하는 파일
– main.js
– worker.js
작업시작 전 작업 중 작업 완료
19
www.javaspecialist.co.kr
Lab (Worker/worker/Lab/end/workertest.html)
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <meta charset="UTF-8">
5. <title>Insert title here</title>
6. <script src="main.js" defer></script>
7. <script src="clock.js" defer></script>
8. </head>
9. <body>
10. <h1>워커 실행</h1>
11. <div>
12. <input type="text" id="msg"/>
13. <input type="button" value="메세지 전송" id="send"/>
14. <input type="button" value="계산" id="calc"/>
15. <input type="button" value="워커 종료" id="stop"/><br>
16. <div id="workerImg"></div>
17. </div>
18. <div id="log"><p>로그</p></div>
19. <canvas id="clockCanvas" width="300" height="300"></canvas>
20. </body>
21. </html>
20
www.javaspecialist.co.kr
Lab
//main.js
1. (function(){
2. function log(msg){
3. var log = document.getElementById("log")|| document.querySelector(".log");
4. if(log) log.innerHTML += msg + "<br>";
5. }
6. var worker = new Worker("worker.js"); //워커 생성
7. worker.onmessage = function(me){
8. log(me.data);
9. calc.removeAttribute("disabled"); //계산 버튼 활성화
10. document.getElementById("workerImg").innerHTML = ""; //작업중 이미지 제거
11. };
12. var sendBtn = document.getElementById("send");
13. sendBtn.onclick = function(){
14. var msg = document.getElementById("msg").value;
15. worker.postMessage(msg); //워커에 메시지 전송
16. };
17. var calcBtn = document.getElementById("calc");
18. calcBtn.onclick = function(){
19. var num = document.getElementById("msg").value;
20. worker.postMessage({"msg":"calc", "num":num}); //워커에 메시지와 데이터 전송
21. calcBtn.setAttribute("disabled", "disabled"); //계산 버튼 비활성화
22. document.getElementById("workerImg").innerHTML = "<img src='worker.png'>"; //작업중 이미지
보여줌
23. };
24. var stopBtn = document.getElementById("stop");
25. stopBtn.onclick = function(){
26. worker.terminate(); //워커 강제 종료
27. calcBtn.removeAttribute("disabled"); //계산 버튼 활성화
28. document.getElementById("workerImg").innerHTML = ""; //작업중 이미지 제거
29. };
30. })();
21
www.javaspecialist.co.kr
Lab
//worker.js
1. onmessage = function(me) {
2. //worker는 js 확장자로 생성함
3. //워커발생시 message 이벤트가 발생하고 message가 넘어옴
4. //워커는 독립된프로세스이므로 화면에 표현안됨. 메인 프로그램에 결과를 넘겨주면 처리해야 함
5. //워커는 비즈니스 로직과 UI를 분리시키는 역할을 함
6. if(me.data.msg == "calc"){
7. //작업을 2초 후에 실행되게 함, 백그라운드 작업임을 보여주기 위함
8. setTimeout(function() {
9. var sum = 0;
10. for(var i=1; i<=me.data.num; i++){
11. sum += i;
12. }
13. //워커를 생성한 곳으로 작업 결과 전송
14. postMessage("워커수행결과 :" + sum);
15. }, 2000);
16. }else{
17. //받은 메세지 반송
18. postMessage("Returned Message :" + me.data);
19. }
20. };
22
www.javaspecialist.co.kr
5. 공유 워커 사용하기
1. 공유워커 생성(UI JS에서)
var sworker = new SharedWorker("worker.js",
wk);
4. 공유워커에 메시지 보내기(UI JS에서)
sworker.port.postMessage(data);
7. 공유워커로부터 메시지를 받은 수신측에서
message 이벤트 처리(UI JS에서)
sworker.port.onmessage = function(me) {}
2. 공유워커 생성 이벤트 처리 (공유워커 JS에서)
window.onconnect = function(me) {}
3. 공유워커 생성시 포트 저장(공유워커 JS에서)
var clients = [];
clients.push(me.port[0]);
5. 공유워커에서 작업시작(공유워커 JS에서)
me.port[0].onmessage = function(me) {}
6. 공유워커의 처리 결과를 UI에 전송(공유워커
JS에서)
client[i].postMessage(result);
var sworker = new SharedWorker("sworker.js","sw");
btn.onclick = function(){
sworker.port.postMessage(data);
};
swworker.port.onmessage = function(me){
var result = me.data;
};
UI의 자바스크립트 코드 SharedWorker 가 실행시키는 자바스크립트 코드
5
1
2 onconnect = function(me){
clients.push(me.ports[0]);
me.ports[0].onmessage = function(e){
//백그라운드 작업
for(var i=0; i<clients.length; i++){
clients[i].postMessage(result);
}
};
};
3
4
6
7
www.javaspecialist.co.kr
Lab
• start.html 문서에서 백그라운드 처리를 시작 한 다음 end.html 문서에서 결과를 표시하는 프
로그램을 작성하자
• SharedWorker(공유 워커)를 이용하면 다른 문서 사이에 워커를 공유할 수 있다.
• 주의사항
– 두 창 사이에 워커를 공유하기 위해서는 location.href 속성을 이용하면 안된다.
– window.open()으로 윈도우를 띄우고 이전 윈도우는 opener.lose() 로 닫아줘서 두 윈도우
사이에 공유워커 프로세스가 유지되도록 해야 한다.(크롬 브라우저에서 Shift+ESC로 확인
가능)
• 제공되는 코드
– start.html
– end.html
• 작성해야 하는 코드
– start.html, end.html 파일의 script 작성
– dowork.js
24
www.javaspecialist.co.kr
Lab
start.html
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <meta charset="UTF-8">
5. <title>Shared Worker 테스트</title>
6. <script type="text/javascript">
7. window.onload = function(){
8. var sw = new SharedWorker("dowork.js","work");
9.
10. document.getElementById("send").onclick = function(){
11. var msg = document.getElementById("msg").value;
12. // TODO 워커에 메세지 전송
13. sw.port.postMessage(msg);
14.
15. //location.href="end.html";
16. window.open("end.html")
17. };
18.}
19.</script>
20.</head>
21.<body>
22. <h1>공유 워커 작업시작</h1>
23. <div>
24. <input type="text" id="msg" />
25. <input type="button" value="작업시작" id="send"/><br>
26. </div>
27.</body>
28.</html>
25
www.javaspecialist.co.kr
Lab
end.html
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <meta charset="UTF-8">
5. <title>Shared Worker 테스트</title>
6. <script type="text/javascript">
7. window.onload = function(){
8. function log(msg){
9. var log = document.getElementById("log")|| document.querySelector(".log");
10. if(log) log.innerHTML += msg + "<br>";
11. }
12. // TODO 공유워커 생성
13. // 인수는 파일명, 이름으로 선언하고 모든 창에서 동일한 파일명, 이름으로
14. // 워커 생성하면 동일한 워커를 사용하는 것으로 함
15. var sw = new SharedWorker("dowork.js","work");
16. sw.port.onmessage = function(me){
17. log(me.data);
18. };
19.
20. opener.close();//이전 창을 닫아준다.
21.}
22.</script>
23.</head>
24.<body>
25. <h1>공유 워커 작업끝</h1>
26. <div id="log"><p>로그</p></div>
27.</body>
28.</html>>
26
www.javaspecialist.co.kr
Lab
1. //doorker.js
2.
3. var target;
4.
5. // 공유워커 생성 시 호출
6. onconnect = function(me){
7. target = me.ports[0];//마지막으로 공유워커를 생성한 포트 정보를 저장함
8.
9. target.onmessage = function(e){
10. //백그라운드로 처리되어야 할 작업
11. setTimeout(function() {
12. var sum = 0;
13. for(var i=1; i<=e.data; i++){
14. sum += i;
15. }
16. target.postMessage(sum);
17. }, 5000);//5초간 쉼
18. };
19.};
27
www.javaspecialist.co.kr 28
www.javaspecialist.co.kr
www.javaspecialist.co.kr
Server-Sent Event
서버의 푸시기술을 정의한 사양에 대하여 알아본다.
29
www.javaspecialist.co.kr
www.javaspecialist.co.kr
Polling
응답 데이터 형식SSE
푸시 데이터 사양
Lab - 푸시 데이터 표현하기
www.javaspecialist.co.kr
1. Polling
• AJAX를 이용해 서버에 비동기 요청을 주기적으로 수행하는 방법은 서버의 데이터가 변경되
고 다음 요청이 발생할 때 까지 신규 데이터를 받지 못하는 단점이 있음
• 그러한 단점을 해결하기 위해 서버에서 데이터가 변경되면 응답하는 Long Polling, 응답을 여
러 개 나눠 보내는 Streaming 등이 사용됐었습니다.
requeset
response
Browser Server
event
requeset
response
Ajax Polling
requeset
Browser Server
event
requeset
response
Long Polling Streaming
requeset
response part
Browser Server
event
response part
event
서버와
동기화
가
안돼 있
는
기간
31
www.javaspecialist.co.kr
2. Server-Sent Event
• 클라이언트 API와 푸시(Push) 데이터를 정의한 사양이다. 사실 속을 들여다 보면 폴링이다.
• 서버로부터 푸시된 데이터를 수집하여 일반적인 DOM이벤트처럼 처리가 가능하다.
• SSE를 사용하면 서버의 갱신된 데이터를 클라이언트에 보여주기 위해 AJAX와 setInterval()
을 사용할 필요가 없다.
• 이벤트 소스 객체 생성
– var eventSource = new EventSource("message.jsp");.
• 이벤트 소스에 onmessage 핸들러 지정
– eventSource.onmessage = function(event) { }
– eventSource.addEventListener("message", function(event) { }, false);
• EventSource의 이벤트
이벤트 핸들러 이벤트 핸들러 이벤트 타입
onopen open
onmessage message
onerror error
32
www.javaspecialist.co.kr
3. 푸시 데이터 형식
• SSE는 EventSource가 자동으로 해석할 수 있도록 서버로부터의 푸시되는 데이터의 규칙이
정해져 있다.
– mime 타입은 text/event-stream, charset 파라미터는 필요 없다.
– 문자 인코딩은 UTF-8로 고정이다.
– 줄 바꿈 코드는 ‘rn’ ‘n’ ‘r’ 모두 유효한다.
– ‘:’(콜론)으로 시작하는 줄은 주석이다.
– 빈 줄이나 파일 끝은 이벤트 구분자가 된다.
– 주석이나 빈 줄 이외는 ‘필드 이름: 필드 값’ 이라는 형식으로 작성된다.
– 필드 값이 없을 경우 콜론 다음을 생략할 수 있다.
– 가독성을 좋게 하기 위해 콜론과 필드 값 사이에 공백 하나를 포함할 수 있다.
33
www.javaspecialist.co.kr
4. 응답데이터 형식의 유효한 필드
• 응답 데이터 형식에 있어서 유효한 필드 이름이 또한 정해져 있음
• event
– 브라우저가 발생시킬 이벤트. 기본은 message 임.
• data
– 서버가 보낼 메시지
– 한 번에 여러 개를 보낼 수 있음
– 값이 없으면 수신측에서 message 이벤트가 발생하지 않음
• id
– 이벤트 ID이다.
– 마지막으로 수신한 이벤트의 ID는 MessageEvent의 lastEventId 속성으로 참조할 수 있으
며 요청 헤더에 'Last-Event-ID'로 포함됨.
• retry
– 다음 재시도 까지 시간 간격을 밀리 초 단위로 지정.
– 생략 시 다음 재시도 간격은 브라우저에 따라 다를 수 있음.
34
www.javaspecialist.co.kr
Lab
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <meta charset="EUC-KR">
5. <title>server sent event</title>
6. <script type="text/javascript">
7. function init() {
8. var source = new EventSource("http://www.javaspecialist.co.kr/ex/SSE/stockserver.jsp");
9. source.addEventListener(
10. "message",
11. function(event) {
12. var data = event.data.split("n");
13. var symbol = data[0];
14. var delta = parseInt(data[1], 10);
15. var cell = document.getElementById(symbol);
16. var currentValue = parseInt(cell.textContent, 10);
17. cell.textContent = currentValue + delta;
18. },
19. false
20. );
21. }
22. </script>
23. </head>
24. <body onload="init()">
25. <h1>Server-Sent Event 예제</h1>
26. <p>서버에서 보내온 데이터를 표시하고 있습니다.</p>
27. <table>
28. <tr><th>Samsung</th><th>LG</th><th>ConSolution</th></tr>
29. <tr><td id="Samsung">55</td><td id="LG">70</td><td id="ConSolution">100</td></tr>
30. </table>
31. </body>
32. </html>
35
www.javaspecialist.co.kr
Lab
• 서버측의 푸쉬 데이터를 위한 코드
http://www.javaspecialist.co.kr/ex/SSE/stockserver.jsp
1. <%@ page contentType="text/event-stream"%>
2.
3. retry: 2000
4. <%
5. String[] symbols = new String[]{"Samsung", "LG", "ConSolution"};
6. for(String symbol : symbols) {
7. int delta = (int)(Math.random() * 10);
8.
9. if(delta < 7) {
10. if(System.currentTimeMillis() % 2 == 0)
11. delta = -delta;
12. %>
13. data: <%= symbol %>
14. data: <%= delta %>
15. <%
16. }
17. }
18. %>
19.
20.
36
www.javaspecialist.co.kr
www.javaspecialist.co.kr
Web Socket
플러그인 없이 웹페이지만으로 소켓 통신을?
37
www.javaspecialist.co.kr
www.javaspecialist.co.kr
WebSocket
www.javaspecialist.co.kr
1. WebSocket
• 현재의 HTTP 표준 프로토콜은 서버에서 문서를 요청하고 웹 페이지를 표시하기 전에 문서가
전송되기를 기다려야 하기 때문에 속도가 느리다.
• WebSockets를 사용하면 텍스트, 이진 배열 또는 BLOB를 통해 데이터를 즉시 주고받을 수
있다.
• WebSocket API는 단순하고 복잡하지 않으며 코드가 거의 필요하지 않는다. 느린 대기 시간
양방향 데이터 교환을 손쉽게 활용하여 온라인 게임, 소셜 네트워크 즉시 알림, 재고 및 날씨
정보 실시간 표시, 기타 적시 데이터를 더 빨리 만들 수 있다.
• WebSockets 구현
– 다음 단계를 수행하면 이 새로운 데이터 교환 기술을 간단하게 구현할 수 있다.
1. WebSocket 프로토콜을 구현하는 클라이언트 브라우저를 사용한다.
2. 클라이언트 websocket을 만드는 웹 페이지에서 코드를 작성한다.
3. Websocket을 통해 클라이언트 요청에 응답하는 웹 서버에서 코드를 작성한다.
• WebSocket 클라이언트 코드 작성
– 웹 페이지 코드는 다음 작업을 해야 한다.
1. WebSocket을 초기화하고 서버에 연결한다.
2. 테스트를 통해 연결에 성공했는지 확인한다.
3. 데이터를 보내고 받는다
39
www.javaspecialist.co.kr
2. WebSocket 구조
Web
Socket 서
버
WebSocke
t
클라이언트
HTTP 요청
서버가 요청을
받아들인 후
Web
Socket 서
버
WebSocke
t
클라이언트
쌍방향 통신
40
www.javaspecialist.co.kr
3. WebSocket 클라이언트 코드
• 웹소켓 서버가 구축되어 있어야 함
• 클라이언트에서 웹소켓 서버에 접속하기 위해 다음과 같이 WebSocket 객체 생성
– var wsSocket = new WebSocket("ws://Web Socket Server URL");
– 웹 소켓 프로토콜은 다음과 같은 새로은 URL 체계를 사용한다.
• ws://
• wss://
• 서버로 메시지를 보낼 때
– wsSocket.send("전송할 Message");
• 서버로부터 메시지를 받을 때 message 이벤트 발생함
• WebSocket 인터페이스 이벤트 핸들러
Event Handler 설명
onmessage Server 로 Message를 전달 받을 때
onopen Web Socket Server 가 열릴 때
onclose Web Socket Server 가 닫힐 때
onerror 에러가 발생할 때
41
www.javaspecialist.co.kr
4. WebSocket 개체, 메서드, 속성
• WebSocket은 WebSocket 프로그래밍에 사용할 수 있는 개체, 메서드 및 속성 집합을 제공한
다.
이름 유형 설명
WebSocket 개체 원격 호스트에 대한 양방향 채널을 제공한다.
close 메서드 WebSocket을 닫는다.
send 메서드 WebSocket을 사용하여 데이터를 서버로 보낸다.
binaryType 속성 onmessage에 수신되는 이진 데이터 형식이다.
bufferedAmount 속성 send를 사용하여 대기 중인 데이터 바이트 수.
extensions 속성 서버가 선택한 확장을 보고한다.
onclose 속성 소켓을 닫을 때 호출되는 이벤트 처리기.
onerror 속성 오류가 있을 때 호출되는 이벤트 처리기.
onmessage 속성 메시지가 수신되었음을 알리는 이벤트 처리기.
onopen 속성 WebSocket이 연결된 경우 호출되는 이벤트 처리기.
protocol 속성 서버가 선택한 프로토콜을 보고한다.
readyState 속성 WebSocket 연결 상태를 보고한다.
url 속성 소켓의 현재 URL을 보고한다.
42
www.javaspecialist.co.kr
Lab
• 톰캣 7에 예제로 포함되어 있음
• Build Path에 catalina-7.0.29.2.jar 파일과 tomcat-juli.jar 파일 포함
– WEB-INF/lib 폴더에 복사하면 안됨
– tomcat-juli.jar
• http://tomcat.apache.org -> Download -> Binaries -> Extras -> JULI log4j jar
– catalina-7.0.39.3.jar
• org.apache.catalina.websocket. 패키지를 포함.
• http://grepcode.com/project/repo1.maven.org/maven2/org.apache.geronimo.ext.tomcat/catalina/
43
www.javaspecialist.co.kr
Lab - HTMLFilter
1. package util;
2. public final class HTMLFilter {
3. public static String filter(String message) {
4. if (message == null)
5. return (null);
6. char content[] = new char[message.length()];
7. message.getChars(0, message.length(), content, 0);
8. StringBuilder result = new StringBuilder(content.length + 50);
9. for (int i = 0; i < content.length; i++) {
10. switch (content[i]) {
11. case '<':
12. result.append("&lt;");
13. break;
14. case '>':
15. result.append("&gt;");
16. break;
17. case '&':
18. result.append("&amp;");
19. break;
20. case '"':
21. result.append("&quot;");
22. break;
23. default:
24. result.append(content[i]);
25. }
26. }
27. return (result.toString());
28.
29. }
30. }
웹소켓 서블릿에서 응답할 때 < > & " 문자 변환에 사용
44
www.javaspecialist.co.kr
Lab - ChatWebsocketServlet.java (1/3)
1. package websocket.chat;
2.
3. import java.io.IOException;
4. import java.nio.ByteBuffer;
5. import java.nio.CharBuffer;
6. import java.util.Set;
7. import java.util.concurrent.CopyOnWriteArraySet;
8. import java.util.concurrent.atomic.AtomicInteger;
9.
10. import javax.servlet.http.HttpServletRequest;
11.
12. import org.apache.catalina.websocket.MessageInbound;
13. import org.apache.catalina.websocket.StreamInbound;
14. import org.apache.catalina.websocket.WebSocketServlet;
15. import org.apache.catalina.websocket.WsOutbound;
16.
17. import util.HTMLFilter;
18.
19. @WebServlet("/ws/chat")
20. public class ChatWebSocketServlet extends WebSocketServlet {
21.
22. private static final long serialVersionUID = 1L;
23.
24. private static final String GUEST_PREFIX = "Guest";
25.
26. private final AtomicInteger connectionIds = new AtomicInteger(0);
27.
28. private final Set<ChatMessageInbound> connections =
29. new CopyOnWriteArraySet<ChatMessageInbound>();
30.
31. @Override
32. protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) {
33. return new ChatMessageInbound(connectionIds.incrementAndGet());
34. }
35.
45
www.javaspecialist.co.kr
Lab - ChatWebsocketServlet.java (2/3)
36. private final class ChatMessageInbound extends MessageInbound {
37.
38. private final String nickname;
39.
40. private ChatMessageInbound(int id) {
41. this.nickname = GUEST_PREFIX + id;
42. }
43.
44. @Override
45. protected void onOpen(WsOutbound outbound) {
46. connections.add(this);
47. String message = String.format("* %s %s", nickname, "has joined.");
48. broadcast(message);
49. }
50.
51. @Override
52. protected void onClose(int status) {
53. connections.remove(this);
54. String message = String.format("* %s %s", nickname, "has disconnected.");
55. broadcast(message);
56. }
57.
58. @Override
59. protected void onBinaryMessage(ByteBuffer message) throws IOException {
60. throw new UnsupportedOperationException(
61. "Binary message not supported.");
62. }
63.
64. @Override
65. protected void onTextMessage(CharBuffer message) throws IOException {
66. String filteredMessage = String.format("%s: %s", nickname, HTMLFilter.filter(message.toString()));
67. broadcast(filteredMessage);
68. }
69.
70.
46
www.javaspecialist.co.kr
Lab - ChatWebsocketServlet.java (3/3)
71. private void broadcast(String message) {
72. for (ChatMessageInbound connection : connections) {
73. try {
74. CharBuffer buffer = CharBuffer.wrap(message);
75. connection.getWsOutbound().writeTextMessage(buffer);
76. } catch (IOException ignore) {
77. // Ignore
78. }
79. }
80. }
81.
82. }//end ChatMessageInbound final inner class
83.
84. }//end ChatWebSocketServlet
47
www.javaspecialist.co.kr
Lab - WebSocket/chat.html (1/4)
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <title>Apache Tomcat WebSocket Examples: Chat</title>
5.
6. <style type="text/css">
7. input#chat {
8. width: 410px
9. }
10.
11. #console-container {
12. width: 400px;
13. }
14.
15. #console {
16. border: 1px solid #CCCCCC;
17. border-right-color: #999999;
18. border-bottom-color: #999999;
19. height: 170px;
20. overflow-y: scroll;
21. padding: 5px;
22. width: 100%;
23. }
24.
25. #console p {
26. padding: 0;
27. margin: 0;
28. }
29. </style>
30.
48
www.javaspecialist.co.kr
Lab - WebSocket/chat.html (2/4)
31. <script type="text/javascript">
32. var Chat = {};
33.
34. Chat.socket = null;
35.
36. Chat.connect = (function(host) {
37. if ('WebSocket' in window) {
38. Chat.socket = new WebSocket(host);
39. } else if ('MozWebSocket' in window) {
40. Chat.socket = new MozWebSocket(host);
41. } else {
42. Console.log('Error: WebSocket is not supported by this browser.');
43. return;
44. }
45.
46. Chat.socket.onopen = function () {
47. Console.log('Info: WebSocket connection opened.');
48. document.getElementById('chat').onkeydown = function(event) {
49. if (event.keyCode == 13) {
50. Chat.sendMessage();
51. }
52. };
53. };
54.
55. Chat.socket.onclose = function () {
56. document.getElementById('chat').onkeydown = null;
57. Console.log('Info: WebSocket closed.');
58. };
59.
60.
49
www.javaspecialist.co.kr
Lab - WebSocket/chat.html (3/4)
61. Chat.socket.onmessage = function (message) {
62. Console.log(message.data);
63. };
64. });
65.
66. Chat.initialize = function() {
67. if (window.location.protocol == 'http:') {
68. Chat.connect('ws://' + window.location.host + '/html5/ws/chat');
69. } else {
70. Chat.connect('wss://' + window.location.host + '/html5/ws/chat');
71. }
72. };
73.
74. Chat.sendMessage = (function() {
75. var message = document.getElementById('chat').value;
76. if (message != '') {
77. Chat.socket.send(message);
78. document.getElementById('chat').value = '';
79. }
80. });
81.
82. var Console = {};
83.
84. Console.log = (function(message) {
85. var console = document.getElementById('console');
86. var p = document.createElement('p');
87. p.style.wordWrap = 'break-word';
88. p.innerHTML = message;
89. console.appendChild(p);
90.
50
www.javaspecialist.co.kr
Lab - WebSocket/chat.html (3/4)
91. while (console.childNodes.length > 25) {
92. console.removeChild(console.firstChild);
93. }
94. console.scrollTop = console.scrollHeight;
95. });
96.
97. Chat.initialize();
98.
99. </script>
100.</head>
101.<body>
102.<noscript>
103.<h2 style="color: #ff0000">WebSocket은 자바스크립트에 의존합니다. 자바스크립트가 실행될 수 있도록 설정하세요</h2>
104.</noscript>
105.<div>
106. <p>
107. <input type="text" placeholder="type and press enter to chat" id="chat">
108. </p>
109. <div id="console-container">
110. <div id="console"></div>
111. </div>
112.</div>
113.</body>
114.</html>
51

Contenu connexe

Tendances

[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발
NAVER D2
 
Web Components 101 polymer & brick
Web Components 101 polymer & brickWeb Components 101 polymer & brick
Web Components 101 polymer & brick
yongwoo Jeon
 

Tendances (20)

진짜기초 Node.js
진짜기초 Node.js진짜기초 Node.js
진짜기초 Node.js
 
3-2. selector api
3-2. selector api3-2. selector api
3-2. selector api
 
Express 프레임워크
Express 프레임워크Express 프레임워크
Express 프레임워크
 
ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!ECMAScript 6의 새로운 것들!
ECMAScript 6의 새로운 것들!
 
막하는 스터디 첫 번째 만남 Node.js
막하는 스터디 첫 번째 만남 Node.js막하는 스터디 첫 번째 만남 Node.js
막하는 스터디 첫 번째 만남 Node.js
 
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modificationSecrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
 
Html5 web workers
Html5 web workersHtml5 web workers
Html5 web workers
 
Hacosa jquery 1th
Hacosa jquery 1thHacosa jquery 1th
Hacosa jquery 1th
 
JSP 프로그래밍 #03 서블릿
JSP 프로그래밍 #03 서블릿JSP 프로그래밍 #03 서블릿
JSP 프로그래밍 #03 서블릿
 
Node.js 심화과정
Node.js 심화과정Node.js 심화과정
Node.js 심화과정
 
[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발
 
Html5 performance
Html5 performanceHtml5 performance
Html5 performance
 
JSP 프로그래밍 #04 JSP 의 기본
JSP 프로그래밍 #04 JSP 의 기본JSP 프로그래밍 #04 JSP 의 기본
JSP 프로그래밍 #04 JSP 의 기본
 
JSP 프로그래밍 #05 HTML과 JSP
JSP 프로그래밍 #05 HTML과 JSPJSP 프로그래밍 #05 HTML과 JSP
JSP 프로그래밍 #05 HTML과 JSP
 
Node.js 기본과정
Node.js 기본과정Node.js 기본과정
Node.js 기본과정
 
Angular2 router&http
Angular2 router&httpAngular2 router&http
Angular2 router&http
 
Web Components 101 polymer & brick
Web Components 101 polymer & brickWeb Components 101 polymer & brick
Web Components 101 polymer & brick
 
Anatomy of Realm
Anatomy of RealmAnatomy of Realm
Anatomy of Realm
 
Node.js intro
Node.js introNode.js intro
Node.js intro
 
처음배우는 자바스크립트, 제이쿼리 #1
처음배우는 자바스크립트, 제이쿼리 #1처음배우는 자바스크립트, 제이쿼리 #1
처음배우는 자바스크립트, 제이쿼리 #1
 

Similaire à 5-5. html5 connectivity

구글 기술을 이용한 모바일 클라우드 애플리케이션 개발
 구글 기술을 이용한 모바일 클라우드 애플리케이션 개발 구글 기술을 이용한 모바일 클라우드 애플리케이션 개발
구글 기술을 이용한 모바일 클라우드 애플리케이션 개발
LGU+
 

Similaire à 5-5. html5 connectivity (20)

Web workers
Web workersWeb workers
Web workers
 
Active MQ
Active MQActive MQ
Active MQ
 
Html5
Html5 Html5
Html5
 
Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기
 
자바스크립트 프레임워크 살펴보기
자바스크립트 프레임워크 살펴보기자바스크립트 프레임워크 살펴보기
자바스크립트 프레임워크 살펴보기
 
[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현
[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현
[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현
 
letswift22_우당탕탕 확장 프로그램(이다혜 light).pdf
letswift22_우당탕탕 확장 프로그램(이다혜 light).pdfletswift22_우당탕탕 확장 프로그램(이다혜 light).pdf
letswift22_우당탕탕 확장 프로그램(이다혜 light).pdf
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JS
 
C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발
 
Web server page_ed10
Web server page_ed10Web server page_ed10
Web server page_ed10
 
구글 기술을 이용한 모바일 클라우드 애플리케이션 개발
 구글 기술을 이용한 모바일 클라우드 애플리케이션 개발 구글 기술을 이용한 모바일 클라우드 애플리케이션 개발
구글 기술을 이용한 모바일 클라우드 애플리케이션 개발
 
Nodejs_chapter3
Nodejs_chapter3Nodejs_chapter3
Nodejs_chapter3
 
파이썬 웹 프로그래밍 2탄
파이썬 웹 프로그래밍 2탄 파이썬 웹 프로그래밍 2탄
파이썬 웹 프로그래밍 2탄
 
Portfolio
PortfolioPortfolio
Portfolio
 
20201121 코드 삼분지계
20201121 코드 삼분지계20201121 코드 삼분지계
20201121 코드 삼분지계
 
04 프로세스
04 프로세스04 프로세스
04 프로세스
 
Node.js의 도입과 활용
Node.js의 도입과 활용Node.js의 도입과 활용
Node.js의 도입과 활용
 
Metaworks3 Framework workbook 2015
Metaworks3 Framework workbook 2015Metaworks3 Framework workbook 2015
Metaworks3 Framework workbook 2015
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST API
 
Spring integration을 통해_살펴본_메시징_세계
Spring integration을 통해_살펴본_메시징_세계Spring integration을 통해_살펴본_메시징_세계
Spring integration을 통해_살펴본_메시징_세계
 

Plus de JinKyoungHeo (7)

6. nexcore alopex runtime
6. nexcore alopex runtime6. nexcore alopex runtime
6. nexcore alopex runtime
 
5-2. html5 multimedia
5-2. html5 multimedia5-2. html5 multimedia
5-2. html5 multimedia
 
5-1. html5 graphics
5-1. html5 graphics5-1. html5 graphics
5-1. html5 graphics
 
3-1. css
3-1. css3-1. css
3-1. css
 
2-2. html5
2-2. html52-2. html5
2-2. html5
 
2 1. html4.01
2 1. html4.012 1. html4.01
2 1. html4.01
 
1. 웹 어플리케이션 아키텍처
1. 웹 어플리케이션 아키텍처1. 웹 어플리케이션 아키텍처
1. 웹 어플리케이션 아키텍처
 

5-5. html5 connectivity

  • 3. www.javaspecialist.co.kr www.javaspecialist.co.kr Communication API 윈도우 객체를 통한 페이지 사이의 메시지 전달에 대하여 알아본다. 3
  • 4. www.javaspecialist.co.kr www.javaspecialist.co.kr 커뮤니케이션 API MessageEvent와 postMessage() 메시지 송수신 주체 메시지 송수신 크로스 도큐먼트 메시징 채널 메시징
  • 5. www.javaspecialist.co.kr 1. 커뮤니케이션 API • 배경 – 실행중인 브라우저에서 프레임, 탭, 그리고 윈도우 사이의 통신은 보안상의 이유로 모두 제한되어 있다. – 브라우저는 다른 도메인에서 로드된 컨텐츠를 획득하거나 수정할 경우 보안 예외를 발생 시키고 작동을 차단한다. – 브라우저 제작사와 표준화 단체는 다른 도메인 문서 사이에 메시징 기능 필요함을 서로 합 의하여 다른 도메인 문서 사이에 메시징을 이용할 수 있도록 했다. – 이로 인해 탄생한 것이 Communication API이며 이를 이용하면 iframe, 탭, 윈도우 사이에 보안 통신이 가능하다. • Communication API – 커뮤니케이션 API는 단지 웹 페이지 사이의 통신을 위한 API는 아님. – 메시지를 보내는 표준 방식은 postMessage API로 정의 – postMessage() 메서드를 이용하면 자바스크립트 컨텍스트 사이에 비동기 메시지 통신을 제공 – postMessage() 메서드는 같은 도메인 문서 사이의 통신에도 사용되지만 브라우저의 동일 도메인 정책(Cross-Origin Resource Sharing policy)에 의해 허용되지 않는 문서 사이의 통 신에 더욱 유용하게 사용 • 용도 – Cross-document 통신 – 웹 워커와 같은 자바스크립트 컨텍스트간의 통신 – SSE(Server-Sent Event) 통신 5
  • 6. www.javaspecialist.co.kr 2. MessageEvent와 postMessage() • 메시지 송신 – 메시지를 보내는 표준 방식은 postMessage API로 정의 – 메시지를 보낼 때 postMessage(data, [port], targetOrigin)으로 보냄 • 메시지 수신 처리 – 메시지가 도착하면 message 이벤트 발생 – MessageEvent는 메시지 수신측에서 사용하는 이벤트 객체 – 메시지 수신처리하는 콜백함수 인자로 MessageEvent 객체가 전달됨 – MessageEvent 객체의 속성을 통해 수신되는 데이터를 알 수 있음 속성 설명 data 수신되는 데이터가 저장되어 있다. origin 메시지 송신처의 도메인이다. 신뢰할 수 없는 도메인에서 온 메시지는 무시할 수 있다. source 메시지를 보내는 윈도우 객체이다. ports 메시지 송신 시 지정한 포트의 복사본이다. Channel Messaging에서 사용한다. lastEventId 마지막 이벤트 ID이다. Server-Sent Event에서 사용한다. MessageEvent 속성 6
  • 7. www.javaspecialist.co.kr 3. 메시지 송수신 주체 • 커뮤니케이션 API에서 통신의 종류별로 postMessage() 메서드와 message 이벤트를 사용하는 객 체가 다릅니다. • 각 통신 종류별 사용되는 객체 – Cross document : window 객체 • 보내거나 받는 쪽은 상대방의 윈도우 객체를 알아야 함 • targetWindow.postMessage(data, "*"); • sourceWindow.onmessage = function(){}; – Channel : MessagePort 객체 • channel.port1.postMessage(data, "*"); • channel.port2.onmessage = function(){}; – Web Workers : Worker 객체 • worker.postMessage(data, "*"); • worker.onmessage = function(){}; • 워커에서 메시지를 주고받을 때에는 window 객체를 이용함 – Server-Sent Events : EventSource 객체 • 서버로부터 수신 이벤트 처리 • eventSource.onmessage = function(){}; 7
  • 8. www.javaspecialist.co.kr 4. 메시지 송수신 • 메시지 송신 – 메시지를 보내는 쪽에서는 postMessage(data, [ports,] targetOrigin) 메서드를 사용. – postMessage() 메서드의 각 파라미터는 다음과 같다. • data : 송신할 메시지(자바스크립트 객체)이다. • ports : 채널 메시지 전송 시 공유할 포트배열이며, 생략 가능하다. • targetOrigin : 수신처의 도메인이다. • var targetWindow = window.parent.frames[1] • targetWindow.postMessage(position, "*") • 메시지 수신 – 메시지 수신측에서는 메시지를 수신할 때 발생하는 message 이벤트를 이용. – message 이벤트 핸들러 메서드의 인자로 넘어오는 MessageEvent 객체의 속성을 이용하 여 수신된 메시지를 사용 window.onmessage = function(event){ // 원하는 도메인에서만 오는 경우만 처리하고자 할 경우 if(event.origin =="http://localhost"){ document.getElementById("display").innerHTML = event.data; } }; 8
  • 9. www.javaspecialist.co.kr 5. 크로스 도큐먼트 메시징 • 크로스 도큐먼트 메시징 – 둘 이상의 웹 페이지가 서로 데이터를 주고 받을 수 있 음 – 수신 측 윈도우의 postMessage() 호출 – 자신의 window 에 대해 message 이벤트 핸들러를 지 정하면 됨 • CORS(Cross-Origin Resource Sharing) policy 해결 – CORS 정책(동일 도메인 정책)은 HTML문서 내에서 자 기가 속해있는 도메인이 아닌 다른 도메인의 자원을 호 출하면 브라우저 마다 약간의 차이가 있지만 요청자체 를 브라우저에서 차단한다. – Communication API를 이용하면 내부 프래임들이 서로 다른 도메인에 존재하더라도 내부의 다른 도메인 프래 임들끼리 데이터를 주고받을 수 있다. – 프레임을 포함하는 메인 윈도우 객체를 통해서 프레임 윈도우 객체를 얻을 수 있기 때문에 가능하다. – CORS(동일 도메인 정책)는 Ajax에서 자세하게 다룬다. 9
  • 10. www.javaspecialist.co.kr 예제코드 • Cross document 예제 – Communication/cross-document/sender.html – Communication/cross-document/receiver.html • 새로운 프로젝트 생성 후 테스트 할 수 있음 • 동일도메인정책 회피 예제 – Communication/cross-domain/index.html – Communication/cross-domain/left.html – Communication/cross-domain/right.html (다른 애플리케이션의 파일임을 가정한다.) • 새로운 프로젝트 생성 후 테스트 할 수 있음 10
  • 11. www.javaspecialist.co.kr 6. 채널 메시징 • 채널 메시징은 다대다 메시지 통신을 실현하기 위한 API • MessageChannel(채널)이라는 채널을 통해 메시지를 송수신 – MessageChannel은 메시지 송수신을 중개하는 객체 – new MessageChannel()로 생성 – 채널 메시징에서 채널의 메시지 출입구를 나타내는 포트는 MessagePort에 정의 – MessagePort는 채널의 메시지 출입구를 나타내는 객체 • 포트 공개 – 메시지 수신측의 포트를 송신측에 전달하면 송신측에서는 수신자가 누구인지 알 필요 없이 전달 받은 포트에 메시지만 전송하면 되므로 publish/subscribe 형태의 일대 다 통신이나 범용적인 라 이브러리 구현에 적합 – 수신측에서는 postMessage() 메서드의 두 번째 인자로 포트의 배열을 지정하여 전달하면 됨 속성과 메서드 설명 start() 포트를 이용할 수 있도록 지정한다. close() 포트를 닫는다. postMessage() 메시지 송신에 사용한다. message 메시지 수신 시 발생하는 이벤트이다. 여러 개의 핸들러를 지정하면 다대다 메시지 통신 구현도 가능하다. MessagePort의 이벤트속성과 메서드 11
  • 12. www.javaspecialist.co.kr 예제코드 • 포트 공개 예제 – Communication/one2many/publisher.html – Communication/one2many/subscriber.html 12
  • 13. www.javaspecialist.co.kr www.javaspecialist.co.kr Web Worker 워커를 이용해 백그라운드에서 작업을 실행할 수 있다. 백그라운드 작업 처리 결과는 통신 API를 이용해 UI 스레드에게 전달해 야 한다. 13
  • 15. www.javaspecialist.co.kr 1. Web Workers • 자바스크립트 코드를 백그라운드에서 실행시키기 위한 기술이다. • 오래 걸리는 작업 수행 시 워커를 이용할 수 있다. • 워커로는 DOM 조작이 불가능하다. • 워커가 실행하는 자바스크립트 코드의 저장 인코딩방식은 utf-8이다. 11. Web Workers DOM UI 스레드 worker postMessage() postMessage() new UI 변경 메시지를 통해 데이터를 주고받 음 워커로 DOM 을 조작할 수 없음 15
  • 16. www.javaspecialist.co.kr 2. 전용 워커와 공유 워커 • 워커 – 워커 객체와 백그라운드 프로세스가 일대일로 대응. – interface DedicatedWorkerGlobalScope : WorkerGlobalScope { – void postMessage(in any message, in optional sequence<Transferable> transfer); – attribute Function? onmessage; – }; • 공유 워커 – 여러 객체가 하나의 백그라운드 프로세스를 공유하는 모델. – interface SharedWorkerGlobalScope : WorkerGlobalScope { – readonly attribute DOMString name; – readonly attribute ApplicationCache applicationCache; – attribute Function? onconnect; – }; 11. Web Workers Worker1 (scriptURL = worker.js, "wk") 워커 프로세 스 Worker2 (scriptURL = worker.js, "wk") 워커 프로세 스 Worker1 (scriptURL = worker.js, "wk") Worker2 (scriptURL = worker.js, "wk") 워커 프로세 스 16
  • 17. www.javaspecialist.co.kr Worker interface SharedWorker interface 3. Worker API 속성/메서드/이벤트 설명 postMessage(message, [ports]) 워커에 메시지를 전송한다. postMessage() 메서드는 port의 메서드를 사 용한다. terminate() 워커를 강제로 종료한다. error 에러가 발생된 것을 알리는 이벤트이다. message 워커로부터 메시지가 전달됬을 경우 발생하는 이벤트이다. port 공유 워커와 통신할 수 있는 MessagePort 객체이다. connect SharedWorker 객체 생성 시 발생한다. 속성/메서드/이벤트 설명 postMessage(message) 워커에 메시지를 전송한다. terminate() 워커를 강제로 종료한다. error 에러를 포착하기 위한 이벤트 핸들러이다. message 워커로부터 전달되는 메시지를 포착하기 위한 이벤트 핸들러이다. 17
  • 18. www.javaspecialist.co.kr 4. 전용 워커 사용하기 • 1. 워커 생성(UI JS에서) – var worker = new Worker("worker.js"); • 2. 워커에 메시지 보내기(UI JS에서) – 워커가 작업을 시작하도록 할 수 있음 – worker.postMessage(data); • 3. 워커에서 메시지 수신 처리(워커 JS에서) – window.onmessage = function(me) {} • 4. 워커에서 작업 완료 후 결과를 UI에 전송(워커 JS에서) – window.postMessage(result); • 5. 워커로부터 메시지를 받은 수신측에서 message 이벤트 처리(UI JS에서) – worker.onmessage = function(me) { } var worker = new Worker("worker.js"); UI의 자바스크립트 코드 Worker 가 실행시키는 자바스크립트 코드 5 1 worker.postMessage(data);2 onmessage = function(me) { //백그라운드 작업 postMessage(result); }; 3 4worker.onmessage = function(me) { var result = me.data; } 18
  • 19. www.javaspecialist.co.kr Lab • 백그라운드로 계산한 결과를 반환하는 워커의 자바스크립트 코드를 작성하라. – 워커 자바스크립트 • worker.js • UI로부터 메시지를 받으면 2초간 기다린 다음 데이터를 처리함 • 처리 결과는 UI에게로 보내져야 함 – UI 자바스크립트 • main.js • 계산 버튼이 클릭되면 입력필드의 값을 워커에게 전송, 버튼은 비활성화 되도록 함 • 작업중임을 이미지로 보여줌 • 작업 종료 후 버튼활성화, 이미지 제거 • 제공되는 파일 – wookertest.html – clock.js • 아날로그 시계 – worker.png • 작성해야 하는 파일 – main.js – worker.js 작업시작 전 작업 중 작업 완료 19
  • 20. www.javaspecialist.co.kr Lab (Worker/worker/Lab/end/workertest.html) 1. <!DOCTYPE html> 2. <html> 3. <head> 4. <meta charset="UTF-8"> 5. <title>Insert title here</title> 6. <script src="main.js" defer></script> 7. <script src="clock.js" defer></script> 8. </head> 9. <body> 10. <h1>워커 실행</h1> 11. <div> 12. <input type="text" id="msg"/> 13. <input type="button" value="메세지 전송" id="send"/> 14. <input type="button" value="계산" id="calc"/> 15. <input type="button" value="워커 종료" id="stop"/><br> 16. <div id="workerImg"></div> 17. </div> 18. <div id="log"><p>로그</p></div> 19. <canvas id="clockCanvas" width="300" height="300"></canvas> 20. </body> 21. </html> 20
  • 21. www.javaspecialist.co.kr Lab //main.js 1. (function(){ 2. function log(msg){ 3. var log = document.getElementById("log")|| document.querySelector(".log"); 4. if(log) log.innerHTML += msg + "<br>"; 5. } 6. var worker = new Worker("worker.js"); //워커 생성 7. worker.onmessage = function(me){ 8. log(me.data); 9. calc.removeAttribute("disabled"); //계산 버튼 활성화 10. document.getElementById("workerImg").innerHTML = ""; //작업중 이미지 제거 11. }; 12. var sendBtn = document.getElementById("send"); 13. sendBtn.onclick = function(){ 14. var msg = document.getElementById("msg").value; 15. worker.postMessage(msg); //워커에 메시지 전송 16. }; 17. var calcBtn = document.getElementById("calc"); 18. calcBtn.onclick = function(){ 19. var num = document.getElementById("msg").value; 20. worker.postMessage({"msg":"calc", "num":num}); //워커에 메시지와 데이터 전송 21. calcBtn.setAttribute("disabled", "disabled"); //계산 버튼 비활성화 22. document.getElementById("workerImg").innerHTML = "<img src='worker.png'>"; //작업중 이미지 보여줌 23. }; 24. var stopBtn = document.getElementById("stop"); 25. stopBtn.onclick = function(){ 26. worker.terminate(); //워커 강제 종료 27. calcBtn.removeAttribute("disabled"); //계산 버튼 활성화 28. document.getElementById("workerImg").innerHTML = ""; //작업중 이미지 제거 29. }; 30. })(); 21
  • 22. www.javaspecialist.co.kr Lab //worker.js 1. onmessage = function(me) { 2. //worker는 js 확장자로 생성함 3. //워커발생시 message 이벤트가 발생하고 message가 넘어옴 4. //워커는 독립된프로세스이므로 화면에 표현안됨. 메인 프로그램에 결과를 넘겨주면 처리해야 함 5. //워커는 비즈니스 로직과 UI를 분리시키는 역할을 함 6. if(me.data.msg == "calc"){ 7. //작업을 2초 후에 실행되게 함, 백그라운드 작업임을 보여주기 위함 8. setTimeout(function() { 9. var sum = 0; 10. for(var i=1; i<=me.data.num; i++){ 11. sum += i; 12. } 13. //워커를 생성한 곳으로 작업 결과 전송 14. postMessage("워커수행결과 :" + sum); 15. }, 2000); 16. }else{ 17. //받은 메세지 반송 18. postMessage("Returned Message :" + me.data); 19. } 20. }; 22
  • 23. www.javaspecialist.co.kr 5. 공유 워커 사용하기 1. 공유워커 생성(UI JS에서) var sworker = new SharedWorker("worker.js", wk); 4. 공유워커에 메시지 보내기(UI JS에서) sworker.port.postMessage(data); 7. 공유워커로부터 메시지를 받은 수신측에서 message 이벤트 처리(UI JS에서) sworker.port.onmessage = function(me) {} 2. 공유워커 생성 이벤트 처리 (공유워커 JS에서) window.onconnect = function(me) {} 3. 공유워커 생성시 포트 저장(공유워커 JS에서) var clients = []; clients.push(me.port[0]); 5. 공유워커에서 작업시작(공유워커 JS에서) me.port[0].onmessage = function(me) {} 6. 공유워커의 처리 결과를 UI에 전송(공유워커 JS에서) client[i].postMessage(result); var sworker = new SharedWorker("sworker.js","sw"); btn.onclick = function(){ sworker.port.postMessage(data); }; swworker.port.onmessage = function(me){ var result = me.data; }; UI의 자바스크립트 코드 SharedWorker 가 실행시키는 자바스크립트 코드 5 1 2 onconnect = function(me){ clients.push(me.ports[0]); me.ports[0].onmessage = function(e){ //백그라운드 작업 for(var i=0; i<clients.length; i++){ clients[i].postMessage(result); } }; }; 3 4 6 7
  • 24. www.javaspecialist.co.kr Lab • start.html 문서에서 백그라운드 처리를 시작 한 다음 end.html 문서에서 결과를 표시하는 프 로그램을 작성하자 • SharedWorker(공유 워커)를 이용하면 다른 문서 사이에 워커를 공유할 수 있다. • 주의사항 – 두 창 사이에 워커를 공유하기 위해서는 location.href 속성을 이용하면 안된다. – window.open()으로 윈도우를 띄우고 이전 윈도우는 opener.lose() 로 닫아줘서 두 윈도우 사이에 공유워커 프로세스가 유지되도록 해야 한다.(크롬 브라우저에서 Shift+ESC로 확인 가능) • 제공되는 코드 – start.html – end.html • 작성해야 하는 코드 – start.html, end.html 파일의 script 작성 – dowork.js 24
  • 25. www.javaspecialist.co.kr Lab start.html 1. <!DOCTYPE html> 2. <html> 3. <head> 4. <meta charset="UTF-8"> 5. <title>Shared Worker 테스트</title> 6. <script type="text/javascript"> 7. window.onload = function(){ 8. var sw = new SharedWorker("dowork.js","work"); 9. 10. document.getElementById("send").onclick = function(){ 11. var msg = document.getElementById("msg").value; 12. // TODO 워커에 메세지 전송 13. sw.port.postMessage(msg); 14. 15. //location.href="end.html"; 16. window.open("end.html") 17. }; 18.} 19.</script> 20.</head> 21.<body> 22. <h1>공유 워커 작업시작</h1> 23. <div> 24. <input type="text" id="msg" /> 25. <input type="button" value="작업시작" id="send"/><br> 26. </div> 27.</body> 28.</html> 25
  • 26. www.javaspecialist.co.kr Lab end.html 1. <!DOCTYPE html> 2. <html> 3. <head> 4. <meta charset="UTF-8"> 5. <title>Shared Worker 테스트</title> 6. <script type="text/javascript"> 7. window.onload = function(){ 8. function log(msg){ 9. var log = document.getElementById("log")|| document.querySelector(".log"); 10. if(log) log.innerHTML += msg + "<br>"; 11. } 12. // TODO 공유워커 생성 13. // 인수는 파일명, 이름으로 선언하고 모든 창에서 동일한 파일명, 이름으로 14. // 워커 생성하면 동일한 워커를 사용하는 것으로 함 15. var sw = new SharedWorker("dowork.js","work"); 16. sw.port.onmessage = function(me){ 17. log(me.data); 18. }; 19. 20. opener.close();//이전 창을 닫아준다. 21.} 22.</script> 23.</head> 24.<body> 25. <h1>공유 워커 작업끝</h1> 26. <div id="log"><p>로그</p></div> 27.</body> 28.</html>> 26
  • 27. www.javaspecialist.co.kr Lab 1. //doorker.js 2. 3. var target; 4. 5. // 공유워커 생성 시 호출 6. onconnect = function(me){ 7. target = me.ports[0];//마지막으로 공유워커를 생성한 포트 정보를 저장함 8. 9. target.onmessage = function(e){ 10. //백그라운드로 처리되어야 할 작업 11. setTimeout(function() { 12. var sum = 0; 13. for(var i=1; i<=e.data; i++){ 14. sum += i; 15. } 16. target.postMessage(sum); 17. }, 5000);//5초간 쉼 18. }; 19.}; 27
  • 31. www.javaspecialist.co.kr 1. Polling • AJAX를 이용해 서버에 비동기 요청을 주기적으로 수행하는 방법은 서버의 데이터가 변경되 고 다음 요청이 발생할 때 까지 신규 데이터를 받지 못하는 단점이 있음 • 그러한 단점을 해결하기 위해 서버에서 데이터가 변경되면 응답하는 Long Polling, 응답을 여 러 개 나눠 보내는 Streaming 등이 사용됐었습니다. requeset response Browser Server event requeset response Ajax Polling requeset Browser Server event requeset response Long Polling Streaming requeset response part Browser Server event response part event 서버와 동기화 가 안돼 있 는 기간 31
  • 32. www.javaspecialist.co.kr 2. Server-Sent Event • 클라이언트 API와 푸시(Push) 데이터를 정의한 사양이다. 사실 속을 들여다 보면 폴링이다. • 서버로부터 푸시된 데이터를 수집하여 일반적인 DOM이벤트처럼 처리가 가능하다. • SSE를 사용하면 서버의 갱신된 데이터를 클라이언트에 보여주기 위해 AJAX와 setInterval() 을 사용할 필요가 없다. • 이벤트 소스 객체 생성 – var eventSource = new EventSource("message.jsp");. • 이벤트 소스에 onmessage 핸들러 지정 – eventSource.onmessage = function(event) { } – eventSource.addEventListener("message", function(event) { }, false); • EventSource의 이벤트 이벤트 핸들러 이벤트 핸들러 이벤트 타입 onopen open onmessage message onerror error 32
  • 33. www.javaspecialist.co.kr 3. 푸시 데이터 형식 • SSE는 EventSource가 자동으로 해석할 수 있도록 서버로부터의 푸시되는 데이터의 규칙이 정해져 있다. – mime 타입은 text/event-stream, charset 파라미터는 필요 없다. – 문자 인코딩은 UTF-8로 고정이다. – 줄 바꿈 코드는 ‘rn’ ‘n’ ‘r’ 모두 유효한다. – ‘:’(콜론)으로 시작하는 줄은 주석이다. – 빈 줄이나 파일 끝은 이벤트 구분자가 된다. – 주석이나 빈 줄 이외는 ‘필드 이름: 필드 값’ 이라는 형식으로 작성된다. – 필드 값이 없을 경우 콜론 다음을 생략할 수 있다. – 가독성을 좋게 하기 위해 콜론과 필드 값 사이에 공백 하나를 포함할 수 있다. 33
  • 34. www.javaspecialist.co.kr 4. 응답데이터 형식의 유효한 필드 • 응답 데이터 형식에 있어서 유효한 필드 이름이 또한 정해져 있음 • event – 브라우저가 발생시킬 이벤트. 기본은 message 임. • data – 서버가 보낼 메시지 – 한 번에 여러 개를 보낼 수 있음 – 값이 없으면 수신측에서 message 이벤트가 발생하지 않음 • id – 이벤트 ID이다. – 마지막으로 수신한 이벤트의 ID는 MessageEvent의 lastEventId 속성으로 참조할 수 있으 며 요청 헤더에 'Last-Event-ID'로 포함됨. • retry – 다음 재시도 까지 시간 간격을 밀리 초 단위로 지정. – 생략 시 다음 재시도 간격은 브라우저에 따라 다를 수 있음. 34
  • 35. www.javaspecialist.co.kr Lab 1. <!DOCTYPE html> 2. <html> 3. <head> 4. <meta charset="EUC-KR"> 5. <title>server sent event</title> 6. <script type="text/javascript"> 7. function init() { 8. var source = new EventSource("http://www.javaspecialist.co.kr/ex/SSE/stockserver.jsp"); 9. source.addEventListener( 10. "message", 11. function(event) { 12. var data = event.data.split("n"); 13. var symbol = data[0]; 14. var delta = parseInt(data[1], 10); 15. var cell = document.getElementById(symbol); 16. var currentValue = parseInt(cell.textContent, 10); 17. cell.textContent = currentValue + delta; 18. }, 19. false 20. ); 21. } 22. </script> 23. </head> 24. <body onload="init()"> 25. <h1>Server-Sent Event 예제</h1> 26. <p>서버에서 보내온 데이터를 표시하고 있습니다.</p> 27. <table> 28. <tr><th>Samsung</th><th>LG</th><th>ConSolution</th></tr> 29. <tr><td id="Samsung">55</td><td id="LG">70</td><td id="ConSolution">100</td></tr> 30. </table> 31. </body> 32. </html> 35
  • 36. www.javaspecialist.co.kr Lab • 서버측의 푸쉬 데이터를 위한 코드 http://www.javaspecialist.co.kr/ex/SSE/stockserver.jsp 1. <%@ page contentType="text/event-stream"%> 2. 3. retry: 2000 4. <% 5. String[] symbols = new String[]{"Samsung", "LG", "ConSolution"}; 6. for(String symbol : symbols) { 7. int delta = (int)(Math.random() * 10); 8. 9. if(delta < 7) { 10. if(System.currentTimeMillis() % 2 == 0) 11. delta = -delta; 12. %> 13. data: <%= symbol %> 14. data: <%= delta %> 15. <% 16. } 17. } 18. %> 19. 20. 36
  • 39. www.javaspecialist.co.kr 1. WebSocket • 현재의 HTTP 표준 프로토콜은 서버에서 문서를 요청하고 웹 페이지를 표시하기 전에 문서가 전송되기를 기다려야 하기 때문에 속도가 느리다. • WebSockets를 사용하면 텍스트, 이진 배열 또는 BLOB를 통해 데이터를 즉시 주고받을 수 있다. • WebSocket API는 단순하고 복잡하지 않으며 코드가 거의 필요하지 않는다. 느린 대기 시간 양방향 데이터 교환을 손쉽게 활용하여 온라인 게임, 소셜 네트워크 즉시 알림, 재고 및 날씨 정보 실시간 표시, 기타 적시 데이터를 더 빨리 만들 수 있다. • WebSockets 구현 – 다음 단계를 수행하면 이 새로운 데이터 교환 기술을 간단하게 구현할 수 있다. 1. WebSocket 프로토콜을 구현하는 클라이언트 브라우저를 사용한다. 2. 클라이언트 websocket을 만드는 웹 페이지에서 코드를 작성한다. 3. Websocket을 통해 클라이언트 요청에 응답하는 웹 서버에서 코드를 작성한다. • WebSocket 클라이언트 코드 작성 – 웹 페이지 코드는 다음 작업을 해야 한다. 1. WebSocket을 초기화하고 서버에 연결한다. 2. 테스트를 통해 연결에 성공했는지 확인한다. 3. 데이터를 보내고 받는다 39
  • 40. www.javaspecialist.co.kr 2. WebSocket 구조 Web Socket 서 버 WebSocke t 클라이언트 HTTP 요청 서버가 요청을 받아들인 후 Web Socket 서 버 WebSocke t 클라이언트 쌍방향 통신 40
  • 41. www.javaspecialist.co.kr 3. WebSocket 클라이언트 코드 • 웹소켓 서버가 구축되어 있어야 함 • 클라이언트에서 웹소켓 서버에 접속하기 위해 다음과 같이 WebSocket 객체 생성 – var wsSocket = new WebSocket("ws://Web Socket Server URL"); – 웹 소켓 프로토콜은 다음과 같은 새로은 URL 체계를 사용한다. • ws:// • wss:// • 서버로 메시지를 보낼 때 – wsSocket.send("전송할 Message"); • 서버로부터 메시지를 받을 때 message 이벤트 발생함 • WebSocket 인터페이스 이벤트 핸들러 Event Handler 설명 onmessage Server 로 Message를 전달 받을 때 onopen Web Socket Server 가 열릴 때 onclose Web Socket Server 가 닫힐 때 onerror 에러가 발생할 때 41
  • 42. www.javaspecialist.co.kr 4. WebSocket 개체, 메서드, 속성 • WebSocket은 WebSocket 프로그래밍에 사용할 수 있는 개체, 메서드 및 속성 집합을 제공한 다. 이름 유형 설명 WebSocket 개체 원격 호스트에 대한 양방향 채널을 제공한다. close 메서드 WebSocket을 닫는다. send 메서드 WebSocket을 사용하여 데이터를 서버로 보낸다. binaryType 속성 onmessage에 수신되는 이진 데이터 형식이다. bufferedAmount 속성 send를 사용하여 대기 중인 데이터 바이트 수. extensions 속성 서버가 선택한 확장을 보고한다. onclose 속성 소켓을 닫을 때 호출되는 이벤트 처리기. onerror 속성 오류가 있을 때 호출되는 이벤트 처리기. onmessage 속성 메시지가 수신되었음을 알리는 이벤트 처리기. onopen 속성 WebSocket이 연결된 경우 호출되는 이벤트 처리기. protocol 속성 서버가 선택한 프로토콜을 보고한다. readyState 속성 WebSocket 연결 상태를 보고한다. url 속성 소켓의 현재 URL을 보고한다. 42
  • 43. www.javaspecialist.co.kr Lab • 톰캣 7에 예제로 포함되어 있음 • Build Path에 catalina-7.0.29.2.jar 파일과 tomcat-juli.jar 파일 포함 – WEB-INF/lib 폴더에 복사하면 안됨 – tomcat-juli.jar • http://tomcat.apache.org -> Download -> Binaries -> Extras -> JULI log4j jar – catalina-7.0.39.3.jar • org.apache.catalina.websocket. 패키지를 포함. • http://grepcode.com/project/repo1.maven.org/maven2/org.apache.geronimo.ext.tomcat/catalina/ 43
  • 44. www.javaspecialist.co.kr Lab - HTMLFilter 1. package util; 2. public final class HTMLFilter { 3. public static String filter(String message) { 4. if (message == null) 5. return (null); 6. char content[] = new char[message.length()]; 7. message.getChars(0, message.length(), content, 0); 8. StringBuilder result = new StringBuilder(content.length + 50); 9. for (int i = 0; i < content.length; i++) { 10. switch (content[i]) { 11. case '<': 12. result.append("&lt;"); 13. break; 14. case '>': 15. result.append("&gt;"); 16. break; 17. case '&': 18. result.append("&amp;"); 19. break; 20. case '"': 21. result.append("&quot;"); 22. break; 23. default: 24. result.append(content[i]); 25. } 26. } 27. return (result.toString()); 28. 29. } 30. } 웹소켓 서블릿에서 응답할 때 < > & " 문자 변환에 사용 44
  • 45. www.javaspecialist.co.kr Lab - ChatWebsocketServlet.java (1/3) 1. package websocket.chat; 2. 3. import java.io.IOException; 4. import java.nio.ByteBuffer; 5. import java.nio.CharBuffer; 6. import java.util.Set; 7. import java.util.concurrent.CopyOnWriteArraySet; 8. import java.util.concurrent.atomic.AtomicInteger; 9. 10. import javax.servlet.http.HttpServletRequest; 11. 12. import org.apache.catalina.websocket.MessageInbound; 13. import org.apache.catalina.websocket.StreamInbound; 14. import org.apache.catalina.websocket.WebSocketServlet; 15. import org.apache.catalina.websocket.WsOutbound; 16. 17. import util.HTMLFilter; 18. 19. @WebServlet("/ws/chat") 20. public class ChatWebSocketServlet extends WebSocketServlet { 21. 22. private static final long serialVersionUID = 1L; 23. 24. private static final String GUEST_PREFIX = "Guest"; 25. 26. private final AtomicInteger connectionIds = new AtomicInteger(0); 27. 28. private final Set<ChatMessageInbound> connections = 29. new CopyOnWriteArraySet<ChatMessageInbound>(); 30. 31. @Override 32. protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { 33. return new ChatMessageInbound(connectionIds.incrementAndGet()); 34. } 35. 45
  • 46. www.javaspecialist.co.kr Lab - ChatWebsocketServlet.java (2/3) 36. private final class ChatMessageInbound extends MessageInbound { 37. 38. private final String nickname; 39. 40. private ChatMessageInbound(int id) { 41. this.nickname = GUEST_PREFIX + id; 42. } 43. 44. @Override 45. protected void onOpen(WsOutbound outbound) { 46. connections.add(this); 47. String message = String.format("* %s %s", nickname, "has joined."); 48. broadcast(message); 49. } 50. 51. @Override 52. protected void onClose(int status) { 53. connections.remove(this); 54. String message = String.format("* %s %s", nickname, "has disconnected."); 55. broadcast(message); 56. } 57. 58. @Override 59. protected void onBinaryMessage(ByteBuffer message) throws IOException { 60. throw new UnsupportedOperationException( 61. "Binary message not supported."); 62. } 63. 64. @Override 65. protected void onTextMessage(CharBuffer message) throws IOException { 66. String filteredMessage = String.format("%s: %s", nickname, HTMLFilter.filter(message.toString())); 67. broadcast(filteredMessage); 68. } 69. 70. 46
  • 47. www.javaspecialist.co.kr Lab - ChatWebsocketServlet.java (3/3) 71. private void broadcast(String message) { 72. for (ChatMessageInbound connection : connections) { 73. try { 74. CharBuffer buffer = CharBuffer.wrap(message); 75. connection.getWsOutbound().writeTextMessage(buffer); 76. } catch (IOException ignore) { 77. // Ignore 78. } 79. } 80. } 81. 82. }//end ChatMessageInbound final inner class 83. 84. }//end ChatWebSocketServlet 47
  • 48. www.javaspecialist.co.kr Lab - WebSocket/chat.html (1/4) 1. <!DOCTYPE html> 2. <html> 3. <head> 4. <title>Apache Tomcat WebSocket Examples: Chat</title> 5. 6. <style type="text/css"> 7. input#chat { 8. width: 410px 9. } 10. 11. #console-container { 12. width: 400px; 13. } 14. 15. #console { 16. border: 1px solid #CCCCCC; 17. border-right-color: #999999; 18. border-bottom-color: #999999; 19. height: 170px; 20. overflow-y: scroll; 21. padding: 5px; 22. width: 100%; 23. } 24. 25. #console p { 26. padding: 0; 27. margin: 0; 28. } 29. </style> 30. 48
  • 49. www.javaspecialist.co.kr Lab - WebSocket/chat.html (2/4) 31. <script type="text/javascript"> 32. var Chat = {}; 33. 34. Chat.socket = null; 35. 36. Chat.connect = (function(host) { 37. if ('WebSocket' in window) { 38. Chat.socket = new WebSocket(host); 39. } else if ('MozWebSocket' in window) { 40. Chat.socket = new MozWebSocket(host); 41. } else { 42. Console.log('Error: WebSocket is not supported by this browser.'); 43. return; 44. } 45. 46. Chat.socket.onopen = function () { 47. Console.log('Info: WebSocket connection opened.'); 48. document.getElementById('chat').onkeydown = function(event) { 49. if (event.keyCode == 13) { 50. Chat.sendMessage(); 51. } 52. }; 53. }; 54. 55. Chat.socket.onclose = function () { 56. document.getElementById('chat').onkeydown = null; 57. Console.log('Info: WebSocket closed.'); 58. }; 59. 60. 49
  • 50. www.javaspecialist.co.kr Lab - WebSocket/chat.html (3/4) 61. Chat.socket.onmessage = function (message) { 62. Console.log(message.data); 63. }; 64. }); 65. 66. Chat.initialize = function() { 67. if (window.location.protocol == 'http:') { 68. Chat.connect('ws://' + window.location.host + '/html5/ws/chat'); 69. } else { 70. Chat.connect('wss://' + window.location.host + '/html5/ws/chat'); 71. } 72. }; 73. 74. Chat.sendMessage = (function() { 75. var message = document.getElementById('chat').value; 76. if (message != '') { 77. Chat.socket.send(message); 78. document.getElementById('chat').value = ''; 79. } 80. }); 81. 82. var Console = {}; 83. 84. Console.log = (function(message) { 85. var console = document.getElementById('console'); 86. var p = document.createElement('p'); 87. p.style.wordWrap = 'break-word'; 88. p.innerHTML = message; 89. console.appendChild(p); 90. 50
  • 51. www.javaspecialist.co.kr Lab - WebSocket/chat.html (3/4) 91. while (console.childNodes.length > 25) { 92. console.removeChild(console.firstChild); 93. } 94. console.scrollTop = console.scrollHeight; 95. }); 96. 97. Chat.initialize(); 98. 99. </script> 100.</head> 101.<body> 102.<noscript> 103.<h2 style="color: #ff0000">WebSocket은 자바스크립트에 의존합니다. 자바스크립트가 실행될 수 있도록 설정하세요</h2> 104.</noscript> 105.<div> 106. <p> 107. <input type="text" placeholder="type and press enter to chat" id="chat"> 108. </p> 109. <div id="console-container"> 110. <div id="console"></div> 111. </div> 112.</div> 113.</body> 114.</html> 51