1. 程式人生 > >WEB即時通訊/訊息推送

WEB即時通訊/訊息推送

寫在前面

通常進行的Web開發都是由客戶端主動發起的請求,然後伺服器對請求做出響應並返回給客戶端。但是在很多情況下,你也許會希望由伺服器主動對客戶端傳送一些資料。

那麼,該如何實現這個需求,或者說該如何向網頁推送訊息呢?

一、推送方式

我們知道,HTTP/HTTPS協議是被設計基於“請求-相應”模型的,儘管HTTP/HTTPS可以在任何網際網路協議或網路上實現,但這裡我們只討論在Internet網上的全球資訊網中的情況。

由於在Internet中,HTTP協議在傳輸層使用的是TCP協議。由此可知,只要我們能保持TCP連線不隨一次“請求-響應”結束而結束,使得伺服器可以主動傳送資料,那麼我們就能夠實現向網頁的資料推送。事與願違,在2011年WebSocket

(詳見下文)出現之前我們對此是無能為力的。

不過,在那時雖然不能直接實現推送,但是還是有曲線救國路線的,基本上有4類這種間接方式。當然現在我們還有了1種直接方式-WebSocket ,接下來我來依次介紹下。

模擬推送

1. 輪詢(Polling)

AJAX 定時(可以使用JS的 setTimeout 函式)去伺服器查詢是否有新訊息,從而進行增量式的更新。這種方式間隔多長時間再查詢是個問題,因為效能和即時性是反比關係。間隔太短,海量的請求會拖垮伺服器,間隔太長,伺服器上的新資料就需要更長的時間才能到達客戶機。

  • 優點:服務端邏輯簡單;
  • 缺點:大多數請求是無效請求,在輪詢很頻繁的情況下對伺服器的壓力很大;

所以,除了一些簡單練習專案外,這種方式不能被用於生產。

Comet

2和3屬於:Comet (web技術),是廣大開發者想出來的比較可行的推送技術。

2. 長輪詢(Long-Polling)

客戶端向伺服器傳送AJAX請求,伺服器接到請求後hold住連線,直到有新訊息或超時(設定)才返回響應資訊並關閉連線,客戶端處理完響應資訊後再向伺服器傳送新的請求。

  • 優點:任意瀏覽器都可用;實時性好,無訊息的情況下不會進行頻繁的請求;
  • 缺點:連線建立銷燬操作還是比較頻繁,伺服器維持著連線比較消耗資源;

微信網頁版使用的就是這種方式,據我觀察:

  • 微信把25秒作為超時時間;
  • 用兩個請求來完成長輪詢,一個用於25秒超時獲取是否有新訊息,當有新訊息時會用另一個AJAX請求來獲取具體資料。

這種方式是可以被用於生產的,並且已經被實踐檢驗有比較高的可用性。

3. 基於iframe的方式

iframe 是很早就存在的一種 HTML 標記, 通過在 HTML 頁面裡嵌入一個隱蔵幀,然後將這個隱蔵幀的 src 屬性設為對一個長連線的請求,伺服器端就能源源不斷地往客戶端輸入資料。
這裡寫圖片描述

iframe 伺服器端並不返回直接顯示在頁面的資料,而是返回對客戶端 Javascript 函式的呼叫,如<script type="text/javascript">js_func("data from server")</script>。伺服器端將返回的資料作為客戶端 JavaScript 函式的引數傳遞;客戶端瀏覽器的 Javascript 引擎在收到伺服器返回的 JavaScript 呼叫時就會去執行程式碼。

每次資料傳送不會關閉連線,連線只會在通訊出現錯誤時,或是連線重建時關閉(一些防火牆常被設定為丟棄過長的連線, 伺服器端可以設定一個超時時間, 超時後通知客戶端重新建立連線,並關閉原來的連線)。

  • 優點:訊息能夠實時到達;
  • 缺點:使用 iframe 請求一個長連線有一個很明顯的不足之處:IE、Morzilla Firefox 下端的進度欄都會顯示載入沒有完成,而且 IE 上方的圖示會不停的轉動,表示載入正在進行;

Google公司在一些產品中使用了iframe流,如Google Talk。

侷限性方式

4. 外掛提供的Socket方式

