WebSocket與消息推送

WebSocket與消息推送

 

B/S結構的軟件項目中有時客戶端須要實時的得到服務器消息,但默認HTTP協議只支持請求響應模式,這樣作能夠簡化Web服務器,減小服務器的負擔,加快響應速度,由於服務器不須要與客戶端長時間創建一個通訊連接,但不容易直接完成實時的消息推送功能,如聊天室、後臺信息提示、實時更新數據等功能,但經過polling、Long polling、長鏈接、Flash Socket以及HTML5中定義的WebSocket能完成該功能須要。html

1、Socket簡介

Socket又稱"套接字",應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求。Socket的英文原義是「孔」或「插座」,做爲UNIX的進程通訊機制。Socket能夠實現應用程序間網絡通訊。java

Socket可使用TCP/IP協議或UDP協議。jquery

TCP/IP協議git

TCP/IP協議是目前應用最爲普遍的協議,是構成Internet國際互聯網協議的最爲基礎的協議,由TCP和IP協議組成:
TCP協議:面向鏈接的、可靠的、基於字節流的傳輸層通訊協議,負責數據的可靠性傳輸的問題。github

IP協議:用於報文交換網絡的一種面向數據的協議,主要負責給每臺網絡設備一個網絡地址,保證數據傳輸到正確的目的地。web

UDP協議ajax

UDP特色:無鏈接、不可靠、基於報文的傳輸層協議,優勢是發送後不用管,速度比TCP快。後端

2、WebSocket簡介與消息推送

B/S架構的系統多使用HTTP協議,HTTP協議的特色:瀏覽器

1 無狀態協議
2 用於經過 Internet 發送請求消息和響應消息
3 使用端口接收和發送消息,默認爲80端口
底層通訊仍是使用Socket完成。

HTTP協議決定了服務器與客戶端之間的鏈接方式,沒法直接實現消息推送(F5已壞),一些變相的解決辦法:

雙向通訊與消息推送

輪詢:客戶端定時向服務器發送Ajax請求,服務器接到請求後立刻返回響應信息並關閉鏈接。  優勢:後端程序編寫比較容易。  缺點:請求中有大半是無用,浪費帶寬和服務器資源。  實例:適於小型應用。

長輪詢:客戶端向服務器發送Ajax請求,服務器接到請求後hold住鏈接,直到有新消息才返回響應信息並關閉鏈接,客戶端處理完響應信息後再向服務器發送新的請求。  優勢:在無消息的狀況下不會頻繁的請求,耗費資小。  缺點:服務器hold鏈接會消耗資源,返回數據順序無保證,難於管理維護。 Comet異步的ashx, 實例:WebQQ、Hi網頁版、Facebook IM。

長鏈接:在頁面裏嵌入一個隱蔵iframe,將這個隱蔵iframe的src屬性設爲對一個長鏈接的請求或是採用xhr請求,服務器端就能源源不斷地往客戶端輸入數據。  優勢:消息即時到達,不發無用請求;管理起來也相對便。  缺點:服務器維護一個長鏈接會增長開銷。  實例:Gmail聊天

Flash Socket:在頁面中內嵌入一個使用了Socket類的 Flash 程序JavaScript經過調用此Flash程序提供的Socket接口與服務器端的Socket接口進行通訊,JavaScript在收到服務器端傳送的信息後控制頁面的顯示。  優勢:實現真正的即時通訊,而不是僞即時。  缺點:客戶端必須安裝Flash插件;非HTTP協議,沒法自動穿越防火牆。  實例:網絡互動遊戲。

Websocket:
WebSocket是HTML5開始提供的一種瀏覽器與服務器間進行全雙工通信的網絡技術。依靠這種技術能夠實現客戶端和服務器端的長鏈接,雙向實時通訊。
特色:
事件驅動
異步
使用ws或者wss協議的客戶端socket

可以實現真正意義上的推送功能

缺點:

少部分瀏覽器不支持,瀏覽器支持的程度與方式有區別。

3、WebSocket客戶端

websocket容許經過JavaScript創建與遠程服務器的鏈接,從而實現客戶端與服務器間雙向的通訊。在websocket中有兩個方法:  
    一、send() 向遠程服務器發送數據
    二、close() 關閉該websocket連接
  websocket同時還定義了幾個監聽函數    
    一、onopen 當網絡鏈接創建時觸發該事件
    二、onerror 當網絡發生錯誤時觸發該事件
    三、onclose 當websocket被關閉時觸發該事件
    四、onmessage 當websocket接收到服務器發來的消息的時觸發的事件,也是通訊中最重要的一個監聽事件。msg.data
  websocket還定義了一個readyState屬性,這個屬性能夠返回websocket所處的狀態:
    一、CONNECTING(0) websocket正嘗試與服務器創建鏈接
    二、OPEN(1) websocket與服務器已經創建鏈接
    三、CLOSING(2) websocket正在關閉與服務器的鏈接
    四、CLOSED(3) websocket已經關閉了與服務器的鏈接

  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="發送" />
        </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() {
                //實現化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已關閉");
                };
                //發生了錯誤事件
                socket.onerror = function() {
                    alert("發生了錯誤");
                }
            });
            
            //發送消息
            $("#btnSend").click(function() {
                socket.send("這是來自客戶端的消息" + location.href + new Date());
            });
            
            //關閉
            $("#btnClose").click(function() {
                socket.close();
            });
        </script>
    </body>

