引言
第一次寫博客,本身是小白,也不敢說什麼精通了解,只是把自己新學到的東西通過博客作爲筆記,以便以後忘記以及作爲參考。也把自己的學習心得分享給大家,寫的好於不好大家不要見怪,畢竟是新手小白,理解難免會有錯誤。也請大家取其精華,去其糟粕。舉一反三,通過自己的理解再變成自己的技能。廢話少說,下面進入正文吧!!!
本文是由郭霖視頻見證Android消息推送時刻 學習後的梳理與筆記對於想學習推送的同學可以幫助大家更好的理解視頻中的內容,由於視頻內容過長,在這裏針對每個模塊和代碼進行簡單的解析。和整個流程的概括,幫助大家即使不開視頻也能簡單的理解和搭建子的消息推送。
通過學習會學到什麼
- 推送的基本原理
- socket
- mina框架
- XMPP協議
- 心跳、斷線、重連
- 別名和標籤消息推送
- 富媒體消息推送
推送的基本原理
學習推送要簡單的理解幾個概念:
什麼是推送?
推送就是指服務器定向將信息實時發送至客戶端的功能
長連接短連接?
長連接就是指客戶端與服務器始終建立一個通信連接,在連接沒有中斷之前,客戶端和服務器之間可是隨時進行通信。典型例子:socket
短連接是指通訊雙方在有數據交互時,就建立一個連接,數據發送完後則斷開此連接。典型例子:http
長連接實現及時通訊:推送
短連接實現及時通訊:輪詢
推送工作原理圖:
其實推送和IM有很大的相似,但卻比IM要簡單一些,畢竟推送只相當於IM的一半流程嘛!
既然講到了與服務器建立聯繫那就少不了socket通信,我將簡單的利用socket通信的方式發出來大家參考
客戶端:
在需要高亮的代碼塊的前一行及後一行使用三個反引號“`”,同時第一行反引號後面表面代碼塊所使用的語言,如下:
客戶端:
public class SocketClient {
public static final int PORT=9898;
public static void main(String[] args) {
SocketClient client=new SocketClient();
client.run();
}
public void run(){
Socket socket=null;
BufferedReader reader=null;
BufferedReader inputReader=null;
BufferedWriter writer=null;
try {
socket=new Socket(InetAddress.getLocalHost().getHostAddress(),PORT);
reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
inputReader=new BufferedReader(new InputStreamReader(System.in));
startServerReplyLinstener(reader);
String inputCountent;
int count=0;
while(!(inputCountent=inputReader.readLine()).equals("bye")){
writer.write(inputCountent);
if (count % 2==0) {
writer.write("\n");
}
count++;
writer.flush();
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
socket.close();
writer.close();
reader.close();
inputReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void startServerReplyLinstener(final BufferedReader reader){
new Thread(new Runnable() {
@Override
public void run() {
try {
String response;
while((response=reader.readLine())!=null){
System.out.println(response);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
服務器端:
/*
* 服務器類
*/
public class SocketServer {
BufferedWriter writer;
BufferedReader reader;
public static void main(String[] args) {
SocketServer server=new SocketServer();
server.run();
}
public void run(){
ServerSocket serverSocket=null;
Socket socket=null;
try {
serverSocket=new ServerSocket(8181);
System.out.println("server start...");
while(true){
socket=serverSocket.accept();
manageConnection(socket);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
serverSocket.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 管理客戶端和服務器的連接
*/
public void manageConnection(final Socket socket){
new Thread(new Runnable() {
public void run() {
try {
System.out.println("client"+socket.hashCode()+"connedted");
reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String receiveMsg;
while((receiveMsg=reader.readLine())!=null){
System.out.println("client"+socket.hashCode()+"says: "+receiveMsg);
writer.write("server says: "+receiveMsg+"\n");
writer.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
writer.close();
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
}
mina框架通過Java nio(jdk1.4)技術基於TCP/IP和UDP/IP協議提供了抽象的、事件驅動的、異步的API。幫助我們更方便的去處理服務器與客戶端的連接,也是我們本文推送消息中用的框架,針對mina框架的使用主要分4步,下面就舉出利用mina框架進行客戶端與服務器建立通信
public class MinaClient {
public static void main(String[] args) {
NioSocketConnector connector=new NioSocketConnector();
connector.setHandler(new MyServerHandle());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory()));
ConnectFuture future=connector.connect(new InetSocketAddress("127.0.0.1", 9898));
future.awaitUninterruptibly();
IoSession session=future.getSession();
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
try {
String content;
while(!(content=reader.readLine()).equals("bye")){
session.write(content);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
mina框架中,通信的狀態與接受消息都是通過Handle(),然後調用connector.setHandler(new MyServerHandle()); 其中MyServerHandle()需要繼承IoHandlerAdapter,然後調用 connector.getFilterChain()去設置一個過濾器來處理消息。這裏只是簡單的創建一個文本過濾器也可以自定義自己的過濾器,最後通過ConnectFuture future=connector.connect(new InetSocketAddress(“127.0.0.1”, 9898));制定服務器的地址和端口號。
服務器端這裏問了節省篇幅在這裏我就不寫了 具體的邏輯代碼可以去我的github上去參考下
XMPP協議的簡單理解
相信大家通過簡單瞭解,大家對socket和mina框架都有了簡單瞭解(其實我也不寫什麼,具體看代碼,代碼中重要的部分也有註釋,有過有時間的也可以去看看視頻,連我這麼笨的都一看都懂,相信大家學起來也不會浪費太多時間),那麼接下來就簡單的瞭解下XMPP協議。
對於理解xmpp的人來說這裏也不用看了,我本身也是一點不懂的,通過視頻的學習,我對xmpp也有了簡單的理解,這裏只是把我筆記分享個大家
XMPP協議解析
概念:
可擴展消息和展示協議。是一種以XML爲基礎的開放式實時通信的協議。它將需要實時通信的消息嵌入到XML結構體當中,不僅具有很好的可擴展性,還有較強的可讀性。
- XMPP的優點
- 開放性
- 可擴展
- 跨平臺
- 標準性
- 缺點:
- 數據冗餘
- 不支持二進制數據
XMPP 傳輸 是通過 XML Stanzas
XMPP的身份標識 每個客戶端是使用JID來作爲身份標識的:
[user”@”]domain[“/”resource]
一寫簡單的理解請訪問我的學習筆記,這裏就不浪費過多的篇幅了。筆記地址