WebSocket 的簡單應用入門
websocket簡單實現分為以下幾個步驟:新增websocket庫、編寫後臺程式碼、編寫前端程式碼。
新增websocket庫
在maven中新增websocket庫的程式碼如下所示:
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> <scope>provided</scope> </dependency>
注:九風有次沒寫<scope>欄位,前端後臺都會報錯,大家記得加上就行。
WebSocket 客戶端的實現
一,WebSocket 客戶端的簡單示例
WebSocket 的用法比較簡單,下面是一個網頁尾本的例子:
var ws = new WebSocket("wss://echo.websocket.org"); ws.onopen = function(evt) { console.log("Connection open ..."); ws.send("Hello WebSockets!"); }; ws.onmessage = function(evt) { console.log( "Received Message: " + evt.data); ws.close(); }; ws.onclose = function(evt) { console.log("Connection closed."); };
二,WebSocket 客戶端的 API
- WebSocket 建構函式
WebSocket 物件作為一個建構函式,用於新建 WebSocket 例項
var ws = new WebSocket('ws://localhost:8080');
執行上面語句之後,客戶端就會與伺服器進行連線。
- webSocket.readyState
readyState
屬性返回例項物件的當前狀態,共有四種。
- CONNECTING:值為0,表示正在連線。
- OPEN:值為1,表示連線成功,可以通訊了。
- CLOSING:值為2,表示連線正在關閉。
- CLOSED:值為3,表示連線已經關閉,或者開啟連線失敗。
下面是一個示例:
switch (ws.readyState) {
case WebSocket.CONNECTING:
// do something
break;
case WebSocket.OPEN:
// do something
break;
case WebSocket.CLOSING:
// do something
break;
case WebSocket.CLOSED:
// do something
break;
default:
// this never happens
break;
}
- webSocket.onopen
例項物件的onopen
屬性,用於指定連線成功後的回撥函式。
ws.onopen = function () {
ws.send('Hello Server!');
}
如果要指定多個回撥函式,可以使用addEventListener
方法。
ws.addEventListener('open', function (event) {
ws.send('Hello Server!');
});
- webSocket.onclose
例項物件的onclose
屬性,用於指定連線關閉後的回撥函式。
ws.onclose = function(event) {
var code = event.code;
var reason = event.reason;
var wasClean = event.wasClean;
// handle close event
};ws.addEventListener("close", function(event) {
var code = event.code;
var reason = event.reason;
var wasClean = event.wasClean;
// handle close event
});
- webSocket.onmessage
例項物件的onmessage
屬性,用於指定收到伺服器資料後的回撥函式。
ws.onmessage = function(event) {
var data = event.data;
// 處理資料
};ws.addEventListener("message", function(event) {
var data = event.data;
// 處理資料
});
注意,伺服器資料可能是文字,也可能是二進位制資料(blob
物件或Arraybuffer
物件)。
ws.onmessage = function(event){
// 動態判斷收到的資料型別
if(typeof event.data === String) {
console.log("Received data string");
}// 動態判斷收到的資料型別
if(event.data instanceof ArrayBuffer){
var buffer = event.data;
console.log("Received arraybuffer");
}
}
除了動態判斷收到的資料型別,也可以使用binaryType
屬性,顯式指定收到的二進位制資料型別。
// 收到的是 blob 資料
ws.binaryType = "blob";
ws.onmessage = function(e) {
console.log(e.data.size);
};// 收到的是 ArrayBuffer 資料
ws.binaryType = "arraybuffer";
ws.onmessage = function(e) {
console.log(e.data.byteLength);
};
- webSocket.send()
例項物件的send()
方法用於向伺服器傳送資料。
1,傳送文字的例子:
ws.send('your message');
2,傳送 Blob 物件的例子:
var file = document
.querySelector('input[type="file"]')
.files[0];
ws.send(file);
3,傳送 ArrayBuffer 物件的例子:
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
ws.send(binary.buffer);
- webSocket.bufferedAmount
例項物件的bufferedAmount
屬性,表示還有多少位元組的二進位制資料沒有傳送出去。它可以用來判斷髮送是否結束。
var data = new ArrayBuffer(10000000);
socket.send(data);if (socket.bufferedAmount === 0) {
// 傳送完畢
} else {
// 傳送還沒結束
}
- webSocket.onerror
例項物件的onerror
屬性,用於指定報錯時的回撥函式。
socket.onerror = function(event) {
// handle error event
};socket.addEventListener("error", function(event) {
// handle error event
});
實際應用前端程式碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
websocket Demo---- user000 <br />
<input id="text" type="text" />
<button onclick="send()"> Send </button>
<button onclick="closeWebSocket()"> Close </button>
<div id="message"> </div>
<script type="text/javascript">
//判斷當前瀏覽器是否支援WebSocket
if('WebSocket' in window){
websocket = new WebSocket("ws://localhost:8080/Demo/websocketTest/user000");
console.log("link success")
}else{
alert('Not support websocket')
}
//連線發生錯誤的回撥方法
websocket.onerror = function(){
setMessageInnerHTML("error");
};
//連線成功建立的回撥方法
websocket.onopen = function(event){
setMessageInnerHTML("open");
}
console.log("-----")
//接收到訊息的回撥方法
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}
//連線關閉的回撥方法
websocket.onclose = function(){
setMessageInnerHTML("close");
}
//監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。
window.onbeforeunload = function(){
websocket.close();
}
//將訊息顯示在網頁上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//關閉連線
function closeWebSocket(){
websocket.close();
}
//傳送訊息
function send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</body>
</html>
WebSocket 服務端的實現
後臺實現websocket有兩種方式:使用繼承類、使用註解;註解方式比較方便,一下程式碼中使用註解方式來進行演示。
- @ServerEndpoint
宣告websocket地址類似Spring MVC中的@controller註解類似,websocket使用@ServerEndpoint來進行宣告介面:@ServerEndpoint(value="/websocket/{paraName}") ; 其中 “ { } ”用來表示帶引數的連線,如果需要獲取{}中的引數在引數列表中增加:@PathParam("paraName") Integer userId 。
1,@OnOpen
public void onOpen(Session session) throws IOException{ }-------有連線時的觸發函式。 我們可以在使用者連線時記錄使用者的連線帶的引數,只需在引數列表中增加引數:@PathParam("paraName") String paraName。
擴充套件:
其中OnOpen發生的時候,即有連結過來的時候,可以把當前WebSocket Server丟在ServerManager裡管理起來,這樣Tomcat才知道總共有哪些Server, 方便以後進行群發,具體案例http://how2j.cn/k/websocket/websocket-develop/1628.html#nowhere
2,@OnClose
public void onClose(){ }------連線關閉時的呼叫方法。
3,@OnMessage
public void onMessage(String message, Session session) { }-------收到訊息時呼叫的函式,其中Session是每個websocket特有的資料成員
4,Session----每個Session代表了兩個web socket斷點的會話;當websocket握手成功後,websocket就會提供一個開啟的Session,可以通過這個Session來對另一個端點發送資料;如果Session關閉後傳送資料將會報錯。
5,Session.getBasicRemote().sendText("message")-------向該Session連線的使用者傳送字串資料。
6,@OnError
public void onError(Session session, Throwable error) { }--------發生意外錯誤時呼叫的函式。
實際應用後端程式碼如下:
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Class: Test
* @Description: 簡單websocket demo
* @author 九風萍舟
*/
@ServerEndpoint(value="/websocketTest/{userId}")
public class Test {
private Logger logger = LoggerFactory.getLogger(Test.class);
private static String userId;
//連線時執行
@OnOpen
public void onOpen(@PathParam("userId") String userId,Session session) throws IOException{
this.userId = userId;
logger.debug("新連線:{}",userId);
}
//關閉時執行
@OnClose
public void onClose(){
logger.debug("連線:{} 關閉",this.userId);
}
//收到訊息時執行
@OnMessage
public void onMessage(String message, Session session) throws IOException {
logger.debug("收到使用者{}的訊息{}",this.userId,message);
session.getBasicRemote().sendText("收到 "+this.userId+" 的訊息 "); //回覆使用者
}
//連線錯誤時執行
@OnError
public void onError(Session session, Throwable error){
logger.debug("使用者id為:{}的連線傳送錯誤",this.userId);
error.printStackTrace();
}
}
ServerEndpoint報錯: 原因是不能自動檢測 ServerEndpoint 的包,解決方法:複製 import javax.websocket.server.ServerEndpoint;
到檔案程式 import 區域即可。
測試執行
在Chrome上開啟前端程式碼後,馬上就建立了連線,大家可以使用F12檢視下建立連線的請求與響應,可以對比前面關於協議建立的部分進行學習。
建立連線後,想後臺傳送資料後,同時可以看到後臺返回的資訊:
前端測試
在後臺可以看到連線的建立和收到的資料:
後臺測試
對於其他功能功能大家可以自己測測。
總結
websocket特別適合於需要實時資料傳送的場景,比輪詢方式效率高很多。
擴充套件:一款非常特別的 WebSocket 伺服器:Websocketd。
它的最大特點,就是後臺指令碼不限語言,標準輸入(stdin)就是 WebSocket 的輸入,標準輸出(stdout)就是 WebSocket 的輸出。具體使用介紹http://www.ruanyifeng.com/blog/2017/05/websocket.html
參考來源於:
http://www.ruanyifeng.com/blog/2017/05/websocket.html
https://www.jianshu.com/p/d79bf8174196
https://www.java-mindmap.com/channel/7
http://how2j.cn/k/websocket/websocket-develop/1628.html#nowhere