1.Websocket介紹
傳統的瀏覽器與服務器通訊的方式是http連接,這種連接是無狀態、單向的通信協議。即每次建立連接都得傳遞cookie、session信息來證明自己的身份,因爲服務器是不會記住之前連接的信息。同時只有客戶端向服務端發出請求才能獲得返回信息,服務器是不能主動給客戶端發送連接的,因爲服務器記不住有哪些客戶端跟自己連接的。
這種單向請求的特點,註定瞭如果服務器有連續的狀態變化,客戶端要獲知就非常麻煩。大多數 Web 應用程序將通過頻繁的異步JavaScript和XML(AJAX)請求實現長輪詢。輪詢的效率低,非常浪費資源(因爲必須不停連接,或者 HTTP 連接始終打開)。
WebSocket 連接允許客戶端和服務器之間進行全雙工通信,以便任一方都可以通過建立的連接將數據推送到另一端。WebSocket 只需要建立一次連接,就可以一直保持連接狀態。這相比於輪詢方式的不停建立連接顯然效率要大大提高。
首先要理清websocket連接是web瀏覽器(支持html5,無需引用js)與web服務器(websocket服務)之間建立,連接採用websocket協議。一旦建立後,服務端和客戶端都可以雙向發送消息。
2.springboot配置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發生了錯誤");
}
}