利用Flash XMLSocket,Java Applet套介面,Activex包裝的socket。

  • 優點:原生socket的支援,和PC端和移動端的實現方式相似;
  • 缺點:瀏覽器端需要裝相應的外掛;

5. WebSocket

2011年,WebSocket被IETF定為標準RFC 6455,WebSocket API也被W3C定為標準。WebSocket 使得客戶端和伺服器之間的資料交換變得更加簡單,允許服務端主動向客戶端推送資料。在 WebSocket API 中,瀏覽器和伺服器只需要完成一次握手,兩者之間就直接可以建立永續性的連線,並進行雙向資料傳輸。

WebSocket自然是極好的,更多細節我在下一節詳細說明。

到這裡,我們已經對WEB上的訊息推送機制有了一個整體的瞭解。不過,僅僅只有了解對於我們來說顯然還不夠,由於我是Java程式設計師,接下來我將繼續介紹WebSocket,並且用Java做服務端來做一個例子。

二、WebSocket

WebSocket 是獨立的、建立在 TCP 上的協議。Websocket 通過 HTTP/1.1 協議的101狀態碼進行握手。為了建立Websocket連線,需要通過瀏覽器發出請求,之後伺服器進行迴應,這個過程通常稱為“握手”(handshaking)。

1. ws請求

一個典型的WebSocket請求如下:

GET wss://xxx.xxx.com/push/ HTTP/1.1
Host: xxx.xxx.com:port
Connection:Upgrade
Upgrade:websocket
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:rZGX8zZKTrdkhIJTCuW54Q==
Sec-WebSocket-Version:13

// Connection必須為:Upgrade,表示client希望升級連線;
// Upgrade必須為:websocket,表示client希望升級到Websocket協議;
// Sec-WebSocket-Key:是隨機字串,服務端會將其做一定運算,最後在Response中返回“Sec-WebSocket-Accept”頭的值。用於避免普通http請求被當做WebSocket協議。
// Sec-WebSocket-Version:表示支援的Websocket版本。RFC6455要求使用的版本是13,之前草案的版本均應當被棄用。

響應如下:

HTTP/1.1 101 Switching Protocols
Upgrade:websocket
Connection:upgrade
Sec-WebSocket-Accept:QJsTRym36zHnArQ7FCmSdPhuK78=

// Connection:upgrade 升級被伺服器同意
// Upgrade:websocket 指示客戶端升級到websocket
// Sec-WebSocket-Accept:參考上面請求的Sec-WebSocket-Key的註釋

2. WebSocket在Java中

JavaEE 7的JSR-356:Java API for WebSocket,已經對WebSocket做了支援。不少Web容器,如Tomcat、Jetty等都支援WebSocket。Tomcat從7.0.27開始支援WebSocket,從7.0.47開始支援JSR-356。

但是如果使用Java EE的WebSocket API的話,還有很多自己需要封裝的地方。所以接下來我要說的並不是Java官方的API,而是目前正在接觸的一種推送框架:Socket.IO以及其Server端的Java實現netty-socketio。這個框架不僅支援WebSocket,還支援Long-Polling模式。

注意Socket.IO並不是一個標準的WebSocket的實現,只是說Socket.IO使用並很好的支援了WebSocket協議而已。

下面就說一下這兩個框架。

3. SOCKET.IO

Socket.IO enables real-time bidirectional event-based communication. It consists in:

  • a Node.js server (this repository)

由於其Server端是用Node.js實現的,又沒有提供Java版本的Server,所以我找到了一個比較流行的第三方實現:netty-socketio。

4. netty-socketio

This project is an open-source Java implementation of Socket.IO server. Based on Netty server framework.

netty-socketio是一個開源的Socket.IO Server的Java實現,基於Netty。

接下來我就使用netty-socketio來做一個demo。

三、netty-socketio例項

建議先大致讀一下Socket.IO和netty-socketio的官方網站相關資訊,以有個整體的概念,然後再做Demo,我就不把那些搬過來了。

