WebSocket簡介與消息推送
B/S結構的軟件項目中有時客戶端需要實時的獲得服務器消息,但默認HTTP協(xié)議只支持請求響應模式,這樣做可以簡化Web服務器,減少服務器的負擔,加快響應速度,因為服務器不需要與客戶端長時間建立一個通信鏈接,但不容易直接完成實時的消息推送功能,如聊天室、后臺信息提示、實時更新數(shù)據(jù)等功能,但通過polling、Long polling、長連接、Flash Socket以及HTML5中定義的WebSocket能完成該功能需要。
一、Socket簡介
Socket又稱"套接字",應用程序通常通過"套接字"向網(wǎng)絡發(fā)出請求或者應答網(wǎng)絡請求。Socket的英文原義是“孔”或“插座”,作為UNIX的進程通信機制。Socket可以實現(xiàn)應用程序間網(wǎng)絡通信。

Socket可以使用TCP/IP協(xié)議或UDP協(xié)議。
TCP/IP協(xié)議
TCP/IP協(xié)議是目前應用最為廣泛的協(xié)議,是構成Internet國際互聯(lián)網(wǎng)協(xié)議的最為基礎的協(xié)議,由TCP和IP協(xié)議組成:
TCP協(xié)議:面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,負責數(shù)據(jù)的可靠性傳輸?shù)膯栴}。
IP協(xié)議:用于報文交換網(wǎng)絡的一種面向數(shù)據(jù)的協(xié)議,主要負責給每臺網(wǎng)絡設備一個網(wǎng)絡地址,保證數(shù)據(jù)傳輸?shù)秸_的目的地。
UDP協(xié)議
UDP特點:無連接、不可靠、基于報文的傳輸層協(xié)議,優(yōu)點是發(fā)送后不用管,速度比TCP快。
二、WebSocket簡介與消息推送
B/S架構的系統(tǒng)多使用HTTP協(xié)議,HTTP協(xié)議的特點:
- 1 無狀態(tài)協(xié)議
- 2 用于通過 Internet 發(fā)送請求消息和響應消息
- 3 使用端口接收和發(fā)送消息,默認為80端口
底層通信還是使用Socket完成。

HTTP協(xié)議決定了服務器與客戶端之間的連接方式,無法直接實現(xiàn)消息推送(F5已壞),一些變相的解決辦法:
雙向通信與消息推送
輪詢:客戶端定時向服務器發(fā)送Ajax請求,服務器接到請求后馬上返回響應信息并關閉連接。 優(yōu)點:后端程序編寫比較容易。 缺點:請求中有大半是無用,浪費帶寬和服務器資源。 實例:適于小型應用。
長輪詢:客戶端向服務器發(fā)送Ajax請求,服務器接到請求后hold住連接,直到有新消息才返回響應信息并關閉連接,客戶端處理完響應信息后再向服務器發(fā)送新的請求。 優(yōu)點:在無消息的情況下不會頻繁的請求,耗費資小。 缺點:服務器hold連接會消耗資源,返回數(shù)據(jù)順序無保證,難于管理維護。Comet異步的ashx, 實例:WebQQ、Hi網(wǎng)頁版、Facebook IM。
長連接:在頁面里嵌入一個隱蔵iframe,將這個隱蔵iframe的src屬性設為對一個長連接的請求或是采用xhr請求,服務器端就能源源不斷地往客戶端輸入數(shù)據(jù)。 優(yōu)點:消息即時到達,不發(fā)無用請求;管理起來也相對便。 缺點:服務器維護一個長連接會增加開銷。 實例:Gmail聊天
Flash Socket:在頁面中內嵌入一個使用了Socket類的 Flash 程序JavaScript通過調用此Flash程序提供的Socket接口與服務器端的Socket接口進行通信,JavaScript在收到服務器端傳送的信息后控制頁面的顯示。 優(yōu)點:實現(xiàn)真正的即時通信,而不是偽即時。 缺點:客戶端必須安裝Flash插件;非HTTP協(xié)議,無法自動穿越防火墻。 實例:網(wǎng)絡互動游戲。
Websocket:
WebSocket是HTML5開始提供的一種瀏覽器與服務器間進行全雙工通訊的網(wǎng)絡技術。依靠這種技術可以實現(xiàn)客戶端和服務器端的長連接,雙向實時通信。
特點:
事件驅動
異步
使用ws或者wss協(xié)議的客戶端socket
能夠實現(xiàn)真正意義上的推送功能
缺點:
少部分瀏覽器不支持,瀏覽器支持的程度與方式有區(qū)別。

