수색…


비고

WebSocket은 단일 TCP 연결을 사용하여 클라이언트와 서버 / 엔드 포인트 간의 통신을 가능하게하는 프로토콜입니다.

WebSocket은 웹 브라우저 및 웹 서버에 구현되도록 설계되었지만 모든 클라이언트 또는 서버 응용 프로그램에서 사용할 수 있습니다.

JSR 356 에서 개발되었고 Java EE 7 사양에 통합 된 웹 소켓 용 Java API에 대한이 항목입니다.

WebSocket 통신 생성하기

WebSocket은 단일 TCP 연결을 통해 양방향 / 양방향 통신 프로토콜을 제공합니다.

  • 클라이언트가 WebSocket 요청을 수신하는 서버에 대한 연결을 엽니 다.
  • 클라이언트는 URI를 사용하여 서버에 연결합니다.
  • 서버는 여러 클라이언트의 요청을 청취 할 수 있습니다.

서버 엔드 포인트

단지와 POJO에 주석으로 당신은 웹 소켓 서버 entpoint를 만들 수 있습니다 @ServerEndpoint . @OnMessage 는 들어오는 메시지를받는 메소드를 @OnMessage . @OnOpen 은 피어로부터의 새로운 연결이 수신 될 때 호출 될 메소드를 꾸미기 위해 사용될 수 있습니다. 마찬가지로 @OnClose 로 주석 된 메소드는 연결이 닫힐 때 호출됩니다.

@ServerEndpoint("/websocket")
public class WebSocketServerEndpoint
{

    @OnOpen
    public void open(Session session) {
     System.out.println("a client connected");
    }

    @OnClose
    public void close(Session session) {
     System.out.println("a client disconnected");
    }

    @OnMessage
    public void handleMessage(String message) {
        System.out.println("received a message from a websocket client! " + message);
    }

}

클라이언트 Enpoint

서버 끝점과 @ClientEndpoint POJO에 @ClientEndpoint 주석을 달아 WebSocket 클라이언트 끝점을 만들 수 있습니다.

@ClientEndpoint
public class WebsocketClientEndpoint {

    Session userSession = null;
    
    // in our case i.e. "ws://localhost:8080/myApp/websocket"
    public WebsocketClientEndpoint(URI endpointURI) {
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        container.connectToServer(this, endpointURI);
    }

    @OnOpen
    public void onOpen(Session userSession) {
        System.out.println("opening websocket");
        this.userSession = userSession;
    }

    @OnClose
    public void onClose(Session userSession, CloseReason reason) {
        System.out.println("closing websocket");
        this.userSession = null;
    }

    @OnMessage
    public void onMessage(String message) {
        System.out.println("received message: "+ message);
    }

    public void sendMessage(String message) {
        System.out.println("sending message: "+ message);
        this.userSession.getAsyncRemote().sendText(message);
    }
}

인코더와 디코더 : 객체 지향 웹 소켓

인코더와 디코더 덕분에 JSR 356은 객체 지향 통신 모델을 제공합니다.

메시지 정의

수신 된 모든 메시지가 연결된 모든 세션으로 다시 전송되기 전에 서버에 의해 변환되어야한다고 가정합니다.

public abstract class AbstractMsg {
    public abstract void transform();
}

이제 서버가 텍스트 기반 메시지와 정수 기반 메시지라는 두 가지 메시지 유형을 관리한다고 가정 해 보겠습니다.

정수 메시지는 내용 자체를 곱합니다.

public class IntegerMsg extends AbstractMsg {

    private Integer content;

    public IntegerMsg(int content) {
        this.content = content;
    }

    public Integer getContent() {
        return content;
    }

    public void setContent(Integer content) {
        this.content = content;
    }

    @Override
    public void transform() {
        this.content = this.content * this.content;
    }
}

문자열 메시지 앞에 몇 개의 텍스트가 추가됩니다.

public class StringMsg extends AbstractMsg {

    private String content;

