「詳解」WebSocket相關知識整理
前言
記得大概半年前就產生了疑惑,即後台如何主動向前端推送數據。問了下專業老師,知道了原來有一個叫WebSocket的技術可以用於推送數據。於是,當時我就找了個教程,用的是Spring WebSocket。照著敲了一遍,也就搭起來了,依葫蘆畫瓢而已。當時有其他東西要學,也沒有相關的需求,就沒再接觸過。前陣子剛好要用這個框架,但是API早忘了,就又搜了一遍,發現網上各種各樣的案例都有,API都不一樣。以下是我這階段對各種與WebSocket掛鉤的知識點的梳理。
數據推送的應用場景
數據推送的應用場景很多,如發送公告,郵件提示啊等等。那麼問題是如何推送,換句話說,前端如何獲得最新的數據?
推和拉
假如後台更新了一些數據,如添加了一個公告,想要讓所有瀏覽主頁的人都看到。那麼我要做的,就是把伺服器的數據推送給瀏覽器。我們知道,雙方通信必須建立連接。但是問題就來了,HTTP連接的發起方只能是瀏覽器,而且請求一旦結束,連接就斷了。去哪裡找連接呢?所以,單純依賴HTTP來推數據是行不通的。那既然推不動,我客戶端主動去拉不就行了。
拉當然是可以的,一種解決方法就是輪詢,即每隔一段時間用Ajax請求一遍。這樣確實可以達到目的。但是存在兩個問題,一個是開銷問題,如果你輪詢了一個上午,都沒有最新消息,那你這一上午發出的請求都是無效請求,都是相當於在騷擾伺服器。你可能也意識到了前一個問題,決定把時間間隔設大,來減少請求數。但是這樣就可能影響實時性了,也就是說如果在本次無效請求後,數據剛好更新,那麼你必須等待一個時間周期結束後,才能獲取到最新值。
WebSocket技術
WebSocket就是用來解決前面的連接問題的。使用WebSocket時,連接的發起方同樣是瀏覽器,但是不同的是,除非一方主動觸發,否則連接一旦建立就不會斷開。另外需要注意的是,建立連接,即握手過程,用的還是HTTP協議,這個過程如果順利的話,就會將HTTP協議升級到WebSocket協議。
WebSocket協議相對於HTTP有何優點?
除了讓後台可以主動推數據外,WebSocket還具有以下優點:
- 連接狀態可保持,因為是長連接,就不需要像HTTP那樣每次都帶Cookie這樣。
- 更少的控制信息,單純的WebSocket不需要HTTP那麼多的頭信息,輕量級。
- 支持擴展,可以擴展協議,如STOMP
後備選項 PLAN B
誒,有沒有注意到,我前面說的是"如果順利",難道HTTP升級到Websocket還會失敗嗎?答案是會。為什麼,因為不是所有瀏覽器都支持WebSocket協議的。那這問題不就出現了嗎,我當初是這麼想的,你們下個新的瀏覽器會死啊?!
後來,我冷靜思考了一下,我這樣想是不對的。因為如果是一個對外網站,一個遊客因為瀏覽器不支持,而不能得到良好的響應效果,你覺得他還會耐心地裝新瀏覽器,再次訪問嗎?所以,我們必須有後備選項實現推送功能。其實,所謂的後備選項就是輪詢。那這時候我們要做的就是前端的工作了,即判斷瀏覽器是否支持,如果支持就用WebSocket,如果不能就用Ajax輪詢。但是這樣其實工作量挺大的,特別是瀏覽器還要跟服務端交互,而不僅僅是接收數據的時候。
好在,有一個包含WebSocket和長輪詢的框架,SockJS。使用它的時候,如果瀏覽器支持就用WebSocket傳輸,如果不支持就用輪詢。判斷和切換對我們來說是透明的,我們使用它的方法,跟使用WebSocket的API差不多。Spring WebSocket就支持SockJS,服務端配置也方便,綁定連接點的時候加上.withSockJS()即可。
WebSocket的API
服務端發布一個WebSocket連接點的過程:
1.創建連接點類
2.實現該連接點的各個生命周期的方法,如連接建立成功,來消息,連接斷開這些回調函數
3.在連接點類中添加業務邏輯,這主要看你的應用需求了
4.發布連接點,其實就是綁定這個連接點類到一個URL,當客戶端嘗試連接這個URL後,所有的操作由這個類實例完成
JavaEE WebSocket API
JavaEE有相關的API規範,JSR 356。Tomcat實現了這套規範。
需要的包:如果是Spring Boot項目,你勾選了Web選項。那你就有了內置Tomcat,也就直接能用WebSocket了。註:不需要引入Spring-WebSocket。
API使用方式:這個API的使用方式是,創建一個連接點類,標註上@ServerEndPoint("指定的URL")註解,然後在類內部,使用@OnOpen, @OnMessage,@OnClose等註解標識對應的生命周期回調方法。
Spring WebSocket API
Spring WebSocket 在原生基礎上,做了些補充,有自己的使用方法。
需要的包:如果是Spring Boot項目要使用Spring的WebSocket,就要勾選WebSocket選項,它就會引入相關的整合包。
API使用方式:註:這裡只講純WebSocket的使用,不講擴展內容。Spring把連接點的處理類叫作Handler,創建Handler的方式可以是實現WebSocketHandler介面,或繼承已有類TextWebSocketHandler等,你需要根據需要覆蓋已有的回調方法。然後在實現了WebSocketConfigurer介面的配置類中,綁定URL。這裡需要使用@EnableWebSocket註解開啟WebSocket支持。
與原生API的對比:我覺得同樣是使用純WebSocketAPI,Spring因為用的是實現介面的形式,所以它各個回調方法的參數都更明確。而且一看介面就很清楚有哪些回調方法。而如果使用@OnOpen,@OnMessage等註解,你根本不清楚註解的方法,支持哪些參數,參數到底是什麼類型的。這些你看註解代碼都看不出來,需要看官方的說明才清楚。
擴展內容:Spring除了讓你能使用純WebSocket外,還支持其他擴展。如支持SockJS使得瀏覽器.都能接受推送數據,支持WebSocket擴展協議STOMP,使得能夠像消息機制那樣使用WebSocket。
使用程度:Spring WebSocket支持擴展,你可以自己決定用到什麼程度。
1.純WebSocket,部分瀏覽器不支持。如果你確定用戶使用的瀏覽器都沒問題,用到這層就夠了。
2.支持SockJS(WebSocket + 長輪詢),服務端改動的話,只需要加withSockJS即可。所有瀏覽器都支持
3.純WebSocket/SockJS + STOMP。這種時候是隊列使用的是In-Memory的MQ。消息機制,可發布訂閱,實現廣播。
4.純WebSocket/SockJS + STOMP + ActiveMQ/RabbitMQ。引入第三方消息隊列。這時候消息就能持久化,防止因伺服器宕機,導致消息丟失。
注意:使用STOMP,並不一定要配合SockJS。
Socket.IO
Socket.IO是單獨的一套WebSocketAPI。它使用的Engine.IO引擎也能夠切換傳輸方式,即所有瀏覽器都支持,相當於SockJS吧。它的分組機制,使得它也能夠廣播消息,暫時不知道是否支持STOMP擴展。它官方提供的服務端實現是Node版,客戶端支持多種語言。Java如果要使用它的服務端的話,可以使用一個開源的用Netty實現的框架netty-socketio。
目前就Spring-WebSocket與Socket.IO的性能優劣還不甚了解。
作者:貓毛·波拿巴
原文:https://www.cnblogs.com/longfurcat/p/10201026.html
※mysql索引最左匹配原則的理解
※Asp.net Core + Log4net + ELK 搭建日誌中心
TAG:程序員小新人學習 |