</html>
複製代碼

4、WebSocket服務器端

JSR356定義了WebSocket的規範,Tomcat7中實現了該標準。JSR356 的 WebSocket 規範使用 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的訪問端點,客戶端瀏覽器已經能夠對WebSocket客戶端API發起HTTP長鏈接了。
使用ServerEndpoint註釋的類必須有一個公共的無參數構造函數,@onMessage註解的Java方法用於接收傳入的WebSocket信息,這個信息能夠是文本格式,也能夠是二進制格式。
OnOpen在這個端點一個新的鏈接創建時被調用。參數提供了鏈接的另外一端的更多細節。Session代表兩個WebSocket端點對話鏈接的另外一端,能夠理解爲相似HTTPSession的概念。
OnClose在鏈接被終止時調用。參數closeReason可封裝更多細節,如爲何一個WebSocket鏈接關閉。
更高級的定製如@Message註釋,MaxMessageSize屬性能夠被用來定義消息字節最大限制,在示例程序中,若是超過6個字節的信息被接收,就報告錯誤和鏈接關閉。

複製代碼
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;
    
    //鏈接打開時執行
    @OnOpen
    public void onOpen(@PathParam("user") String user, Session session) {
        currentUser = user;
        System.out.println("Connected ... " + session.getId());
    }

    //收到消息時執行
    @OnMessage
    public String onMessage(String message, Session session) {
        System.out.println(currentUser + ":" + message);
        return currentUser + ":" + message;
    }

    //鏈接關閉時執行
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        System.out.println(String.format("Session %s closed because of %s", session.getId(), closeReason));
    }

    //鏈接錯誤時執行
    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }
}
複製代碼

url中的字符張三是的路徑參數,響應請求的方法將自動映射。

5、測試運行

6、小結與消息推送框架

 Socket在應用程序間通訊被普遍使用,若是須要兼容低版本的瀏覽器,建議使用反向ajax或長連接實現;若是純移動端或不需考慮非現代瀏覽器則能夠直接使用websocket。Flash實現推送消息的方法不建議使用,由於依賴插件且手機端支持很差。關於反向ajax也有一些封裝好的插件如「Pushlet」

6.一、開源Java消息推送框架 Pushlet

Pushlet 是一個開源的 Comet 框架,Pushlet 使用了觀察者模型:客戶端發送請求,訂閱感興趣的事件;服務器端爲每一個客戶端分配一個會話 ID 做爲標記,事件源會把新產生的事件以多播的方式發送到訂閱者的事件隊列裏。

源碼地址:https://github.com/wjw465150/Pushlet

Pushlet是一種comet實現:在Servlet機制下,數據從server端的Java對象直接推送(push)到(動態)HTML頁面,而無需任何Javaapplet或者插件的幫助。它使server端能夠週期性地更新client的web頁面,這與傳統的request/response方式相悖。瀏覽器client爲兼容JavaScript1.4版本以上的瀏覽器(如InternetExplorer、FireFox),並使用JavaScript/DynamicHTML特性。而底層實現使用一個servlet經過Http鏈接到JavaScript所在的瀏覽器,並將數據推送到後者。

6.二、開源DotNet消息推送框架SignalR

SignalR是一個ASP .NET下的類庫,能夠在ASP .NET的Web項目中實現實時通訊。在Web網頁與服務器端間創建Socket鏈接,當WebSockets可用時(即瀏覽器支持Html5)SignalR使用WebSockets,當不支持時SignalR將使用長輪詢來保證達到相同效果。

官網:http://signalr.net/

源碼:https://github.com/SignalR/SignalR

 

7、代碼下載

7.一、Java實現的服務器端代碼與客戶端代碼下載

點擊下載服務器端代碼

點擊下載客戶端代碼

7.二、DotNet服務器端手動鏈接實現代碼下載

點擊下載DotNet服務器端手動鏈接實現代碼

7.三、DotNet下使用SuperWebSocket三方庫實現代碼下載

點擊下載DotNet下使用SuperWebSocket三方庫實現代碼

 

原文連接:https://www.cnblogs.com/best/archive/2016/09/12/5695570.html

相關文章
相關標籤/搜索