基於netty-socketio的web推送服務

實時消息的推送,PC端的推送技術可使用socket創建一個長鏈接來實現。傳統的web服務都是客戶端發出請求,服務端給出響應。可是如今直觀的要求是容許特定時間內在沒有客戶端發起請求的狀況下服務端主動推送消息到客戶端。javascript

有哪些能夠實現web消息推送的技術:html

  • 不斷地輪詢(俗稱「拉」,polling)是獲取實時消息的一個手段:Ajax 隔一段時間(一般使用 JavaScript 的 setTimeout 函數)就去服務器查詢是否有改變,從而進行增量式的更新。可是間隔多長時間去查詢成了問題,由於性能和即時性形成了嚴重的反比關係。間隔過短,接二連三的請求會沖垮服務器,間隔太長,務器上的新數據就須要越多的時間才能到達客戶機。java

    • 優勢:服務端邏輯簡單;jquery

    • 缺點:其中大多數請求多是無效請求,在大量用戶輪詢很頻繁的狀況下對服務器的壓力很大;git

    • 應用:併發用戶量少,並且要求消息的實時性不高,通常不多采用;github

  • 長輪詢技術(long-polling):客戶端向服務器發送Ajax請求,服務器接到請求後hold住鏈接,直到有新消息或超時(設置)才返回響應信息並關閉鏈接,客戶端處理完響應信息後再向服務器發送新的請求。web

    • 優勢:實時性高,無消息的狀況下不會進行頻繁的請求;瀏覽器

    • 缺點:服務器維持着鏈接期間會消耗資源;服務器

  • 基於Iframe及htmlfile的流(streaming)方式:iframe流方式是在頁面中插入一個隱藏的iframe,利用其src屬性在服務器和客戶端之間建立一條長連接,服務器向iframe傳輸數據(一般是HTML,內有負責插入信息的javascript),來實時更新頁面。網絡

    • 優勢:消息可以實時到達;

    • 缺點:服務器維持着長鏈接期會消耗資源;

  • 插件提供socket方式:好比利用Flash XMLSocket,Java Applet套接口,Activex包裝的socket。

    • 優勢:原生socket的支持,和PC端和移動端的實現方式類似;

    • 缺點:瀏覽器端須要裝相應的插件;

  • WebSocket:是HTML5開始提供的一種瀏覽器與服務器間進行全雙工通信的網絡技術。

    • 優勢:更好的節省服務器資源和帶寬並達到實時通信;

    • 缺點:目前還未普及,瀏覽器支持很差;

綜上,考慮到瀏覽器兼容性和性能問題,採用長輪詢(long-polling)是一種比較好的方式。

netty-socketio是一個開源的Socket.io服務器端的一個java的實現, 它基於Netty框架。 項目地址爲: https://github.com/mrniko/netty-socketio

如下是一個來自netty-socketio的推送示例,web聊天系統。

服務器端push server:

消息實體:

package com.nettysocketio.test;

public class ChatObject {
    private String userName;
    private String message;

    public ChatObject() {
    }

    public ChatObject(String userName, String message) {
        super();
        this.userName = userName;
        this.message = message;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
View Code

監聽事件:

package com.nettysocketio.test;

import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.DataListener;

public class CharteventListener implements DataListener<ChatObject> {

    SocketIOServer server;

    public void setServer(SocketIOServer server) {
        this.server = server;
    }

    public void onData(SocketIOClient client, ChatObject data,
            AckRequest ackSender) throws Exception {
        // chatevent爲 事件的名稱, data爲發送的內容
        this.server.getBroadcastOperations().sendEvent("chatevent", data);
    }
}

推送服務:

package com.nettysocketio.test;

import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOServer;

public class App {
    public static void main(String[] args) throws InterruptedException
    {
        Configuration config = new Configuration();
        config.setHostname("localhost");
        config.setPort(9092);

        SocketIOServer server = new SocketIOServer(config);
        CharteventListener listner = new CharteventListener();
        listner. setServer(server);
        // chatevent爲事件名稱
        server.addEventListener("chatevent", ChatObject.class, listner);
        //啓動服務
        server.start();
        Thread.sleep(Integer.MAX_VALUE) ;
        server.stop();
    }
}

瀏覽器端Client:

客戶端使用的是socket.io-client,項目地址爲:https://github.com/Automattic/socket.io-client

客戶端聊天代碼:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Socketio chat</title>
<script src="./jquery-1.7.2.min.js" type="text/javascript"></script>
<script type="text/javascript" src="./socket.io/socket.io.js"></script>
<style>
body {
    padding: 20px;
}
#console {
    height: 400px;
    overflow: auto;
}
.username-msg {
    color: orange;
}
.connect-msg {
    color: green;
}
.disconnect-msg {
    color: red;
}
.send-msg {
    color: #888
}
</style>
</head>
<body>
    <h1>Netty-socketio chat demo</h1>
    <br />
    <div id="console" class="well"></div>
    <form class="well form-inline" onsubmit="return false;">
        <input id="name" class="input-xlarge" type="text" placeholder="用戶名稱. . . " />
        <input id="msg" class="input-xlarge" type="text" placeholder="發送內容. . . " />
        <button type="button" onClick="sendMessage()" class="btn">Send</button>
        <button type="button" onClick="sendDisconnect()" class="btn">Disconnect</button>
    </form>
</body>
<script type="text/javascript">
    var socket = io.connect('http://localhost:9092');
    socket.on('connect',function() {
        output('<span class="connect-msg">Client has connected to the server!</span>');
    });
    
    socket.on('chatevent', function(data) {
        output('<span class="username-msg">' + data.userName + ' : </span>'
                + data.message);
    });
    
    socket.on('disconnect',function() {
        output('<span class="disconnect-msg">The client has disconnected! </span>');
    });
    
    function sendDisconnect() {
        socket.disconnect();
    }
    
    function sendMessage() {
        var userName = $("#name").val()
        var message = $('#msg').val();
        $('#msg').val('');
        socket.emit('chatevent', {
            userName : userName,
            message : message
        });
    }
    
    function output(message) {
        var currentTime = "<span class='time' >" + new Date() + "</span>";
        var element = $("<div>" + currentTime + " " + message + "</div>");
        $('#console').prepend(element);
    }
</script>
</html>

先運行push server,再打開chat html就能夠看到鏈接信息和服務器推送的聊天信息。

 

參考:

https://socket.io/

https://github.com/socketio/socket.io

https://github.com/mrniko/netty-socketio

https://github.com/mrniko/netty-socketio-demo

相關文章
相關標籤/搜索