    public StringMsg(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public void transform() {
        this.content = "Someone said: " + this.content;
    }
}

인코더 및 디코더

메시지 유형마다 하나의 인코더가 있고 모든 메시지에 대해 하나의 디코더가 있습니다. 인코더는 구현해야한다 Encoder.XXX<Type> 디코더를 구현해야하는 경우 인터페이스를 Decoder.XXX<Type> .

인코딩은 매우 간단합니다. 메시지에서 encode 메소드는 JSON 형식의 String을 출력해야합니다. 다음은 IntegerMsg 의 예입니다.

public class IntegerMsgEncoder implements Encoder.Text<IntegerMsg> {

    @Override
    public String encode(IntegerMsg object) throws EncodeException {
        JsonObjectBuilder builder = Json.createObjectBuilder();
        
        builder.add("content", object.getContent());
        
        JsonObject jsonObject = builder.build();
        return jsonObject.toString();
    }

    @Override
    public void init(EndpointConfig config) {
        System.out.println("IntegerMsgEncoder initializing");
    }

    @Override
    public void destroy() {
        System.out.println("IntegerMsgEncoder closing");
    }
}

StringMsg 클래스와 비슷한 인코딩입니다. 물론, 인코더는 추상 클래스를 통해 인수 분해 될 수 있습니다.

public class StringMsgEncoder implements Encoder.Text<StringMsg> {

    @Override
    public String encode(StringMsg object) throws EncodeException {
        JsonObjectBuilder builder = Json.createObjectBuilder();

        builder.add("content", object.getContent());

        JsonObject jsonObject = builder.build();
        return jsonObject.toString();
    }

    @Override
    public void init(EndpointConfig config) {
        System.out.println("StringMsgEncoder initializing");
    }

    @Override
    public void destroy() {
        System.out.println("StringMsgEncoder closing");
    }

}

디코더는 두 단계로 진행됩니다 : 수신 된 메시지가 willDecode 와 함께 예외 형식에 willDecode 다음 수신 된 원본 메시지를 decode 된 객체로 변환합니다.

공용 클래스 MsgDecoder는 Decoder.Text {

@Override
public AbstractMsg decode(String s) throws DecodeException {
    // Thanks to willDecode(s), one knows that
    // s is a valid JSON and has the attribute
    // "content"
    JsonObject json = Json.createReader(new StringReader(s)).readObject();
    JsonValue contentValue = json.get("content");

    // to know if it is a IntegerMsg or a StringMsg, 
    // contentValue type has to be checked:
    switch (contentValue.getValueType()) {
        case STRING:
            String stringContent = json.getString("content");
            return new StringMsg(stringContent);
        case NUMBER:
            Integer intContent = json.getInt("content");
            return new IntegerMsg(intContent);
        default:
            return null;
    }

}

@Override
public boolean willDecode(String s) {

    // 1) Incoming message is a valid JSON object
    JsonObject json;
    try {
        json = Json.createReader(new StringReader(s)).readObject();
    }
    catch (JsonParsingException e) {
        // ...manage exception...
        return false;
    }
    catch (JsonException e) {
        // ...manage exception...
        return false;
    }

    // 2) Incoming message has required attributes
    boolean hasContent = json.containsKey("content");

    // ... proceed to additional test ...
    return hasContent;
}

@Override
public void init(EndpointConfig config) {
    System.out.println("Decoding incoming message...");
}

@Override
public void destroy() {
    System.out.println("Incoming message decoding finished");
}

}

ServerEndPoint

Server EndPoint는 세 가지 주요 차이점이있는 WebSocket 통신 과 매우 흡사합니다.

  1. ServerEndPoint 주석에는 encodersdecoders 속성이 있습니다.

  2. sendText 하지만 sendObject 하여 메시지를 보내지 않습니다.

  3. OnError 주석이 사용됩니다. willDecode 동안 오류가 발생하면 여기에서 처리되고 오류 정보가 클라이언트로 다시 전송됩니다.

    @ServerEndpoint (value = "/ webSocketObjectEndPoint", 디코더 = {MsgDecoder.class}, 인코더 = {StringMsgEncoder.class, IntegerMsgEncoder.class}) public class ServerEndPoint {

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("A session has joined");
    }
    
    @OnClose
    public void onClose(Session session) {
        System.out.println("A session has left");
    }
    
    @OnMessage
    public void onMessage(Session session, AbstractMsg message) {
        if (message instanceof IntegerMsg) {
            System.out.println("IntegerMsg received!");
        } else if (message instanceof StringMsg) {
            System.out.println("StringMsg received!");
        }
    
        message.transform();
        sendMessageToAllParties(session, message);
    }
    
