springboot集成Websocket(含源碼)

1.Websocket介紹

傳統的瀏覽器與服務器通訊的方式是http連接,這種連接是無狀態、單向的通信協議。即每次建立連接都得傳遞cookie、session信息來證明自己的身份,因爲服務器是不會記住之前連接的信息。同時只有客戶端向服務端發出請求才能獲得返回信息,服務器是不能主動給客戶端發送連接的,因爲服務器記不住有哪些客戶端跟自己連接的。

這種單向請求的特點,註定瞭如果服務器有連續的狀態變化,客戶端要獲知就非常麻煩。大多數 Web 應用程序將通過頻繁的異步JavaScript和XML(AJAX)請求實現長輪詢。輪詢的效率低,非常浪費資源(因爲必須不停連接,或者 HTTP 連接始終打開)。

WebSocket 連接允許客戶端和服務器之間進行全雙工通信,以便任一方都可以通過建立的連接將數據推送到另一端。WebSocket 只需要建立一次連接,就可以一直保持連接狀態。這相比於輪詢方式的不停建立連接顯然效率要大大提高。

websockets-flow.png

首先要理清websocket連接是web瀏覽器(支持html5,無需引用js)web服務器(websocket服務)之間建立,連接採用websocket協議。一旦建立後,服務端和客戶端都可以雙向發送消息。

2.springboot配置websocket

源碼自取:https://github.com/andesmountain/test/tree/master/Websocket

                                                       

maven引用

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

ServerEndpointExporter建立

該類的作用是檢測到@ServerEndPoint的class,並將該class添加到ServerContainer中進行註冊。

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

@ServerEndPoint

建立Websocket server服務,客戶端通過訪問註解中的uri地址,與websocket服務器建立連接。

@Component
@ServerEndpoint("/websocket")
public class WebsocketServer {
    private static Logger log = Logger.getLogger(WebsocketServer.class);

    //靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。
    private static int onlineCount = 0;
    //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。
    private static CopyOnWriteArraySet<WebsocketServer> webSocketSet = new CopyOnWriteArraySet<WebsocketServer>();

    //與某個客戶端的連接會話,需要通過它來給客戶端發送數據
    private Session session;

    /**
     * 連接建立成功調用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在線數加1
        log.info("有新連接加入!當前在線人數爲" + getOnlineCount());
        try {
            sendMessage("建立連接成功");
        } catch (IOException e) {
            log.error("websocket IO異常");
        }
    }

    /**
     * 連接關閉調用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //從set中刪除
        subOnlineCount();           //在線數減1
        log.info("有一連接關閉!當前在線人數爲" + getOnlineCount());
    }

    /**
     * 收到客戶端消息後調用的方法
     *
     * @param message 客戶端發送過來的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("來自客戶端的消息:" + message);

        //羣發消息
        for (WebsocketServer item : webSocketSet) {
            try {
                item.sendMessage("" + onlineCount);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("發生錯誤");
        error.printStackTrace();
    }


    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 羣發自定義消息
     */
    public static void sendInfo(String message) throws IOException {
        log.info(message);
        for (WebsocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebsocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebsocketServer.onlineCount--;
    }
}

html

var socket;


if(typeof(WebSocket) == "undefined") {
    console.log("您的瀏覽器不支持WebSocket");
}else{
    console.log("您的瀏覽器支持WebSocket");

    socket = new WebSocket("ws://localhost:8080/websocket");
    //打開事件
    socket.onopen = function() {
        console.log("Socket 已打開");
        //socket.send("這是來自客戶端的消息" + location.href + new Date());
    };
    //獲得消息事件
    socket.onmessage = function(msg) {
        console.log(msg.data);
        $('#area').val($('#area').val()+"\t"+msg.data);

    };
    //關閉事件
    socket.onclose = function() {
        console.log("Socket已關閉");
    };
    //發生了錯誤事件
    socket.onerror = function() {
        alert("Socket發生了錯誤");
    }

}

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章