웹 소켓 개발
본 장에서는 ProObject에서 웹 소켓을 등록하고 메시지 송수신, 커스터마이징하는 방법에 대하여 설명한다.
1. 개요
HTTP는 요청-응답 모델(R-R Model : Request-Response Model)만을 고려하고 있으므로, 일반적으로 사용하는 폴링(Polling) 모델에는 적합한 모델이다. 다만 모든 서비스가 항상 폴링 모델에 적합하지 않다. 서버가 클라이언트에 문의를 하거나 특정한 이벤트가 발생한 경우는 여러 클라이언트에 이 이벤트를 알려주는 작업이 별도로 필요할 수도 있다.
대표적인 경우가 흔히 볼 수 있는 모니터링 시스템으로 주기적으로 데이터를 서버로부터 받아오거나 특정 이벤트가 발생했을 때 알람을 받아야 하는 경우이다. 이러한 작업들을 폴링 모델만으로 해결하는 것은 매우 비효율적이기 때문에 웹에서는 웹 소켓의 개념이 나타나게 되었다.
웹 소켓은 일반적인 TCP 소켓과 비슷한 기능으로 기존의 HTTP에서 이루어진 단방향 통신의 한계를 극복할 수 있다. 때문에 서버와 주기적으로 통신이 필요한 대부분의 웹 애플리케이션에서는 여러 분야에 웹 소켓이 이용되고 있다.
ProObject에서도 이러한 웹 소켓을 설계 사상에 맞추어 더욱 편리하게 이용할 수 있도록 기능을 제공하고 있다.
다음의 주소로 웹 소켓에 접근할 수 있다.
ws://ServerIP:serverPort/{applicationName}/[WebsocketID]
|
위의 양식을 제대로 지키지 않았을 경우에는 ProObject의 웹 소켓 연결 자체가 거부되므로 주의하도록 한다. |
2. 웹 소켓 등록
ProObject에서 웹 소켓을 사용하기 위해서는 애플리케이션 설정에 웹 소켓을 등록해야 한다.
다음의 애플리케이션 메타 파일에 웹 소켓을 정보를 설정한다.
${APP_HOME}/config/application.xml
다음은 웹 소켓을 등록한 예로 <web-socket> 항목 정보를 설정한다. 상황에 따라서 다수의 웹 소켓을 운용할 수도 있다.
<application>
<web-socket>
<path>test</path>
<class-name>com.tmax.proobject.example.websocket.ExampleWebSocket</class-name>
<service>test.example.WebSocketTest</service>
</web-socket>
</application>
다음은 각 설정항목에 대한 설명이다.
| 태그 | 설명 |
|---|---|
<path> |
웹 소켓의 아이디를 나타내며, 웹 소켓의 컨텍스트 패스를 의미한다. 예를 들어 'testApp’이라는 애플리케이션에서 test라는 이름의 path를 지니는 웹 소켓을 설정한 경우 다음의 주소로 접속이 가능하다. ws://ServerIP:ServerPort/testApp/test |
<class-name> |
ProObjectWebSocket 클래스의 구현체를 지정한다. 구현체를 직접 지정하는 경우에는 패키지 이름을 포함한 모든 클래스 이름을 적어주어야 하며, 클래스는 반드시 이벤트 계층에 배포되어야 한다. 지정하지 않는 경우 ProObject의 기본 웹 소켓 구현체가 지정되며, 일반적인 경우에는 기본 웹 소켓 구현체를 사용할 것을 권장한다. 설정한 클래스는 기본적인 WebSocket과 제공되는 API가 비슷하므로 기존의 웹 소켓을 사용해본 적이 있다면 쉽게 작성할 수 있으나, onMessage 항목은 오버라이딩이 불가능함만 유의하도록 한다. 자세한 내용은 웹 소켓 커스터마이징을 참고한다. (기본값: com.tmax.proobject.engine.websocket.DefaultProObjectWebSocket) |
<service> |
웹 소켓으로 메시지가 전달된 경우에 호출될 메시지 처리자 서비스의 이름을 지정한다. 기본적으로 ProObject는 모든 것을 서비스로 인식한다. 따라서 웹 소켓으로 들어오는 모든 메시지를 하나의 서비스로 인식하고 수신되는 메시지 또한 '서비스 요청’으로 처리한다. ProObject에서는 웹 소켓으로 들어오는 메시지를 처리하기 위해 메시지가 수신되면 호출되는 '메시지 처리자 서비스’를 통해 이러한 요청을 처리할 수 있다. 이때 호출된 서비스의 출력값은 전달되지 않으며 입력값은 다음의 값으로 고정된다. com.tmax.proobject.engine.websocket.WebSocketMessageDataObject |
3. 웹 소켓 메시지 수신
웹 소켓 설정에서 서비스를 설정하면 서비스가 자동으로 호출된다. 호출된 서비스는 일반적인 서비스와 동일하므로 전달받은 메시지를 이용하여 DB 처리를 하거나 다른 서비스와 연동하는 등의 DB 작업을 추가적으로 수행하거나 다른 웹 소켓들에게 브로드캐스팅 작업을 진행하는 것도 가능하다.
4. 웹 소켓 메시지 송신
서비스나 이벤트에서 웹 소켓으로 메시지를 송신하려면 WebSocketManager를 사용한다. 메시지를 송신할 때에는 브로드캐스팅 방식과 개별 전송 방식 두 가지 중에서 하나를 선택하여 전송이 가능하다.
-
브로드캐스팅
브로드캐스팅하는 경우 두 개의 매개변수를 넘겨주는 write 메소드를 사용한다.
WebSocketManager.write(path, message);
매개변수 설명 path
웹 소켓의 아이디를 나타내며, 웹 소켓의 컨텍스트 패스이다.
test로 설정하였다면 다음의 주소로 접속한 모든 웹 소켓에 메시지를 전달한다.
ws://ServerIP:ServerPort/{applicationName}/testmessage
지정한 웹 소켓 패스로 접속한 모든 웹 소켓에게 전달할 메시지를 지정한다.
전달할 수 있는 타입은 String, byte[], Object이다.
-
개별 전송
필요한 경우에는 웹 소켓 세션 중 단 하나의 세션만 골라 메시지를 송신할 수 있다. 브로드캐스팅과 동일하게 write 메소드를 사용하고 세션 키를 추가로 전달한다. path, message는 브로드캐스팅의 설명을 참고한다.
WebSocketManager.write(path, sessionKey, message);
매개변수 설명 sessionKey
웹 소켓 패스에 접속한 웹 소켓들 중 메시지를 전달할 세션의 키를 입력한다.
5. 웹 소켓 세션
웹 소켓을 통해 접속된 세션은 서비스 내에서는 일반적으로 세션을 얻을 때와 동일하게 RequestContext로부터 세션을 얻어오는 것이 가능하다.
ProObjectSession session = requestContext.getSession();
세션을 얻어온 다음에는 일반적인 웹 세션과 동일한 방식으로 내부의 속성(Attribute)들을 설정하는 것이 가능하다. WebSocket을 통해 세션이 맺어졌다면, 일반적인 웹 세션의 Attribute가 아니라 웹 소켓 세션 내의 UserProperties에 저장되며 API 만 웹 세션 형태로 제공되므로 추후 이용하는데 참고하도록 한다.
이벤트 핸들러나 서비스에서 현재 연결되어 활성화 중인 세션들의 목록을 얻어올 경우에는 다음과 같이 WebSocketManager를 이용한다.
Set<String> sessionKeys = WebSocketManager.getActiveSessionKeySet(path);
6. 웹 소켓 커스터마이징
ProObject의 웹 소켓은 브로드캐스팅이나 개별 전송을 할 수 있도록 코드가 작성되어 있다. 웹 소켓을 통한 메시지 송신이나 세션 관리를 연결하는 경우 이벤트 등에 대한 처리를 하려면 DefaultProObjectWebSocket을 상속받아 구현하는 것을 권장하나, 필요한 경우에는 커스터마이징이 가능하다.
|
onMessage 같은 경우는 오버라이딩이 불가능하도록 코드가 작성되어 있다. 메시지를 수신하는 경우 마다 작업을 처리하고 싶은 경우에는 웹 소켓의 메시지 처리자 서비스를 지정하도록 한다. |
ProObjectWebSocket 인터페이스를 상속받아야 하며, 구현해야 하는 메소드들은 다음과 같다.
-
onCreate
웹 소켓 객체가 처음 생성되었을 때 불리우는 메소드이다. 각종 초기화 등의 작업을 할 때 사용한다.
public void onCreate(String path);
-
onInit
웹 소켓으로 연결 요청이 들어와 세션이 맺어진 경우에 호출되는 메소드이다. 연결된 세션 객체가 함께 전달된다.
public void onInit(Session session);
-
onWrite
서비스, 이벤트 등에서 WebSocketManager를 통해 write 메소드를 호출한 경우 호출되는 메소드이다.
WebSocketWriteBuffer 객체가 전달되며, 해당 객체 내에는 전달할 세션의 키와 전달할 객체(Object, String, byte[])가 모두 전달된다. 세션의 키가 null인 경우에는 브로드캐스팅 메시지이며, 호출한 메소드의 종류에 따라 Object, String, byte[]의 필드가 채워져서 전달된다.
public void onWrite(WebSocketWriteBuffer event);
-
onError
웹 세션에서 오류가 발생한 경우 호출되는 메소드이다.
일반적으로 거의 사용할 일은 적은 편이며, onError가 호출되었다고 해도 웹 소켓 세션이 종료되지 않는다는 점은 주의해야 한다.
public void onError(Session session, Throwable exception);
-
onClose
웹 소켓의 연결이 끊어진 경우에 호출되는 메소드이다.
public void onClose(Session session);
위의 메소드들을 일반적인 웹 소켓을 구현하는 것과 동일하게 커스터마이징해서 사용할 수 있다. 커스터마이징을 후에는 반드시 애플리케이션 설정에서 클래스를 등록하고 클래스는 이벤트로 배포해야 한다.
|
일반적으로 서블릿 워커 스레드에서 수행되는 웹 소켓과 달리 JEUS에서의 웹 소켓은 Node.JAVA 스레드에서만 수행되므로 항시 싱글 스레드에서만 수행된다. 따라서 웹 소켓에서 세션을 관리할 때 일반적으로 걱정하는 동기화 부분에 대해서는 전혀 고려하지 않아도 된다. |