    @OnError
    public void onError(Session session, Throwable throwable) {
        session.getAsyncRemote().sendText(throwable.getLocalizedMessage());
    }
    
    private void sendMessageToAllParties(Session session, AbstractMsg message) {
        session.getOpenSessions().forEach(s -> {
            s.getAsyncRemote().sendObject(message);
        });
    }
    

    }

매우 장황했기 때문에 여기에 시각적 인 예제가 필요한 사람들을위한 기본 JavaScript 클라이언트가 있습니다. 이것은 채팅과 같은 예입니다. 연결된 모든 당사자가 답변을 받게됩니다.

<!DOCTYPE html>
<html>
    <head>
        <title>Websocket-object</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">        
        <!-- start of BAD PRACTICE! all style and script must go into a
             dedicated CSS / JavaScript file-->
        <style>
            body{
                background: dimgray;
            }

            .container{
                width: 100%;
                display: flex;
            }

            .left-side{
                width: 30%;
                padding: 2%;
                box-sizing:  border-box;
                margin: auto;
                margin-top: 0;
                background: antiquewhite;
            }
            .left-side table{
                width: 100%;
                border: 1px solid black;
                margin: 5px;
            }
            .left-side table td{
                padding: 2px;
                width: 50%;
            }
            .left-side table input{
                width: 100%;
                box-sizing: border-box;
            }

            .right-side{
                width: 70%;
                background: floralwhite;
            }
        </style>

        <script>
            var ws = null;
            window.onload = function () {
                // replace the 'websocket-object' with the
                // context root of your web application.
                ws = new WebSocket("ws://localhost:8080/websocket-object/webSocketObjectEndPoint");
                ws.onopen = onOpen;
                ws.onclose = onClose;
                ws.onmessage = onMessage;
            };

            function onOpen() {
                printText("", "connected to server");
            }

            function onClose() {
                printText("", "disconnected from server");
            }

            function onMessage(event) {
                var msg = JSON.parse(event.data);
                printText("server", JSON.stringify(msg.content));
            }

            function sendNumberMessage() {
                var content = new Number(document.getElementById("inputNumber").value);
                var json = {content: content};
                ws.send(JSON.stringify(json));
                printText("client", JSON.stringify(json));
            }

            function sendTextMessage() {
                var content = document.getElementById("inputText").value;
                var json = {content: content};
                ws.send(JSON.stringify(json));
                printText("client", JSON.stringify(json));
            }

            function printText(sender, text) {
                var table = document.getElementById("outputTable");
                var row = table.insertRow(1);
                var cell1 = row.insertCell(0);
                var cell2 = row.insertCell(1);
                var cell3 = row.insertCell(2);

                switch (sender) {
                    case "client":
                        row.style.color = "orange";
                        break;
                    case "server":
                        row.style.color = "green";
                        break;
                    default:
                        row.style.color = "powderblue";
                }
                cell1.innerHTML = new Date().toISOString();
                cell2.innerHTML = sender;
                cell3.innerHTML = text;
            }
        </script>

        <!-- end of bad practice -->
    </head>
    <body>

        <div class="container">
            <div class="left-side">
                <table>
                    <tr>
                        <td>Enter a text</td>
                        <td><input id="inputText" type="text" /></td>
                    </tr>
                    <tr>
                        <td>Send as text</td>
                        <td><input type="submit" value="Send" onclick="sendTextMessage();"/></td>
                    </tr>
                </table>

                <table>
                    <tr>
                        <td>Enter a number</td>
                        <td><input id="inputNumber" type="number" /></td>
                    </tr>
                    <tr>
                        <td>Send as number</td>
                        <td><input type="submit" value="Send" onclick="sendNumberMessage();"/></td>
                    </tr>
                </table>
            </div>
            <div class="right-side">
                <table id="outputTable">
                    <tr>
                        <th>Date</th>
                        <th>Sender</th>
                        <th>Message</th>
                    </tr>
                </table>
            </div>
        </div>
    </body>
</html>

코드가 완성되어 Payara 4.1에서 테스트되었습니다. 예제는 순수 표준입니다 (외부 라이브러리 / 프레임 워크 없음).



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow