[Java] Servlet에서 사용하는 웹 소켓 (WebSocket)


Development note/Java  2020. 2. 20. 21:42

안녕하세요. 명월입니다.


이 글은 Java의 Servlet에서 사용하는 웹 소켓 (WebSocket) 에 대한 글입니다.


보통의 웹 환경은 브라우저(클라이언트)에서 웹 서버에 Html 문서를 요청하면, 웹 서버는 Html를 작성하고 브라우저(클라이언트)에 응답 한 후 연결을 끊는 비동기 소켓 통신입니다.

Websocket는 브라우저(클라이언트)가 접속 요청을 하고 Web 서버가 응답 한 후 연결을 끊는 것이 아니고, Connection을 그대로 유지하고 브라우저(클라이언트)의 요청이 없어도 데이터를 전송할 수있는 프로토콜입니다.


예를 들어, 채팅을 생각하면 사용자가 내용을 쓰고 서버에 전송합니다. 즉, 브라우저(클라이언트)에서 서버로 데이터를 요청한 것입니다. 그리고 서버에서는 다른 응답 결과가 없으면 그대로 응답 메시지를 보내지 않습니다.

그러나 다른 사용자가 채팅 내용을 쓰고 서버로 전송하면 내 브라우저(클라이언트)로 메시지를 보내야 합니다.


일반 웹 프로토콜의 경우는 서버와 브라우저(클라이언트)와 연결이 끊긴 상태이기 때문에 브라우저에서 요청이 오지 않는 이상 다른 사용자의 메시지를 보낼 수 없습니다.

WebSocket의 경우는 서버와 브라우저(클라이언트)가 끊기지 않은 상태이기 때문에 브라우저(클라이언트)의 요청이 없어도 서버에서 브라우저로 메시지를 보낼 수가 있습니다.


물론 웹 프로토콜의 경우, 몇 초당 갱신 주기를 만들어서 일정한 시간 단위로 요청을 하게 하여 동기화를 할 수 있지만, 이 경우에는 트래픽이 많아서져서 웹 서버에 부담이 많이 되겠네요.(socket.io)


WebSocket의 경우는 HTML5부터 표준이 되었습니다. 이미 HTML5가 표준이 된지 한참이 되었으니, WebSocket을 지원하지 않는 브라우저는 이제 없겠네요.

프로토콜의 요청은 「ws://~」로 시작합니다. ssl 방식이라면 「wss://~」로 시작합니다.


이전에 제가 Java 서블릿에 대해 설명한 적이 있습니다.

link - [Java강좌 - 40] Java에서 웹 서비스 프로젝트(Jsp servlet)를 작성하는 방법

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerEndpoint;
// WebSocket의 호스트 주소 설정
@ServerEndpoint("/websocket")
public class Websocket {
  // WebSocket으로 브라우저가 접속하면 요청되는 함수	
  @OnOpen
  public void handleOpen() {
    // 콘솔에 접속 로그를 출력한다.
    System.out.println("client is now connected...");
  }
  // WebSocket으로 메시지가 오면 요청되는 함수
  @OnMessage
  public String handleMessage(String message) {
    // 메시지 내용을 콘솔에 출력한다.
    System.out.println("receive from client : " + message);
    // 에코 메시지를 작성한다.
    String replymessage = "echo " + message;
    // 에코 메시지를 콘솔에 출력한다.
    System.out.println("send to client : "+replymessage);
    // 에코 메시지를 브라우저에 보낸다.
    return replymessage;
  }
  // WebSocket과 브라우저가 접속이 끊기면 요청되는 함수
  @OnClose
  public void handleClose() {
    // 콘솔에 접속 끊김 로그를 출력한다.
    System.out.println("client is now disconnected...");
  }
  // WebSocket과 브라우저 간에 통신 에러가 발생하면 요청되는 함수.
  @OnError
  public void handleError(Throwable t) {
    // 콘솔에 에러를 표시한다.
    t.printStackTrace();
  }
}

WebSocket을 구현하는 것은 크게 어렵지 않습니다. 별도로 소켓 서버를 구축하거나 프로토콜을 선언하거나 해더를 관리하는 것도 없이 심플합니다.

@OnOpen,@OnMessage,@OnClose,@OnError의 네가지 어노테이션으로 브라우저와 통신 이벤트를 관리하는 것입니다.


