天天看點

【反ajax】webSocket實作實時推送功能

額。前天就說有時間要研究下webSocket這種實時推技術。已經用Comet實作了一個結合redis釋出/訂閱功能的小功能,其實還是有點複雜度的。今天有時間,遂了解了下webSocket,發現也沒有想象中那麼難!

但我研究webSocket做東西還是饒了一大圈,有一種用spring+webSocket做的,略複雜(可能容錯性和健壯性更高?),最後卡在404連接配接上了,用的jar包是spring-websocket-4.2.x.jar及相關依賴jar包。鑒于參考網上的例子并沒實作,故作罷。

後來,用了JavaEE7 (jdk1.7+支援)和html5支援的webSocket,問題就顯得簡單多了。涉及jar包:websocket-api-1.x.jar

用戶端:

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>釋出訂閱測試</title>
	
	<script type="text/javascript">
		var socket = null;
		$(function() {
			var websocket;
//考慮各種浏覽器相容問題
            if ('WebSocket' in window) {
                websocket = new WebSocket("ws://localhost:8080/amp/socket/webSocketServer");
            } else if ('MozWebSocket' in window) {
                websocket = new MozWebSocket("ws://localhost:8080/amp/socket/webSocketServer");
            } else {
                websocket = new SockJS("http://localhost:8080/amp/sockjs/webSocketServer");
            }
//和服務端連接配接成功後的操作 send操作必須要有  服務端才會可能響應          
            websocket.onopen = function (evnt) {
            	var data = {appId:'hx', status:'s'};
            	websocket.send(JSON.stringify(data));//嘗試給服務端發送json參數,這也是項目中常見的的
            	$("#showMsg").append("連接配接成功!<br/>");
            };
//接收到服務端傳回的資料後回調
            websocket.onmessage = function (evnt) {
                $("#showMsg").append("(<font color='red'>"+evnt.data+"</font>)<br/>");
            };
//連接配接失敗回調
            websocket.onerror = function (evnt) {
            };
//服務端關閉引發
            websocket.onclose = function (evnt) {
            	$("#showMsg").append("連接配接關閉!<br/>");
            }
		});
	</script>
</head>
<body>
	<div id="showMsg" style="border: 1px solid; width: 500px; height: 400px; overflow: auto;"></div>
</body>
           

 服務端:

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import net.sf.json.JSONObject;

@ServerEndpoint("/socket/webSocketServer")
public class ScrollInfoHandler {
//接收到用戶端的請求
	@OnMessage
	  public void onMessage(String message, Session session)
	    throws IOException, InterruptedException {
	   
	    System.out.println("Received: " + message);
	    
	    Map<String, String> params = JSONObject.fromObject(message);
	    
	    // Send the first message to the client
	    session.getBasicRemote().sendText("return params after handled: " 
	    		+ params.get("appId").toUpperCase() + ", " + params.get("status").toUpperCase());
	   
	    // Send 3 messages to the client every 5 seconds
	    int sentMessages = 0;
//模拟推送資料
	    while(true){
	      Thread.sleep(2000);
	      session.getBasicRemote().
	        sendText("This is an intermediate server message. Count: "
	          + Math.random());
	    }
	   
	  }
//和用戶端連接配接成功後	   
	  @OnOpen
	  public void onOpen() {
	    System.out.println("Client connected");
	  }
//用戶端關閉後	 
	  @OnClose
	  public void onClose() {
	    System.out.println("Connection closed");
	  }
	
}
           

 如果想和redis釋出訂閱結合起來,很簡單:在服務端的onOpen函數裡啟動訂閱管道的線程,以及定時檢查隊列大小的線程,而在onMessage函數裡執行定時從隊列pop資料并send,在onClose裡面寫停止線程和情空隊列的邏輯 即可啦。

下面就來測一測效果!

啟動項目,打開這個用戶端頁面,先觀察控制台列印:

Client connected

Received: {"appId":"hx","status":"s"}

說明,服務端已經跟用戶端連通,并且收到傳遞過來的參數了。

觀察用戶端頁面,你會發現:(某一時刻)

【反ajax】webSocket實作實時推送功能

 用戶端是不斷重新整理着的,而且也收到了服務端處理參數後傳過來的資料了。

若關閉用戶端,服務端控制台會列印:Connection closed

若關閉服務端,用戶端會這樣:

【反ajax】webSocket實作實時推送功能

 說明,達到了響應服務端關閉後的效果。

以上,隻是一個很簡單的推送執行個體。要具體應用到實際項目中是需要不斷完善代碼以提高其健壯性的。但至少對我而言,服務端主動推送技術終于不再那麼神秘和困惑了,以後對實時性要求比較高的地方可以采納,終于突破ajax的方式了。

繼續閱讀