WebSocket實時異步通信


WebSocket實時異步通信

【一】WebSocket簡介

  WebSocket是HTML5推出一個協議規范,用來B/S模式中服務器端和客戶端之間進行實時異步通信。

  眾所周知,傳統的HTTP協議中,服務器端和客戶端通信只能是在客戶端發送一個請求之后,服務器端才能對其響應,也就是說服務器端是不能夠主動向客戶端發起數據的。

  當在服務器端和客戶端之間需要頻繁地實時通信時,傳統HTTP協議只能通過Ajax輪詢的方式,即客戶端每隔一段時間請求一次服務器來獲得更新,這樣做的對服務器的性能要求特別高,而且占用很多無用的帶寬、流量。

 

 

圖一 傳統HTTP請求會話

圖二 WebSocket請求會話

  WebSocket在實時通信方面很好的彌補了傳統HTTP協議的不足。它是一個建立在HTTP協議之上的協議,通過HTTP建立了WebSocket連接之后,服務器端和客戶端就可以隨時通信了。

 

【二】WebSocket的使用

服務器端

  Tomcat7.0.5版本及以后的版本之中已經內嵌了支持WebSocket標准協議的jar包websocket-api.jar;在服務器端開發中通過@ServerEndpoint注解表明WebSocket服務端運行在 ws://[Server端IP或域名]:[Server端口]/project-name/注解參數值 路徑指定的位置,客戶端在創建WebSocket對象的時候,通過該路徑指定服務器響應的WebSocket。

  @OnOpen@OnClose、@OnError注解WebSocket方法分別響應建立連接、關閉連接和出錯時候的回調函數,@OnMessage注解的方法響應收到客戶端發送數據的回調函數。Session相當於客戶端,可以向客戶端發送數據。

  WebSocket類處理客戶端的所有請求,然后根據不同頁面的請求調用不同的類對象進行處理。

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.websocket.Session;
import org.apache.log4j.Logger;
import net.sf.json.JSONObject;

@ServerEndpoint("/websocket") public class WebSocket { public static Logger log = Logger.getLogger(WebSocket.class); private Statement stmt = null; private Connection conn = null; private Timer timer; @OnOpen public void onOpen(Session s) { log.info("client connected"); timer = new Timer(); //connect database try { ResourceBundle config = ResourceBundle.getBundle("config"); String driver = config.getString("jdbc.driver"); String url = config.getString("jdbc.cfg.url"); String username = config.getString("jdbc.cfg.username"); String password = config.getString("jdbc.cfg.password"); Class.forName(driver); conn = DriverManager.getConnection(url, username, password); stmt = conn.createStatement(); log.info("connect database successful"); }catch (ClassNotFoundException e) { e.printStackTrace(); }catch (SQLException e) { e.printStackTrace(); } } @OnMessage public void onMessage(final String message, Session s) throws IOException, InterruptedException{ log.info("message="+message); final JSONObject json = JSONObject.fromString(message); if(json.getInt("pageIndex") == 2){ //熱門配置頁不循環推送 HotConfig hotConfig = new HotConfig(s, stmt); hotConfig.sendWebSocket(json); }else if(json.getInt("pageIndex") == 3){ final TrafficLog trafficLog = new TrafficLog(s, stmt); int isRealTimeSearch = json.getInt("isRealTimeSearch"); if(isRealTimeSearch == 1){ timer.schedule(new TimerTask() { //每隔5分鍾執行一次 @Override public void run() { trafficLog.sendWebSocket(json); } }, 0, 300000); }else{ //只執行一次 timer.schedule(new TimerTask() { @Override public void run() { trafficLog.sendWebSocket(json); } }, 0); } }else if(json.getInt("pageIndex") == 4){ final RuleLog ruleLog = new RuleLog(s, stmt); int isRealTimeSearch = json.getInt("isRealTimeSearch"); if(isRealTimeSearch == 1){ timer.schedule(new TimerTask() { //每隔5分鍾執行一次 @Override public void run() { ruleLog.sendWebSocket(json); } }, 0, 300000); }else{ //只執行一次 timer.schedule(new TimerTask() { @Override public void run() { ruleLog.sendWebSocket(json); } }, 0); } }else{ //isp頁面的請求 final ISPLog ispLog = new ISPLog(s, stmt); int isRealTimeSearch = json.getInt("isRealTimeSearch"); if(isRealTimeSearch == 1){ timer.schedule(new TimerTask() { //每隔5分鍾執行一次 @Override public void run() { ispLog.sendWebSocket(json); } }, 0, 300000); }else{ //只執行一次 timer.schedule(new TimerTask() { @Override public void run() { ispLog.sendWebSocket(json); } }, 0); } } } @OnClose public void onClose(Session s) { log.info("Client closed"); try { timer.cancel(); if (stmt != null) { stmt.close(); stmt = null; } if (conn != null) { conn.close(); conn = null; } } catch (SQLException e) { e.printStackTrace(); } } @OnError public void onError(Throwable e) { log.error("WebSocket Error"); e.printStackTrace(); } }


