最近在找android手機上的訊息推送的解決方案。目前看來有以下幾種常用的方式:
1.定期查詢:按照指定的時間間隔串連伺服器查詢擷取最新的訊息。實現起來簡單,非即時,查詢時間過短則流量耗費多,耗電量大。下面是一個愛立信的測試結果:
2.簡訊方式:需要及時發送訊息給用戶端時也可以通過這種方式,但大家都懂的,這個很花錢。
3.長輪詢:基本上與目前很多網站使用的方式一樣(WEB阿里WangWang、微博、人人等等)。用戶端發起一個很長逾時時間的請求,然後伺服器端在沒有訊息的時候阻塞這個請求(一直不給傳回值)直到快要逾時為止,有訊息到來再返迴響應。用戶端收到響應或逾時後立即再發起請求。
這種算是比較好的方式了,訊息能夠及時地到達用戶端。但考慮到移動互連網的特點(網路不穩定、裝置記憶體小)這種方式不能保證重要的訊息一定能推送到用戶端,另外anroid在手機記憶體小的情況下可能會殺這個在等待PUSH訊息不怎麼活動的進程。
4.C2DM:GOOGLE提供了訊息的PUSH功能,需要和GOOGLE帳號綁定,目前看來這種方式在國內是沒戲的。
5.XMPP:在用戶端整合asmack,伺服器端使用ejabberd或openfire等開源的XMPP伺服器軟體也是一種可行的方式。
缺點就是先要有註冊、登陸等過程,無線網路環境下串連的效果不怎麼樣。重要訊息的PUSH需要自己實現確認邏輯。
6.MQTT:基於代理髮布/訂閱 模式的訊息傳輸協議,適用於受限環境:
網路代價昂貴、頻寬低、不可靠;
在嵌入裝置中運行、處理器和記憶體資源有限。
特點是:
使用發布/訂閱模式,解除應用程式耦合;
對負載內容屏蔽的訊息傳輸;
使用TCP/IP;
提供“至多一次”、“至少一次”、“有且僅有一次”三種層級的訊息傳輸;
小型傳輸、流量開銷少;
使用LAST WILL 和TESTAMENT特性通知有關各方用戶端異常中斷機制。
(聽起來簡直就是為移動互連網設計的 )
下面是基於MQTT的簡單實現方案:
伺服器:
可以採用IBM的MQTT伺服器RSMB;
開源的Mosquitto
用戶端:
IBM的wmqtt.jar 適用於JAVA用戶端。
1.下載安裝運行Mosquitto伺服器。
2.在anroid用戶端整合以下代碼:
import com.ibm.mqtt.IMqttClient;
import com.ibm.mqtt.MqttClient;
import com.ibm.mqtt.MqttException;
import com.ibm.mqtt.MqttPersistence;
import com.ibm.mqtt.MqttPersistenceException;
import com.ibm.mqtt.MqttSimpleCallback;
public class MQTTConnection implements MqttSimpleCallback{
IMqttClient mqttClient = null;
private static int MQTT_PORT =1883;
private static MqttPersistence MQTT_PERSISTENCE=null;
public static String MQTT_CLIENT_ID ="";
private static boolean MQTT_CLEAN_START = true;
private static short MQTT_KEEP_ALIVE = 60 * 15;
private static int[] MQTT_QUALITIES_OF_SERVICE = { 0 } ;
private long mStartTime;
public MQTTConnection(String brokerHostName, String initTopic) throws MqttException {
String mqttConnSpec = "tcp://" + brokerHostName + "@" + MQTT_PORT;
// Create the client and connect
mqttClient = MqttClient.createMqttClient(mqttConnSpec, MQTT_PERSISTENCE);
String clientID = MQTT_CLIENT_ID;
mqttClient.connect(clientID, MQTT_CLEAN_START, MQTT_KEEP_ALIVE);
// register this client app has being able to receive messages
mqttClient.registerSimpleHandler(this);
// Subscribe to an initial topic, which is combination of client ID and device ID.
subscribeToTopic(initTopic);
// Save start time
mStartTime = System.currentTimeMillis();
// Star the keep-alives
//startKeepAlives();
}
private void subscribeToTopic(String topicName) throws MqttException {
if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
// quick sanity check - don't try and subscribe if we don't have
// a connection
System.out.println("subscribe to topic fail");
} else {
String[] topics = { topicName };
mqttClient.subscribe(topics, MQTT_QUALITIES_OF_SERVICE);
}
}
public void disconnect() {
try {
mqttClient.disconnect();
} catch (MqttPersistenceException e) {
System.out.println("disconnection to server error");
}
}
@Override
public void connectionLost() throws Exception {
// TODO Auto-generated method stub
System.out.println("connection to server closed");
}
@Override
public void publishArrived(String topicName, byte[] payload, int qos, boolean retained)
throws Exception {
// TODO Auto-generated method stub
String s = new String(payload);
System.out.println("push message recived :"+s);
}
}
3.運行用戶端程式,在命令視窗中使用Mosquitto_pub.exe -q [Qos層級] -t [主題] -m [發布的內容] 進行測試。
另:Mosquitto由於使用socket select 模型,能支援的用戶端串連數量有限。
如果要支援更高並發量,一方面可以考慮採用“策略伺服器+Mosquitto叢集”的方式,另一方面可以考慮erlang實現的一些MQTT伺服器替換Mosquitto(上次見到的一個類似的發布/訂閱系統每秒可以完成向40K訂閱使用者廣播的任務,夠牛逼了吧)。