創建項目
這里使用阿里云服務器
?
https://start.aliyun.com/

勾選
- MyBatis Framework (在SQL分類下)
- MySQL Driver (在SQL分類下)
- WebSocket (在Messaging分類下)
- Spring Web (在Web分類下)

項目結構

消息發送機制

按照當前已有的知識,主要是HTTP HTTP自身是難以實現這種消息推送效果的~~
HTTP要想實現類似的效果,就需要基于“輪詢”的機制~~
消息推送機制--服務器發送事件 (SSE)
我之前學習過的服務器開發,主要是這樣的模型:
客戶端,主動向服務器發起請求,服務器收到之后,返回一個響應。
如果客戶端不主動發起請求,服務器是不能主動聯系客戶端的~~
這就是消息推送機制
輪詢機制
?????
?
?判斷輪訓or消息推送
很明顯,像這樣的輪詢操作,開銷是比較大的,成本也是比較高的~~
- 如果輪詢間隔時間長,玩家1落子之后,玩家2不能及時的拿到結果.
- 如果輪詢間隔時間短,雖然即時性得到改善,但是玩家2不得不浪費更多的機器資源(尤其是帶寬)
這就類似于去餐館吃飯~~
1.每隔1分鐘,就去前臺看一眼,問問老板,,我的飯好了沒~~
2.我直接找個角落坐下來,玩手機~~啥時候飯做好了,老板就端過來了~~
明顯方案2更好,方案2就是服務器發送事件 (SSE)
但是缺點是只支持單向通信:SSE 只支持從服務器到客戶端的單向通信,不能用于雙向實時通信。
因此, websocket就是實現消息推送的一個主要的方式~~
websocket介紹
需要注意的是ws => websocket,不是"猥瑣”的縮寫~ (滑稽)
websocket報文格式
是一個應用層協議, 下層是基于TCP的

十分顯而易見, 文本幀就是傳輸文本數據(比如JSON格式), 二進制幀就是傳輸二進制數據(比如圖片、文件、音頻流等)
提示一下, 這里Ping幀和Pong幀通常被用作心跳包,用于檢測連接的狀態,確保客戶端和服務器之間的連接是活躍的。
- Ping幀:由一端(通常是服務器)發送,表示一個心跳請求。
- Pong幀:由接收到Ping幀的另一端(通常是客戶端)發送,作為回應。
通過定期發送Ping幀并接收Pong幀,可以檢測到連接是否正常以及是否需要重新建立連接。

Payload len: 當前數據報文攜帶的數據載荷長度。
- 這個字段本身就是一個變長的,WebSocket數據報能夠承載的載荷長度是非常長的。

- Payload data: 實際的傳輸數據。
websocket握手過程
websocket握手過程(建立連接的過程)
使用網頁端,嘗試和服務器建立websocket連接.
網頁端會先給服務器發起一個HTTP請求~~這個HTTP請求中會帶有特殊的header
Connection: Upgrade
Upgrade: Websocket
這兩個header 其實就是在告知服務器,我們要進行協議升級,
如果服務器支持 websocket,就會返回一個特殊的HTTP響應~~這個響應的狀態碼是101.(切換協議)
客戶端和服務器之間就開始使用 websocket來進行通信了~~
編寫一個簡單的websocket代碼
編寫服務器(Java)

TestAPI extends這個類
public class TestAPI extends TextWebSocketHandler {
看看可以重寫哪些方法
?

重寫這四個方法


每個添加打印到控制臺的信息

新建文件WebSocketConfig


TestAPI加上注解@Component



?
編寫客戶端(JS)





前后端函數都是一一對應, 只不過函數方法名字不一樣, 意義都是一樣的


js完整代碼:?
<script>// 創建websocket實例let websocket = new WebSocket("ws://127.0.0.1:8080/test");//給實例掛載一些回調函數websocket.onopen = function () {console.log("連接建立");}websocket.onclose = function () {console.log("連接關閉");}websocket.onerror = function () {console.log("出現錯誤");}websocket.onmessage = function (e) {console.log("收到消息 "+ e.data);}//實現點擊按鈕后, 通過websocket發送請求//querySelector是id選擇器let input = document.querySelector("#message");let button = document.querySelector("#submit");button.onclick = function () {console.log("發送消息: "+input.value);websocket.send(input.value);}</script>
演示

訪問?http://127.0.0.1:8080/TestAPI.html
連接建立

發送消息

那么如何實現服務器端也發送消息呢
@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {System.out.println("收到消息 "+ message.getPayload());session.sendMessage(message);System.out.println("發送消息 " +message.getPayload());}
只需要在

重啟服務

至此, WebSocket示例已經完成