Socket.IO中的一些重要概念。

  1. Server:代表一個服務端伺服器;

  2. Namespace:一個Server中可以包含多個Namespace。見名知意,Namespace代表一個個獨立的空間。

  3. Socket/Client:基本上這兩個詞是一個概念。

    • JavaScript客戶端叫Socket,在建立時必須確定加入哪個Namespace,使用Socket可以讓你和伺服器通訊。注意這個和伯克利Socket是不同的,只是開發者借用了一樣的名字、功能相似。
    • Java服務端用Client來表示連線上伺服器的連結,它就代表了JavaScript連線時建立的那個Socket
  4. room:在服務端,一個Namespace中你可以建立任意個房間,房間就是給Client進行分組,以進行組範圍的通訊。Client可以選擇加入某個房間,也可以不加入。

程式碼例項:兩個Namespace,廣播通訊。

  1. Java服務端

    public static void main(String[] args) throws InterruptedException {
    
    Configuration config = new Configuration();
    config.setHostname("localhost");
    config.setPort(9092);
    
    // 可重用地址,防止處於重啟時處於TIME_WAIT的TCP影響服務啟動
    final SocketConfig socketConfig = new SocketConfig();
    socketConfig.setReuseAddress(true);
    config.setSocketConfig(socketConfig);
    
    final SocketIOServer server = new SocketIOServer(config);
    final SocketIONamespace chat1namespace = server.addNamespace("/chat1");
    chat1namespace.addEventListener("message", ChatObject.class, new DataListener<ChatObject>() {
        @Override
        public void onData(SocketIOClient client, ChatObject data, AckRequest ackRequest) {
            // broadcast messages to all clients
            chat1namespace.getBroadcastOperations().sendEvent("message", data);
        }
    });
    
    final SocketIONamespace chat2namespace = server.addNamespace("/chat2");
    chat2namespace.addEventListener("message", ChatObject.class, new DataListener<ChatObject>() {
        @Override
        public void onData(SocketIOClient client, ChatObject data, AckRequest ackRequest) {
            // broadcast messages to all clients
            chat2namespace.getBroadcastOperations().sendEvent("message", data);
        }
    });
    
    server.start();
    
    Thread.sleep(Integer.MAX_VALUE);
    
    server.stop();
    }
    
  2. JS客戶端

    引用到的JS檔案:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Demo Chat</title>
        <link href="bootstrap.css" rel="stylesheet">
    <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>
    
    <script src="js/socket.io/socket.io.js"></script>
    <script src="js/moment.min.js"></script>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    
    <script>
        var userName1 = 'user1_' + Math.floor((Math.random() * 1000) + 1);
        var userName2 = 'user2_' + Math.floor((Math.random() * 1000) + 1);
    
        var chat1Socket = io.connect('http://localhost:9092/chat1');
        var chat2Socket = io.connect('http://localhost:9092/chat2');
    
        function connectHandler(parentId) {
            return function() {
                output('<span class="connect-msg">Client has connected to the server!</span>', parentId);
            }
        }
    
        function messageHandler(parentId) {
            return function(data) {
                output('<span class="username-msg">' + data.userName + ':</span> '
                        + data.message, parentId);
            }
        }
    
        function disconnectHandler(parentId) {
            return function() {
                output('<span class="disconnect-msg">The client has disconnected!</span>', parentId);
            }
        }
    
        function sendMessageHandler(parentId, userName, chatSocket) {
            var message = $(parentId + ' .msg').val();
            $(parentId + ' .msg').val('');
    
            var jsonObject = {'@class': 'com.ddupa.service.push.model.ChatObject',
                    userName: userName,
                    message: message};
            chatSocket.json.send(jsonObject);
        }
    
        chat1Socket.on('connect', connectHandler('#chat1'));
        chat2Socket.on('connect', connectHandler('#chat2'));
    
        chat1Socket.on('message', messageHandler('#chat1'));
        chat2Socket.on('message', messageHandler('#chat2'));
    
        chat1Socket.on('disconnect', disconnectHandler('#chat1'));
        chat2Socket.on('disconnect', disconnectHandler('#chat2'));
    
        function sendDisconnect1() {
            chat1Socket.disconnect();
        }
    
        function sendDisconnect2() {
            chat2Socket.disconnect();
        }
    
        function sendMessage1() {
            sendMessageHandler('#chat1', userName1, chat1Socket);
        }
    
        function sendMessage2() {
            sendMessageHandler('#chat2', userName2, chat2Socket);
        }
    
        function output(message, parentId) {
            var currentTime = "<span class='time'>"
                    + moment().format('HH:mm:ss.SSS') + "</span>";
            var element = $("<div>" + currentTime + " " + message + "</div>");
            $(parentId + ' .console').prepend(element);
        }
    
        $(document).keydown(function(e) {
            if (e.keyCode == 13) {
                $('#send').click();
            }
        });
    </script>
    </head>
    <body>
        <h1>Namespaces demo chat</h1>
        <br />
        <div id="chat1" style="width: 49%; float: left;">
            <h4>chat1</h4>
            <div class="console well"></div>
    
            <form class="well form-inline" onsubmit="return false;">
                <input class="msg input-xlarge" type="text"
                    placeholder="Type something..." />
                <button type="button" onClick="sendMessage1()" class="btn" id="send">Send</button>
                <button type="button" onClick="sendDisconnect1()" class="btn">Disconnect</button>
            </form>
        </div>
    
        <div id="chat2" style="width: 49%; float: right;">
            <h4>chat2</h4>
            <div class="console well"></div>
    
            <form class="well form-inline" onsubmit="return false;">
                <input class="msg input-xlarge" type="text"
                    placeholder="Type something..." />
                <button type="button" onClick="sendMessage2()" class="btn" id="send">Send</button>
                <button type="button" onClick="sendDisconnect2()" class="btn">Disconnect</button>
            </form>
        </div>
    </body>
    
    </html>
    

