1.定期查詢:按照指定的時間間隔連接服務器查詢獲取最新的消息。實現起來簡單,非實時,查詢時間過短則流量耗費多,耗電量大。下面是一個愛立信的測試結果:
2.短信方式:需要及時發送消息給客戶端時也可以通過這種方式,但大家都懂的,這個很花錢。
3.長輪詢:基本上與目前很多網站使用的方式一樣(WEB阿里旺旺、微博、人人等等)。客戶端發起一個很長超時時間的請求,然后服務器端在沒有消息的時候阻塞這個請求(一直不給返回值)直到快要超時為止,有消息到來再返回響應。客戶端收到響應或超時后立即再發起請求。
這種算是比較好的方式了,消息能夠及時地到達客戶端。但考慮到移動互聯網的特點(網絡不穩定、設備內存小)這種方式不能保證重要的消息一定能推送到客戶端,另外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.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訂閱用戶廣播的任務,夠牛逼了吧)。