一、什麼是WebSocket?
B/S結構的軟體項目中有時用戶端需要實時的獲得伺服器消息,但預設HTTP協定隻支援請求響應模式,這樣做可以簡化Web伺服器,減少伺服器的負擔,加快響應速度,因為伺服器不需要與用戶端長時間建立一個通信連結,但不容易直接完成實時的消息推送功能,如聊天室、背景資訊提示、實時更新資料等功能,但通過polling、Long polling、長連接配接、Flash Socket以及HTML5中定義的WebSocket能完成該功能需要。
WebSocket是HTML5開始提供的一種在單個TCP連接配接上進行全雙工通訊的協定,能更好的節省伺服器資源和帶寬,并且能夠更實時地進行通訊。WebSocket 使得用戶端和伺服器之間的資料交換變得更加簡單,允許服務端主動向用戶端推送資料,在WebSocket API中,浏覽器和伺服器隻需要完成一次握手,兩者之間就直接可以建立持久性的連接配接,并進行雙向資料傳輸。
Socket又稱"套接字",應用程式通常通過"套接字"向網絡送出請求或者應答網絡請求。Socket的英文原義是“孔”或“插座”,作為UNIX的程序通信機制。Socket可以實作應用程式間網絡通信。

Socket可以使用TCP/IP協定或UDP協定。
TCP/IP協定
TCP/IP協定是目前應用最為廣泛的協定,是構成Internet國際網際網路協定的最為基礎的協定,由TCP和IP協定組成:
TCP協定:面向連接配接的、可靠的、基于位元組流的傳輸層通信協定,負責資料的可靠性傳輸的問題。
IP協定:用于封包交換網絡的一種面向資料的協定,主要負責給每台網絡裝置一個網絡位址,保證資料傳輸到正确的目的地。
UDP協定
UDP特點:無連接配接、不可靠、基于封包的傳輸層協定,優點是發送後不用管,速度比TCP快。
二、SpringBoot整合WebSocket
建立一個spring boot項目spring-boot-websocket,按照下面步驟操作。
1.pom.xml引入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.建立WebSocket的配置類
這個配置類檢測帶注解@ServerEndpoint的bean并注冊它們,配置類代碼如下:
@Configuration
public class WebSocketConfig {
/**
* 給spring容器注入這個ServerEndpointExporter對象
* 相當于xml:
* <beans>
* <bean id="serverEndpointExporter" class="org.springframework.web.socket.server.standard.ServerEndpointExporter"/>
* </beans>
* <p>
* 檢測所有帶有@serverEndpoint注解的bean并注冊他們。
*
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
System.out.println("我被注入了");
return new ServerEndpointExporter();
}
}
3.建立WebSocket的處理類
這個處理類需要使用@ServerEndpoint,這個類裡監聽連接配接的建立關閉、消息的接收等,具體代碼如下:
@ServerEndpoint(value = "/ws/asset")
@Component
public class WebSocketServer {
@PostConstruct
public void init() {
System.out.println("websocket 加載");
}
private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
private static final AtomicInteger OnlineCount = new AtomicInteger(0);
// concurrent包的線程安全Set,用來存放每個用戶端對應的Session對象。
private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();
/**
* 連接配接建立成功調用的方法
*/
@OnOpen
public void onOpen(Session session) {
SessionSet.add(session);
int cnt = OnlineCount.incrementAndGet(); // 線上數加1
log.info("有連接配接加入,目前連接配接數為:{}", cnt);
SendMessage(session, "連接配接成功");
}
/**
* 連接配接關閉調用的方法
*/
@OnClose
public void onClose(Session session) {
SessionSet.remove(session);
int cnt = OnlineCount.decrementAndGet();
log.info("有連接配接關閉,目前連接配接數為:{}", cnt);
}
/**
* 收到用戶端消息後調用的方法
*
* @param message
* 用戶端發送過來的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("來自用戶端的消息:{}",message);
SendMessage(session, "收到消息,消息内容:"+message);
}
/**
* 出現錯誤
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("發生錯誤:{},Session ID: {}",error.getMessage(),session.getId());
error.printStackTrace();
}
/**
* 發送消息,實踐表明,每次浏覽器重新整理,session會發生變化。
* @param session
* @param message
*/
public static void SendMessage(Session session, String message) {
try {
// session.getBasicRemote().sendText(String.format("%s (From Server,Session ID=%s)",message,session.getId()));
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("發送消息出錯:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 群發消息
* @param message
* @throws IOException
*/
public static void BroadCastInfo(String message) throws IOException {
for (Session session : SessionSet) {
if(session.isOpen()){
SendMessage(session, message);
}
}
}
/**
* 指定Session發送消息
* @param sessionId
* @param message
* @throws IOException
*/
public static void SendMessage(String message,String sessionId) throws IOException {
Session session = null;
for (Session s : SessionSet) {
if(s.getId().equals(sessionId)){
session = s;
break;
}
}
if(session!=null){
SendMessage(session, message);
}
else{
log.warn("沒有找到你指定ID的會話:{}",sessionId);
}
}
}
4.Html編寫方式
目前大部分浏覽器支援WebSocket,比如Chrome, Mozilla,Opera和Safari,在html頁面進行websocket的連接配接建立、收消息的監聽,頁面代碼如下:
<html>
<head>
<meta charset="UTF-8">
<title>websocket測試</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<style type="text/css">
h3,h4{
text-align:center;
}
</style>
</head>
<body>
<h3>WebSocket測試,用戶端接收到的消息如下:</h3>
<textarea id = "messageId" readonly="readonly" cols="150" rows="30" >
</textarea>
<script type="text/javascript">
var socket;
if (typeof (WebSocket) == "undefined") {
console.log("遺憾:您的浏覽器不支援WebSocket");
} else {
console.log("恭喜:您的浏覽器支援WebSocket");
//實作化WebSocket對象
//指定要連接配接的伺服器位址與端口建立連接配接
//注意ws、wss使用不同的端口。我使用自簽名的證書測試,
//無法使用wss,浏覽器打開WebSocket時報錯
//ws對應http、wss對應https。
socket = new WebSocket("ws://localhost:8080/ws/asset");
//連接配接打開事件
socket.onopen = function() {
console.log("Socket 已打開");
socket.send("消息發送測試(From Client)");
};
//收到消息事件
socket.onmessage = function(msg) {
$("#messageId").append(msg.data+ "\n");
console.log(msg.data );
};
//連接配接關閉事件
socket.onclose = function() {
console.log("Socket已關閉");
};
//發生了錯誤事件
socket.onerror = function() {
alert("Socket發生了錯誤");
}
//視窗關閉時,關閉連接配接
window.unload=function() {
socket.close();
};
}
</script>
</body>
</html>
三、業務調用
WebSocket ws = new WebSocket();
JSONObject jo = new JSONObject();
jo.put("message", "這個比密碼不對還想登入!");
jo.put("To", "admin");// 給使用者名為admin的使用者推送
try {
ws.onMessage(jo.toString());
} catch (IOException e) {
e.printStackTrace();
}
四、 檢視運作效果
啟動SpringBoot項目
1.打開首頁
本地浏覽器打開首頁http://localhost:8080/,出現WebSocket測試頁面,同時背景列印連接配接的日志。
有連接配接加入,目前連接配接數為:1,sessionId=0
2.往用戶端發送消息
通過上面日志可以看到用戶端連接配接連接配接的sessionId,我測試時候sessionId是0,然後浏覽器通路下面接口即可往用戶端發送消息。
//參數說明: id:sessionID
//參數說明: message:消息内容
http://localhost:8080/api/ws/sendOne?id=0&message=你好Java碎碎念
到此SpringBoot整合WebSocket的功能已經全部實作。
完整源碼位址: https://github.com/suisui2019/springboot-study
文章轉載至:https://www.cnblogs.com/haha12/p/11933310.html
-----------------------------------
作者:怒吼的蘿蔔
連結:http://www.cnblogs.com/nhdlb/
-----------------------------------