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
15. www.javaspecialist.co.kr
1. Web Workers
• 자바스크립트 코드를 백그라운드에서 실행시키기 위한 기술이다.
• 오래 걸리는 작업 수행 시 워커를 이용할 수 있다.
• 워커로는 DOM 조작이 불가능하다.
• 워커가 실행하는 자바스크립트 코드의 저장 인코딩방식은 utf-8이다.
11. Web Workers
DOM UI 스레드
worker
postMessage()
postMessage()
new
UI 변경
메시지를 통해
데이터를 주고받
음
워커로 DOM
을 조작할 수
없음
15
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
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
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
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
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("<");
13. break;
14. case '>':
15. result.append(">");
16. break;
17. case '&':
18. result.append("&");
19. break;
20. case '"':
21. result.append(""");
22. break;
23. default:
24. result.append(content[i]);
25. }
26. }
27. return (result.toString());
28.
29. }
30. }
웹소켓 서블릿에서 응답할 때 < > & " 문자 변환에 사용
44