그럼 웹 소켓을 접속하기 위해 jsp파일을 작성하겠습니다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head><title>Web Socket Example</title></head>
  <body>
    <form>
      <!-- 송신 메시지를 작성하는 텍스트 박스 -->
      <input id="textMessage" type="text">
      <!-- 메시지 송신을 하는 버튼 -->
      <input onclick="sendMessage()" value="Send" type="button">
      <!-- WebSocket 접속 종료하는 버튼 -->
      <input onclick="disconnect()" value="Disconnect" type="button">
    </form>
    <br />
    <!-- 콘솔 메시지의 역할을 하는 로그 텍스트 에리어.(수신 메시지도 표시한다.) -->
    <textarea id="messageTextArea" rows="10" cols="50"></textarea>
    <script type="text/javascript">
      // 「WebSocketEx」는 프로젝트 명
      // 「websocket」는 호스트 명
      // WebSocket 오브젝트 생성 (자동으로 접속 시작한다. - onopen 함수 호출)
      var webSocket = new WebSocket("ws://localhost:8080/WebSocketEx/websocket");
      // 콘솔 텍스트 에리어 오브젝트
      var messageTextArea = document.getElementById("messageTextArea");
      // WebSocket 서버와 접속이 되면 호출되는 함수
      webSocket.onopen = function(message) {
        // 콘솔 텍스트에 메시지를 출력한다.
        messageTextArea.value += "Server connect...\n";
      };
      // WebSocket 서버와 접속이 끊기면 호출되는 함수
      webSocket.onclose = function(message) {
        // 콘솔 텍스트에 메시지를 출력한다.
        messageTextArea.value += "Server Disconnect...\n";
      };
      // WebSocket 서버와 통신 중에 에러가 발생하면 요청되는 함수
      webSocket.onerror = function(message) {
        // 콘솔 텍스트에 메시지를 출력한다.
        messageTextArea.value += "error...\n";
      };
      // WebSocket 서버로 부터 메시지가 오면 호출되는 함수
      webSocket.onmessage = function(message) {
        // 콘솔 텍스트에 메시지를 출력한다.
        messageTextArea.value += "Recieve From Server => "+message.data+"\n";
      };
     // Send 버튼을 누르면 호출되는 함수
    function sendMessage() {
      // 송신 메시지를 작성하는 텍스트 박스 오브젝트를 취득한다.
      var message = document.getElementById("textMessage");
      // 콘솔 텍스트에 메시지를 출력한다.
      messageTextArea.value += "Send to Server => "+message.value+"\n";
      // WebSocket 서버에 메시지를 송신한다.
      webSocket.send(message.value);
      // 송신 메시지를 작성하는 텍스트 박스를 초기화한다.
      message.value = "";
    }
    // Disconnect 버튼을 누르면 호출되는 함수
    function disconnect() {
      // WebSocket 접속 해제
      webSocket.close();
    }
  </script>
</body>
</html>

WebSocket는 Javascript의 내부 함수입니다. 파라미터는 WebSocket의 접속 주소를 입력합니다. 프로토콜은 "ws://~"로 시작합니다.

클라이언트 리스너 함수는 "onopen", "onmessgae", "onclose", "onerror"가 있습니다.


onopen는 WebSocket 서버와 연결할 때 호출됩니다. onmessage는 서버에서 메시지를 수신하는 때 호출됩니다.

onclose는 WebSocket 서버와 연결이 끊어 질 때 호출됩니다. onerror오류가 발생할 때 호출됩니다.


그럼 위 소스를 톰켓에 기동하고 브라우저로 접속해서 확인하겠습니다.

연결이 되면 "Server connect ..."라는 메시지가 표시됩니다.

제가 송신 메시지를 작성하는 텍스트 박스에 "hello world"를 쓰고 서버로 메시지를 보냈습니다. 결과는 서버에서 에코 메시지에 답장이 왔습니다.

마지막으로 WebSocket 접속 해제 버튼을 눌렀습니다.

서버 쪽의 로그를 보면 클라이언트가 접속 한 로그가 있습니다. 클라이언트에서 "hello world"메시지를 받고 에코 메시지를 보냈습니다.

WebSocket의 접속 해제 로그까지 있습니다.


여기까지 Java의 Servlet에서 사용하는 웹 소켓 (WebSocket) 에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.