  響應具體某個頁面的請求

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.websocket.Session;
import org.apache.log4j.Logger;
import net.sf.json.JSONObject;

public class HotConfig {
    
    private Session session;
    private Statement stmt = null;
    private ResultSet rs = null;
    private static Logger log = Logger.getLogger(HotConfig.class);
    
    public HotConfig(Session s, Statement stmt){
        this.session = s;
        this.stmt = stmt;
    }
    
    public void sendWebSocket(final JSONObject json){
        String srcIp = json.getString("srcIp");
        String startTime = json.getString("startTime");
        String endTime = json.getString("endTime");
        Map<String, ArrayList<Long>> params = new HashMap<String, ArrayList<Long>>();
        ArrayList<Long> pzID = new ArrayList<Long>();             //different chart lines name
        ArrayList<Long> statCount = new ArrayList<Long>();        //chart x axis
        ArrayList<Long> pzIDReverse = new ArrayList<Long>();            //different chart lines name
        ArrayList<Long> statCountReverse = new ArrayList<Long>();        //chart x axis
        try {
            String srcIpCriteria = "";                        //拼接源IP SQL條件
            if(srcIp.length() > 0) {
                srcIpCriteria = " where CLIENT_IP='"+srcIp+"' ";
            }
            String startTimeCriteria = "";                    //拼接源IP SQL條件
            if(startTime.length() > 0) {
                if(srcIpCriteria.equals(""))
                    startTimeCriteria = " where STAT_TIME >= to_date('"+startTime +"','yyyy-mm-dd hh24:mi')";
                else
                    startTimeCriteria = " and STAT_TIME >= to_date('"+startTime +"','yyyy-mm-dd hh24:mi')";
            }
            String endTimeCriteria = "";                      //拼接源IP SQL條件
            if(endTime.length() > 0) {
                if(srcIpCriteria.equals("") && startTimeCriteria.equals(""))
                    endTimeCriteria = " where STAT_TIME < to_date('" +endTime+"','yyyy-mm-dd hh24:mi') ";
                else
                    endTimeCriteria = " and STAT_TIME < to_date('" +endTime+"','yyyy-mm-dd hh24:mi') ";
            }
            String sql = "select * from (select PZ_ID, sum(STAT_COUNT) as sumCount from RULE_HOT_CONFIG_INFO" 
                    + srcIpCriteria + startTimeCriteria + endTimeCriteria 
                    + " group by PZ_ID order by sumCount desc) where rownum <= 50";                
            log.info("sql="+sql+"execute success");
            rs = stmt.executeQuery(sql);
            while(rs.next()){ 
                   pzID.add(rs.getLong(1));
                   statCount.add(rs.getLong(2));
             }
            for(int i = pzID.size() - 1; i >= 0; i--){
                pzIDReverse.add(pzID.get(i));
                statCountReverse.add(statCount.get(i));
            }
            params.put("pzID", pzIDReverse);
            params.put("statCount",statCountReverse);         
            session.getBasicRemote().sendText(JSONObject.fromBean(params).toString());
            log.info("主動發給前端的數據="+JSONObject.fromBean(params).toString());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
}

 

客戶端

  目前主流的瀏覽器Firefox、Chrome已經支持WebSocket協議,這意味只不需要引用額外的js庫就可以直接使用WebSocket了。

<script type="text/javascript">   
     //創建WebSocket對象,用於一開始建立連接,之后就不要再建立連接了 var webSocket = new WebSocket('ws://localhost:8080/websocket/websocket'); webSocket.onopen = function(event) { }; webSocket.onmessage = function(event) {
        //接收來自服務器的數據,這里客戶端沒有發送任何請求,任何時間接收到數據都可以異步調用 onMessage(event);
        var  m = JSON.parse(event.data);
        alert(m); }; webSocket.onerror
= function(event) { }; function onMessage(event) { } </script>

 


 推薦學習文章:http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/

        http://www.tuicool.com/articles/7zyMvy6

        http://www.alixixi.com/web/a/2014032492868.shtml


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM