일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- spring data jpa
- spring integration
- python
- Java
- 자바
- chatGPT's answer
- flet
- GPT-4's answer
- JVM
- 웹 크롤링
- write by chatGPT
- jpa
- 코틀린
- write by GPT-4
- 리눅스
- 자바암호
- 파이썬
- android
- 역학
- 유닉스
- 소프트웨어공학
- 시스템
- 데이터베이스
- oracle
- 고전역학
- kotlin
- Database
- NIO
- 인프라
- 자바네트워크
- Today
- Total
기억을 지배하는 기록
First WebSocket 본문
HTML5의 주 기능 중에 “Websocket”이 있다는 건 웬만한 개발자라면 다 아는 사실이다. 하지만 사실상 적용된 사례는 드문 것 같다. 이유야 여러가지가 있겠지만 환경 부족과 개발자 인식의 부족인 문제인 것 같다. 또한 최근에는 모든 것이 다 되는(?) 모바일에 그 필요성이 없다고 생각 할 수도 있겠다.
“Websocket”의 특징을 말한다면 “Web브라우저를 기반으로 서버에서 클라이언트로 돈 안들이고 Message을 보낼수 있는 유일한 기술”라고 할 수 있을 것이다.
WebSocket개발에는 뭐가 필요할까?
WebSocket을 http”//로 시작하지 않고 ws://로 시작하는 URL형태를 가진다. 이는 HTTP 프로토콜을 기반으로 확장된 별도의 프로토콜을 가지기 때문이다.
“JSR 356(JavaTM API for WebSocket)”으로 명명된 WebSocket을 지원하는 WAS는 따로있으며
Tomcat의 경우 7이상, Jetty는 9이상의 버전부터 지원하고 있다.(다른 건 잘 모르겠습니다...)
Tomcat 7의 example로 포함된 WebSocket 예를 살펴보면
Server Side: EchoMessage
package websocket.echo; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.Date; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import org.apache.catalina.websocket.WsOutbound; @WebServlet("/echo") public class EchoMessage extends WebSocketServlet implements Servlet { private static final long serialVersionUID = 1L; private volatile int byteBufSize; private volatile int charBufSize; @Override public void init() throws ServletException { super.init(); byteBufSize = getInitParameterIntValue("byteBufferMaxSize", 2097152); charBufSize = getInitParameterIntValue("charBufferMaxSize", 2097152); } public int getInitParameterIntValue(String name, int defaultValue) { String val = this.getInitParameter(name); int result; if (null != val) { try { result = Integer.parseInt(val); } catch (Exception x) { result = defaultValue; } } else { result = defaultValue; } return result; } @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { return new EchoMessageInbound(byteBufSize, charBufSize); } private static final class EchoMessageInbound extends MessageInbound { public EchoMessageInbound(int byteBufferMaxSize, int charBufferMaxSize) { super(); setByteBufferMaxSize(byteBufferMaxSize); setCharBufferMaxSize(charBufferMaxSize); } @Override protected void onBinaryMessage(ByteBuffer message) throws IOException { getWsOutbound().writeBinaryMessage(message); } @Override protected void onTextMessage(CharBuffer message) throws IOException { System.out.println("From Client:" + message.toString()); getWsOutbound().writeTextMessage(message); } @Override protected void onClose(int status) { super.onClose(status); System.out.println("종료:" + status); } @Override protected void onOpen(WsOutbound outbound) { super.onOpen(outbound); System.out.println("연결:" + outbound); CharBuffer buffer = CharBuffer.allocate(100); try { String string = "Current time:"+ new Date()+", WebSocket 연결 하였습니다."; for (int i = 0; i < string.length(); i++) { buffer.put(string.charAt(i)); } buffer.flip(); outbound.writeTextMessage(buffer); buffer.clear(); } catch (IOException e) { e.printStackTrace(); } } } } |
onOpen, onClose 콜백 메서드을 오버라이드해서 적절하게 사용 가능합니다.(여기서는 로그만..)
Inbound 타입은 여러가지가 있어 적절하게 골라 사용하면 됩니다.
Client Side: echo.html
<!DOCTYPE html> <html> <head> <title>Apache Tomcat WebSocket Examples: Echo</title> <style type="text/css"> #connect-container { float: left; width: 400px } #connect-container div { padding: 5px; } #console-container { float: left; margin-left: 15px; width: 400px; } #console { border: 1px solid #CCCCCC; border-right-color: #999999; border-bottom-color: #999999; height: 170px; overflow-y: scroll; padding: 5px; width: 100%; } #console p { padding: 0; margin: 0; } </style> <script type="text/javascript"> var ws = null; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('echo').disabled = !connected; } function connect() { var target = document.getElementById('target').value; if (target == '') { alert('Please select server side connection implementation.'); return; } if ('WebSocket' in window) { ws = new WebSocket(target); } else if ('MozWebSocket' in window) { ws = new MozWebSocket(target); } else { alert('WebSocket is not supported by this browser.'); return; } ws.onopen = function () { setConnected(true); log('Info: WebSocket connection opened.'); }; ws.onmessage = function (event) { log('Received: ' + event.data); }; ws.onclose = function () { setConnected(false); log('Info: WebSocket connection closed.'); }; } function disconnect() { if (ws != null) { ws.close(); ws = null; } setConnected(false); } function echo() { if (ws != null) { var message = document.getElementById('message').value; log('Sent: ' + message); ws.send(message); } else { alert('WebSocket connection not established, please connect.'); } } function updateTarget(target) { if (window.location.protocol == 'http:') { document.getElementById('target').value = 'ws://' + window.location.host + target; } else { document.getElementById('target').value = 'wss://' + window.location.host + target; } } function log(message) { var console = document.getElementById('console'); var p = document.createElement('p'); p.style.wordWrap = 'break-word'; p.appendChild(document.createTextNode(message)); console.appendChild(p); while (console.childNodes.length > 25) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; } </script> </head> <body> <noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!</h2></noscript> <div> <div id="connect-container"> <div> <span>Connect using:</span> <!-- echo example using streams on the server side --> <input id="radio1" type="radio" name="group1" value="/FirstWebSocket/websocket/echoStream" onclick="updateTarget(this.value);"> <label for="radio1">streams</label> <!-- echo example using messages on the server side --> <input id="radio2" type="radio" name="group1" value="/FirstWebSocket/websocket/echoMessage" onclick="updateTarget(this.value);"> <label for="radio2">messages</label> </div> <div> <input id="target" type="text" size="40" style="width: 350px"/> </div> <div> <button id="connect" onclick="connect();">Connect</button> <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button> </div> <div> <textarea id="message" style="width: 350px">Here is a message!</textarea> </div> <div> <button id="echo" onclick="echo();" disabled="disabled">Echo message</button> </div> </div> <div id="console-container"> <div id="console"></div> </div> </div> </body> </html> |
기타 배포에 필요한 Code
EchoStream.java
package websocket.echo; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import org.apache.catalina.websocket.WsOutbound; public class EchoStream extends WebSocketServlet { private static final long serialVersionUID = 1L; @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { return new EchoStreamInbound(); } private static final class EchoStreamInbound extends StreamInbound { @Override protected void onBinaryData(InputStream is) throws IOException { // Simply echo the data to back to the client. WsOutbound outbound = getWsOutbound(); int i = is.read(); while (i != -1) { outbound.writeBinaryData(i); i = is.read(); } outbound.flush(); } @Override protected void onTextData(Reader r) throws IOException { // Simply echo the data to back to the client. WsOutbound outbound = getWsOutbound(); int c = r.read(); while (c != -1) { outbound.writeTextData((char) c); c = r.read(); } outbound.flush(); } } } |
Web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>FirstWebSocket</display-name> <servlet> <servlet-name>wsEchoMessage</servlet-name> <servlet-class>websocket.echo.EchoMessage</servlet-class> </servlet> <servlet-mapping> <servlet-name>wsEchoMessage</servlet-name> <url-pattern>/websocket/echoMessage</url-pattern> </servlet-mapping> <servlet> <servlet-name>wsEchoStream</servlet-name> <servlet-class>websocket.echo.EchoStream</servlet-class> </servlet> <servlet-mapping> <servlet-name>wsEchoStream</servlet-name> <url-pattern>/websocket/echoStream</url-pattern> </servlet-mapping> </web-app> |
결론
만일 여러분이 Dashboard 형태의 Web Application을 만든다면 “WebSocket”은 강력한 도구가 될 것입니다.
그 외 브라우저 환경에서 알림을 받는다든지, 웹 화면 Refresh 없이 데이터 변경을 위한 모든 상황에도 활용이 가능할 것입니다.
'오래된글 > Articles' 카테고리의 다른 글
How to embed Tomcat and Java web apps in an executable JAR (0) | 2018.05.29 |
---|---|
시스템 부팅시 도커 컨테이너 자동 실행 (0) | 2018.05.03 |
Android Service에서 AlertDialog 띄우기 (0) | 2018.05.03 |
Android 촬영 사진의 회전 각도 구하기 (0) | 2018.05.03 |
모바일 보안 취약점 및 대책 (0) | 2018.05.03 |