到這裡,我們學習了一個能用於生產的推送框架的基本使用。不過,以上只是一個簡單例子,僅做引路入門,更多參考可以直接去官方網站找到,我再寫就是贅述了:

例外的一點是,由於分散式netty-socketio的部署方式文件中描述的不太清晰,且這部分實際中比較重要,我會在下面再繼續描述下。

四、分散式伺服器例項

1. 分散式環境下的問題

在分散式部署環境下假設有3臺伺服器分別為:PushServer001PushServer002PushServer003。有3個Client連線上了伺服器且他們都在一個名稱空間下的同一個room中(叫room1)。連線關係如下:

  • Client1 <———> PushServer001
  • Client2 <———> PushServer001
  • Client3 <———> PushServer003

    這裡寫圖片描述

此時Client1傳送了一條訊息,PushServer叢集收到訊息後顯然需要將其推到Client2Client3上。

  • Client2好說:它和Client1連線的是同一個PushServer001PushServer001通過Client1可以獲取到room,繼而通過room獲取到其下的所有Clients(其中必有Client2),然後推送即可。

  • Client3怎麼辦呢?它連線的是PushServer003,而003並沒有收到Client1的推送事件。

2. 解決方案

其實解決方案也很簡單,就是用釋出/訂閱 模式。

  1. 首先需要引入一個第三方的釋出/訂閱系統,比如這裡使用Redis-PUB/SUB(如果Redis是主從複製的,注意PUB只能由Master做,SUB則Master和Slaves都行)

  2. 其次,每當伺服器需要傳送訊息時:

    • 先將訊息傳送給本Server儲存的某room中的所有Client
    • 接著再立即釋出一個通知,例如叫PubSubStore.DISPATCH,並將訊息內容放入其中。
    // 本伺服器推送
    try {
        Iterable<SocketIOClient> clients = pushNamespace.getRoomClients(room);
        for (SocketIOClient socketIOClient : clients) {
            socketIOClient.send(packet);
        }
    } catch (Exception e) {
        logger.error("當前服務直接推送失敗", e);
    }
    
    // 分發訊息(當前服務不會向client推送自己分發出去的訊息)
    try {
        pubSubStore.publish(PubSubStore.DISPATCH, new DispatchMessage(userId, packet, pushNamespace.getName()));
    } catch (Exception e) {
        logger.error("分發訊息失敗", e);
    }
  3. 最後,每臺伺服器啟動時都訂閱通知PubSubStore.DISPATCH。每當當前伺服器收到此類訂閱通知時,就將其中的訊息分發到同一個房間名的所有Client去。在com.corundumstudio.socketio.store.pubsub.BaseStoreFactory.init(*)時:

    pubSubStore().subscribe(PubSubStore.DISPATCH, new PubSubListener<DispatchMessage>() {
        @Override
        public void onMessage(DispatchMessage msg) {
            String room = msg.getRoom();
            namespacesHub.get(msg.getNamespace()).dispatch(room, msg.getPacket());
        }
    }, DispatchMessage.class);