三、WebSocket客戶端
websocket允許通過JavaScript建立與遠程服務器的連接,從而實現(xiàn)客戶端與服務器間雙向的通信。在websocket中有兩個方法:
- 1、send() 向遠程服務器發(fā)送數(shù)據(jù)
- 2、close() 關閉該websocket鏈接
websocket同時還定義了幾個監(jiān)聽函數(shù)
- 1、onopen 當網(wǎng)絡連接建立時觸發(fā)該事件
- 2、onerror 當網(wǎng)絡發(fā)生錯誤時觸發(fā)該事件
- 3、onclose 當websocket被關閉時觸發(fā)該事件
- 4、onmessage 當websocket接收到服務器發(fā)來的消息的時觸發(fā)的事件,也是通信中最重要的一個監(jiān)聽事件。msg.data
websocket還定義了一個readyState屬性,這個屬性可以返回websocket所處的狀態(tài):
- 1、CONNECTING(0) websocket正嘗試與服務器建立連接
- 2、OPEN(1) websocket與服務器已經(jīng)建立連接
- 3、CLOSING(2) websocket正在關閉與服務器的連接
- 4、CLOSED(3) websocket已經(jīng)關閉了與服務器的連接
websocket的url開頭是ws,如果需要ssl加密可以使用wss,當我們調用websocket的構造方法構建一個websocket對象(new WebSocket(url))的之后,就可以進行即時通信了。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>WebSocket 客戶端</title>
</head>
<body>
<div>
<input type="button" id="btnConnection" value="連接" />
<input type="button" id="btnClose" value="關閉" />
<input type="button" id="btnSend" value="發(fā)送" />
</div>
<script src="js/jquery-1.11.1.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var socket;
if(typeof(WebSocket) == "undefined") {
alert("您的瀏覽器不支持WebSocket");
return;
}
$("#btnConnection").click(function() {
//實現(xiàn)化WebSocket對象,指定要連接的服務器地址與端口
socket = new WebSocket("ws://192.168.1.2:8888");
//打開事件
socket.onopen = function() {
alert("Socket 已打開");
//socket.send("這是來自客戶端的消息" + location.href + new Date());
};
//獲得消息事件
socket.onmessage = function(msg) {
alert(msg.data);
};
//關閉事件
socket.onclose = function() {
alert("Socket已關閉");
};
//發(fā)生了錯誤事件
socket.onerror = function() {
alert("發(fā)生了錯誤");
}
});
//發(fā)送消息
$("#btnSend").click(function() {
socket.send("這是來自客戶端的消息" + location.href + new Date());
});
//關閉
$("#btnClose").click(function() {
socket.close();
});
</script>
</body>
</html>
四、WebSocket服務器端
JSR356定義了WebSocket的規(guī)范,Tomcat7中實現(xiàn)了該標準。JSR356 的 WebSocket 規(guī)范使用 javax.websocket.*的 API,可以將一個普通 Java 對象(POJO)使用 @ServerEndpoint 注釋作為 WebSocket 服務器的端點。
@ServerEndpoint("/push")
public class EchoEndpoint {
@OnOpen
public void onOpen(Session session) throws IOException {
//以下代碼省略...
}
@OnMessage
public String onMessage(String message) {
//以下代碼省略...
}
@Message(maxMessageSize=6)
public void receiveMessage(String s) {
//以下代碼省略...
}
@OnError
public void onError(Throwable t) {
//以下代碼省略...
}
@OnClose
public void onClose(Session session, CloseReason reason) {
//以下代碼省略...
}
}
上面簡潔代碼即建立了一個WebSocket的服務端,@ServerEndpoint("/push")的annotation注釋端點表示將WebSocket服務端運行在ws://[Server端IP或域名]:[Server端口]/項目/push的訪問端點,客戶端瀏覽器已經(jīng)可以對WebSocket客戶端API發(fā)起HTTP長連接了。
使用ServerEndpoint注釋的類必須有一個公共的無參數(shù)構造函數(shù),@onMessage注解的Java方法用于接收傳入的WebSocket信息,這個信息可以是文本格式,也可以是二進制格式。
OnOpen在這個端點一個新的連接建立時被調用。參數(shù)提供了連接的另一端的更多細節(jié)。Session表明兩個WebSocket端點對話連接的另一端,可以理解為類似HTTPSession的概念。
OnClose在連接被終止時調用。參數(shù)closeReason可封裝更多細節(jié),如為什么一個WebSocket連接關閉。
更高級的定制如@Message注釋,MaxMessageSize屬性可以被用來定義消息字節(jié)最大限制,在示例程序中,如果超過6個字節(jié)的信息被接收,就報告錯誤和連接關閉。
package action;
import javax.websocket.CloseReason;
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;
//ws://127.0.0.1:8087/Demo1/ws/張三
@ServerEndpoint("/ws/{user}")
public class WSServer {
private String currentUser;
//連接打開時執(zhí)行
@OnOpen
public void onOpen(@PathParam("user") String user, Session session) {
currentUser = user;
System.out.println("Connected ... " + session.getId());
}
//收到消息時執(zhí)行
@OnMessage
public String onMessage(String message, Session session) {
System.out.println(currentUser + ":" + message);
return currentUser + ":" + message;
}
//連接關閉時執(zhí)行
@OnClose
public void onClose(Session session, CloseReason closeReason) {
System.out.println(String.format("Session %s closed because of %s", session.getId(), closeReason));
}
//連接錯誤時執(zhí)行
@OnError
public void onError(Throwable t) {
t.printStackTrace();
}
}
url中的字符張三是的路徑參數(shù),響應請求的方法將自動映射。
五、測試運行


