石巖網(wǎng)站建設(shè) 0755seo網(wǎng)絡(luò)排名優(yōu)化
Websocket的基本概念
? Websocket是一個(gè)“應(yīng)用層協(xié)議”,和HTTP地位是對(duì)等的。都是基于傳輸層的TCP實(shí)現(xiàn)的一個(gè)廣泛被使用的應(yīng)用層協(xié)議。這個(gè)協(xié)議可以實(shí)現(xiàn)服務(wù)器主動(dòng)給客戶端推送數(shù)據(jù)這樣的功能。
websocket報(bào)文格式
簡(jiǎn)單了解一下Websocket的報(bào)文格式:
FIN表示是否要關(guān)閉websocket。在應(yīng)用層要通過(guò)Websocket的FIN來(lái)觸發(fā)TCP的FIN。與TCP的FIN是兩碼事。
RSV保留位:三個(gè)保留位?,F(xiàn)在還不用,以后可能有用。
opcode操作碼:描述了當(dāng)前這個(gè)websocket數(shù)據(jù)幀,是起到啥作用的。比如取值為0x1表示是個(gè)文本數(shù)據(jù),取值為0x2表示是個(gè)二進(jìn)制數(shù)據(jù)。
MASK表示是否開(kāi)啟掩碼操作。掩碼操作主要是為了避免“緩沖區(qū)溢出”。
payload length:就是載荷。也就是數(shù)據(jù)報(bào)上要攜帶的具體數(shù)據(jù)。
? ?payload length 有三種模式:
? ? 1)7 bit? ? ? 2)16bit? ? ?3)64bit
最初的7bit的payload length < 126,此時(shí)是模式1。如果7bit的值是126,此時(shí)是模式2,16bit生效。如果7bit的值是127,此時(shí)是模式3,64個(gè)bit生效了。
websocket的握手過(guò)程
在瀏覽器與服務(wù)器開(kāi)始建立連接的時(shí)候,還是先發(fā)送HTTP請(qǐng)求,這個(gè)HTTP請(qǐng)求中會(huì)帶有一些特殊的header。connection:表示連接升級(jí)。即將應(yīng)用層協(xié)議升級(jí)成websocket。服務(wù)器會(huì)返回一個(gè)響應(yīng),響應(yīng)中帶有是否同意升級(jí)的header。
后續(xù)websocket連接就建立好了,接下來(lái)就使用websocket進(jìn)行數(shù)據(jù)傳輸了。
注:HTTP響應(yīng)中的狀態(tài)碼101,表示”協(xié)議切換“?!皐ebsocket是基于HTTP協(xié)議來(lái)實(shí)現(xiàn)的”這種說(shuō)法是錯(cuò)誤的。
基于Websocket編寫(xiě)代碼
在Java中有兩種方式來(lái)使用websocket:
1.使用tomcat提供的原生websocket api。
2.使用Spring提供的websocket api.
接下來(lái)基于Spring的websocket api編寫(xiě)代碼:
首先要在pom.xml文件中引入依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
接下來(lái)編寫(xiě)服務(wù)器代碼:
1)創(chuàng)建一個(gè)類(lèi)作為WebSocketHandler
@Component
public class TestWebSocketAPI extends TextWebSocketHandler {@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {//這個(gè)方法會(huì)在webscoket連接建立之后,被自動(dòng)調(diào)用System.out.println("TestAPI 連接成功");}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {//這個(gè)方法是在websocket收到消息的時(shí)候,被自動(dòng)調(diào)用的System.out.println("TestAPI 收到消息:" +message.toString());//session是個(gè)會(huì)話,里面就記錄了通信雙方是誰(shuí).(session中就持有了websocket的通信連接)session.sendMessage(message);}@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {//這個(gè)方法是在連接出現(xiàn)異常的時(shí)候,被自動(dòng)調(diào)用的System.out.println("TestAPI 連接異常");}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {//這個(gè)方法是在連接正常關(guān)閉后,被自動(dòng)調(diào)用的System.out.println("TestAPI 連接關(guān)閉");}
?繼承TextWebSocketHandler后,就可以重寫(xiě)一些方法.
2)把上述類(lèi)的實(shí)例,注冊(cè)到spring里面,配置路由
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Autowiredprivate TestWebSocketAPI testWebSocketAPI;@Autowiredprivate WebSocketController webSocketController;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {//通過(guò)這個(gè)方法,把剛才創(chuàng)建好的Hanlder類(lèi)給注冊(cè)到具體的路徑上//此時(shí)當(dāng)瀏覽器,websocket的請(qǐng)求路徑是"/test" 的時(shí)候,就會(huì)調(diào)用到TestWebSocketAPI這個(gè)類(lèi)里的方法//registry.addHandler(testWebSocketAPI,"/test");registry.addHandler(webSocketController,"/WebSocketMessage")//通過(guò)注冊(cè)這個(gè)特定的http攔截器,就可以把用戶給HttpSession中添加的Attribute鍵值對(duì)//往WebSocketSession 里也添加一份.addInterceptors(new HttpSessionHandshakeInterceptor());}
}
客戶端的代碼編寫(xiě):
//編寫(xiě)js使用websocket的代碼//創(chuàng)建一個(gè)websocket示例let websocket = new Websocket("ws://127.0.0.1:8080/test");//給這個(gè)websocket注冊(cè)上一些回調(diào)函數(shù)websocket.onopen = function(){//連接建立完成后,就會(huì)自動(dòng)執(zhí)行案例console.log("websocket 連接成功");}websocket.onclose = function(){//連接斷開(kāi)后,自動(dòng)執(zhí)行到console.log("websocket 連接斷開(kāi)");}websocket.onerror = function(){//連接異常時(shí),自動(dòng)執(zhí)行到console.log("websocket 連接異常");}websocket.onmessage = function(e){//收到消息時(shí),自動(dòng)執(zhí)行到console.log("websocket 收到消息" + e.data);}let messageInput = document.querySelector('#message');let sendButton = document.querySelector('#send-button');sendButton.onclick = function(){console.log("websocket 發(fā)送消息" + messageInput.value);websocket.send(messageInput.value);}
以上,關(guān)于Websocket,希望對(duì)你有所幫助。