其它一些事

1. HTTP持久連線

所謂HTTP持久連線即是:HTTP persistent connection,意即TCP連線重用技術。HTTP 1.0 的連線本來是“短連線”:建立一次TCP做完請求-響應即關閉,這樣頻繁的建立、關閉TCP連線顯然是很低效比較浪費資源。

所以HTTP協議後來就做了升級,允許使用一個請求和響應頭Connection:keep-alive,來祈使伺服器能夠保持連線不中斷。如此,一個TCP連線就能在你對同一個網站進行訪問的時候被多次複用,請求網頁HTML本身、網頁中的JS、CSS和圖片等都用這一個連線。

不過,到了HTTP 1.1 以上連線預設就是持久化的了。

值得注意的是HTTP伺服器一般都有超時機制,伺服器不可能容忍你一直不釋放連線的。例如:Apache httpd 1.3/2.0是15秒、2.2是5秒。

持久連線做的是連線複用的工作,並不是解決全雙工通訊、推送的。

相關推薦

WEB即時通訊/訊息

寫在前面 通常進行的Web開發都是由客戶端主動發起的請求,然後伺服器對請求做出響應並返回給客戶端。但是在很多情況下,你也許會希望由伺服器主動對客戶端傳送一些資料。 那麼,該如何實現這個需求,或者說該如何向網頁推送訊息呢? 一、推送方式 我們知道,

即時通訊-Android方案(MQTT)

這篇文章是居於前面的幾篇部落格,如果還不知道ActiveMQ伺服器的請看:即時通訊-ActiveMQ環境搭建 1.什麼是MQTT協議 MQTT(Message Queuing Telemetry Transport,訊息佇列遙測傳輸)是IBM開發的一個即

淺析web端的訊息原理

開發十年,就只剩下這套架構體系了! >>>   

Web即時通訊訊息的實現

在瀏覽某些網頁的時候,例如 WebQQ、京東線上客服服務、CSDN私信訊息等類似的情況下,我們可以在網頁上進行線上聊天,或者即時訊息的收取與回覆,可見,這種功能的需求由來已久,並且應用廣泛。 網上關於這方面的文章也能搜到一大堆,不過基本上都是理論,真正能夠執行

基於Netty實現的Android 訊息(即時通訊)的解決方案

根據Netty框架實現訊息推送(即時聊天)功能. Netty框架,TCP長連線,心跳,阻塞訊息佇列,執行緒池處理訊息傳送, 基於Google ProtoBuf自定義的訊息協議, TCP粘包/拆包.... 客戶端通過TCP連線到伺服器,並建立TCP長連線;當伺服器端收到新訊息後通過TCP連線推送給

Web Socket 多個使用者之間實現時時訊息

1個月不寫部落格了,最近挺忙的,剛用了2天寫了個預約的小程式和大家分享下~首先大家看下介面:1.祕書端 - 專門新增預約的內容,新增以後立馬在 “市長端” 彈出有一個新的預約2.市長端 - 專門看最新的預約 ,看看要不要接待,接待或不接待點選按鈕以後以後立馬 回覆祕書其實挺簡

SignalR SelfHost實時訊息,整合到web中,實現伺服器訊息

先前用過兩次SignalR,但是中途有段時間沒弄了,今天重新弄,發現已經忘得差不多了,做個筆記! 首先建立一個控制檯專案Nuget新增引用聯機搜尋:Microsoft.AspNet.SignalR.SelfHostMicrosoft.Owin.Cors 在Program.cs新增程式碼新增一個

SignalR快速入門 ~ 仿QQ即時聊天,訊息,單聊,群聊,多群公聊(基礎=》提升)

 SignalR快速入門 ~ 仿QQ即時聊天,訊息推送,單聊,群聊,多群公聊(基礎=》提升,5個Demo貫徹全篇,感興趣的玩才是真的學) 應用情景之一:   沒太多連續的時間來研究SignalR,所以我把這篇文章分了三個階段: 第一個階段,簡單使用,熟悉並認識SignalR 第二個階段,實現

通過Socket.IO與nodeJs實現即時訊息

很早開始就想用WebSocket完成即時訊息推送功能。之前本打算用WebSocket + C#實現的,結果人上了年紀變笨了,弄了一天也沒弄好 ⊙﹏⊙ 今天參考了幾篇資料,終於搞定了一個Socket.IO結合nodeJs的Demo。 用Socket.IO有個很大的好處就是開