六、小結與消息推送框架
Socket在應用程序間通信被廣泛使用,如果需要兼容低版本的瀏覽器,建議使用反向ajax或長鏈接實現(xiàn);如果純移動端或不需考慮非現(xiàn)代瀏覽器則可以直接使用websocket。Flash實現(xiàn)推送消息的方法不建議使用,因為依賴插件且手機端支持不好。關于反向ajax也有一些封裝好的插件如“Pushlet”
6.1、開源Java消息推送框架 Pushlet
Pushlet 是一個開源的 Comet 框架,Pushlet 使用了觀察者模型:客戶端發(fā)送請求,訂閱感興趣的事件;服務器端為每個客戶端分配一個會話 ID 作為標記,事件源會把新產(chǎn)生的事件以多播的方式發(fā)送到訂閱者的事件隊列里。
源碼地址:https://github.com/wjw465150/Pushlet
Pushlet是一種comet實現(xiàn):在Servlet機制下,數(shù)據(jù)從server端的Java對象直接推送(push)到(動態(tài))HTML頁面,而無需任何Javaapplet或者插件的幫助。它使server端可以周期性地更新client的web頁面,這與傳統(tǒng)的request/response方式相悖。瀏覽器client為兼容JavaScript1.4版本以上的瀏覽器(如InternetExplorer、FireFox),并使用JavaScript/DynamicHTML特性。而底層實現(xiàn)使用一個servlet通過Http連接到JavaScript所在的瀏覽器,并將數(shù)據(jù)推送到后者。
6.2、開源DotNet消息推送框架SignalR
SignalR是一個ASP .NET下的類庫,可以在ASP .NET的Web項目中實現(xiàn)實時通信。在Web網(wǎng)頁與服務器端間建立Socket連接,當WebSockets可用時(即瀏覽器支持Html5)SignalR使用WebSockets,當不支持時SignalR將使用長輪詢來保證達到相同效果。
官網(wǎng):http://signalr.net/
源碼:https://github.com/SignalR/SignalR

七、代碼下載
7.1、Java實現(xiàn)的服務器端代碼與客戶端代碼下載
7.2、DotNet服務器端手動連接實現(xiàn)代碼下載
7.3、DotNet下使用SuperWebSocket三方庫實現(xiàn)代碼下載
點擊下載DotNet下使用SuperWebSocket三方庫實現(xiàn)代碼
到此這篇關于WebSocket簡介與消息推送的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Spring?Boot使用HMAC-SHA256對訪問密鑰加解密
本文主要介紹了使用HMAC-SHA256算法進行客戶端和服務端之間的簽名驗簽,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-12-12
基于logback實現(xiàn)純java版本的SDK組件
這篇文章主要介紹了基于logback實現(xiàn)純java版本的SDK組件,在項目開發(fā)過程中通常會使用logback作為日志記錄的依賴工具,使用方式是引入logback相關jar包,然后配置logback.xml配置文件的方式來實現(xiàn),需要的朋友可以參考下2023-11-11
SpringCloud Feign Jackson自定義配置方式
這篇文章主要介紹了SpringCloud Feign Jackson自定義配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot整合kaptcha驗證碼過程(復制粘貼即可用)

