基於netty-socketio的web推送服務

在WEB項目中,服務器向WEB頁面推送消息是一種常見的業務需求。PC端的推送技術可使用socket創建一個長鏈接來實現。傳統的web服務都是客戶端發出請求,服務端給出響應。可是如今直觀的要求是容許特定時間內在沒有客戶端發起請求的狀況下服務端主動推送消息到客戶端。最近的預警系統中,須要服務端向預警系統推送商品行情和K線相關的數據,因此對經常使用的WEB端推送方式進行調研。常見的手段主要包括如下幾種:
  • 輪詢(俗稱「拉」,polling):Ajax 隔一段時間向服務器發送請求,詢問數據是否發生改變,從而進行增量式的更新。輪詢的時間間隔成了一個問題:間隔過短,會有大量的請求發送到服務器,會對服務器負載形成影響;間隔太長業務數據的實時性得不到保證。連。使用輪詢的優勢是實現邏輯簡單,缺點是無效請求的數量多,在用戶量較大的狀況下,服務器負載較高。所以輪詢的方式一般在併發數量較少、而且對消息實時性要求不高的狀況下使用。
  • 長輪詢技術(long-polling):客戶端向服務器發送Ajax請求,服務器接到請求後hold住鏈接,直到有新消息或超時(設置)才返回響應信息並關閉鏈接,客戶端處理完響應信息後再向服務器發送新的請求。長輪詢技術的優勢是消息實時性高,無消息的狀況下不會進行頻繁的請求;缺點是服務端維持和客戶端的鏈接會消耗掉一部分資源。
  • 插件提供socket方式:好比利用Flash XMLSocket,Java Applet套接口,Activex包裝的socket。優勢是對原生socket的支持,和PC端和移動端的實現方式類似;缺點是瀏覽器須要安裝相應的插件。
  • WebSocket:是HTML5開始提供的一種瀏覽器與服務器間進行全雙工通信的網絡技術。其優勢是更好的節省服務器資源和帶寬並達到實時通信;缺點是目前還未普及,瀏覽器支持很差;

    綜上,考慮到瀏覽器兼容性和性能問題,採用長輪詢(long-polling)是一種比較好的方式。netty-socketio是一個開源的Socket.io服務器端的一個java的實現, 它基於Netty框架。 項目地址爲: https://github.com/mrniko/net...javascript

如下基於Netty-socketIO實現一個簡單的聊天室功能,首先引入依賴:html

<dependency>
 <groupId>com.corundumstudio.socketio</groupId>
 <artifactId>netty-socketio</artifactId>
 <version>1.7.3</version>
</dependency>

定義Listen,用戶監聽Oncennect、disconnect和OnMSG事件:java

@Service("eventListenner")
public class EventListenner {
    @Resource(name = "clientCache")
    private SocketIOClientCache clientCache;
 
    @Resource(name = "socketIOResponse")
    private SocketIOResponse socketIOResponse;
     
    @OnConnect
    public void onConnect(SocketIOClient client) {
       System.out.println("創建鏈接");
    }
 
    @OnEvent("OnMSG")
    public void onSync(SocketIOClient client, MsgBean bean) {
        System.out.printf("收到消息-from: %s to:%s\n", bean.getFrom(), bean.getTo());
        clientCache.addClient(client, bean);
        SocketIOClient ioClients = clientCache.getClient(bean.getTo());
        System.out.println("clientCache");
        if (ioClients == null) {
            System.out.println("你發送消息的用戶不在線");
            return;
        }
        socketIOResponse.sendEvent(ioClients,bean);
    }
 
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        System.out.println("關閉鏈接");
    }
}

定義消息發送類:jquery

@Service("socketIOResponse")
public class SocketIOResponse {
    public void sendEvent(SocketIOClient client, MsgBean bean) {
        System.out.println("推送消息");
        client.sendEvent("OnMSG", bean);
    }
}

定義Cache用於保存全部和Web端的鏈接:git

@Service("clientCache")
public class SocketIOClientCache {
    //String:EventType類型
    private Map<String,SocketIOClient> clients=new ConcurrentHashMap<String,SocketIOClient>();
 
    //用戶發送消息添加
    public void addClient(SocketIOClient client,MsgBean msgBean){
        clients.put(msgBean.getFrom(),client);
    }
 
    //用戶退出時移除
    public void remove(MsgBean msgBean) {
        clients.remove(msgBean.getFrom());
    }
     
    //獲取全部
    public  SocketIOClient getClient(String to) {
        return clients.get(to);
    }
}

定義Server:github

//繼承InitializingBean,使Spring加載完配置文件,自動運行以下方法
@Service("chatServer")
public class ChatServer implements InitializingBean{
    @Resource
    private EventListenner eventListenner;
    public void afterPropertiesSet() throws Exception {
        Configuration config = new Configuration();
        config.setPort(9098);
         
        SocketConfig socketConfig = new SocketConfig();
        socketConfig.setReuseAddress(true);
        socketConfig.setTcpNoDelay(true);
        socketConfig.setSoLinger(0);
        config.setSocketConfig(socketConfig);
        config.setHostname("localhost");
         
        SocketIOServer server = new SocketIOServer(config);
        server.addListeners(eventListenner);
        server.start();
        System.out.println("啓動正常");
    }
}

定義MSGbean:web

public class MsgBean { 
    private String from;
    private String to;
    private String content;
     
    public String getFrom() {
        return from;
    }
    public void setFrom(String from) {
        this.from = from;
    }
    public String getTo() {
        return to;
    }
    public void setTo(String to) {
        this.to = to;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
     
    @Override
    public String toString() {
        return "MsgBean [from=" + from + ", to=" + to + ", content=" + content + "]";
    }
}

定義Main:瀏覽器

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:/applicationContext-push.xml");
        context.start();
        context.getBean("chatServer");
    }
}

HTML頁面:服務器

<!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.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="from" class="input-xlarge" type="text" placeholder="from. . . " />
        <input id="to" class="input-xlarge" type="text" placeholder="to. . . " />
        <input id="content" class="input-xlarge" type="text" placeholder="content. . . " />
        <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:9098');
    socket.on('connect',function() {
        output('<span class="connect-msg">Client has connected to the server!</span>');
    });
     
    socket.on('OnMSG', function(data) {
        output('<span class="username-msg">' + data.content + ' : </span>');
    });
     
    socket.on('disconnect',function() {
        output('<span class="disconnect-msg">The client has disconnected! </span>');
    });
     
    function sendDisconnect() {
        socket.disconnect();
    }
     
    function sendMessage() {
        var from = $("#from").val();
        var to = $("#to").val();
        var content = $('#content').val();
        socket.emit('OnMSG', {
            from : from,
            to : to,
            content : content
        });
    }
     
    function output(message) {
        var currentTime = "<span class='time' >" + new Date() + "</span>";
        var element = $("<div>" + currentTime + " " + message + "</div>");
        $('#console').prepend(element);
    }
</script>
</html>

相關文章:
基於netty-socketio的web推送服務
gitee源代碼Socket.io 和 netty-socketio使用網絡

相關文章
相關標籤/搜索