Nodejs和一個簡單的web頁面訊息服務

前言: 英語能力有限,所以不能叫做純翻譯,大概比例是70%翻譯,20%理解,10%自由發揮 原文: http://www.gianlucaguarini.com/blog/nodejs-and-a-simple-push-notification-server/ 簡述: 用

Workerman之WEB訊息框架使用筆記【一】

伺服器使用的時候需要注意雲盾和360埠攔截 下載解壓到任意目錄 cd到目錄下執行 start.php linux :php start.php start -d win:直接執行start_

android socket通訊demo (本篇服務於android訊息

本文系作者原創,轉載請附原文地址,謝謝。 文章末尾提供本文中的原始碼下載連結,需資源積分1分,人艱不拆,下載後評論資源可獲系統返回積分=無損! 前言: 關於什麼是socket通訊,本篇文件中不進行解釋,不甚清楚的可以去百科查詢,日後得空我也會整理相關的內容。 本文

web+java+js的GoEasy的訊息

原文http://blog.csdn.net/xiqincai9/article/details/52535275以前都是使用ajax定時傳送請求到後臺,這種方式非常消耗系統資源。在大併發情況時如果不對執行緒進行控制的話,還會重複取資料,造成資料錯誤。   鑑於這種情況,使

spring boot 整合activemq 進行服務端訊息web頁面)

最近公司的專案裡有需要服務端向web端實時推送訊息的需求,網上搜索了一番,有前端頁面通過定時任務向後臺傳送ajax請求重新整理,有使用第三方提供的訊息服務(GoEasy),前者因為會有很多請求是無用的,容易加大伺服器負荷造成宕機,後者現在收費了(免費的也只能用一

利用Hessian10分鐘配置出一個簡單的跨Web服務消息

開始 mage from 分鐘 啟動 hessian accept 就是 pattern 筆者,之前對Web跨服務推送數據一無所知,今天研究了一下。其實有些事物,在不理解的時候完全覺得好似天外來物。但了解一點點之後,又會覺得十分有趣。每天閑扯一下很開心,下面一個簡單的實例1

Android 基於Netty的訊息方案之物件的傳遞(四)

在上一篇文章中《Android 基於Netty的訊息推送方案之字串的接收和傳送(三)》我們介紹了Netty的字串傳遞,我們知道了Netty的訊息傳遞都是基於流,通過ChannelBuffer傳遞的,那麼自然,Object也需要轉換成ChannelBuffer來傳遞。好在Netty本身已經給我們寫好了

Android 基於Netty的訊息方案之字串的接收和傳送(三)

在上一篇文章中《Android 基於Netty的訊息推送方案之概念和工作原理(二)》 ,我們介紹過一些關於Netty的概念和工作原理的內容,今天我們先來介紹一個叫做ChannelBuffer的東東。 ChannelBuffer  Netty中的訊息傳遞,都必須以位元

Android 基於Netty的訊息方案之概念和工作原理(二)

上一篇文章中我講述了關於訊息推送的方案以及一個基於Netty實現的一個簡單的Hello World,為了更好的理解Hello World中的程式碼,今天我來講解一下關於Netty中一些概念和工作原理的內容,如果你覺得本篇文章有些枯燥,請先去閱讀《Android 基於Netty的訊息推送方案之Hell

IOS APNS訊息框架介紹(pushy)以及詳細使用方法

最近公司需要做IOS訊息推送的功能,我負責後臺推送,IOS端資料處理以及回撥我不負責,本篇文章主要介紹基於java的apns訊息推送,使用框架為pushy。 宣告:我先前也沒有接觸過這個IOS推送,自己研究了兩天,通過百度,對比各個框架的優缺點,最後選擇了這個框架,有說的不對的地方,還

android 實現mqtt訊息,以及不停斷線重連的問題解決

前段時間專案用到mqtt的訊息推送,整理一下程式碼,程式碼的原型是網上找的,具體哪個地址已經忘記了。 程式碼的實現是新建了一個MyMqttService,全部功能都在裡面實現,包括連伺服器,斷線重連,訂閱訊息,處理訊息,釋出訊息等基本操作。 首先新增依賴: dependencies { &