編輯:關於Android編程
Hello,大家好,今天又來寫博客了,項目終於搞完了最近又有時間寫寫博客了。在上上篇博客中我們學習了Android中網絡通訊,並用Socket實現了Android客戶端與服務器的通訊,那麼這一篇將進一步來完善這一功能,就是要實現兩個android手機端的通訊。
通過本篇博客你將學到以下知識點
①Socket的用法
②如何實現兩個手機的端的通訊
③JAVA中的流的小知識
在開始之前我們先來分析以下如何實現這個通訊,首先來考慮這麼幾個問題
①這種實時的通訊應采取哪種通訊方式
②怎麼保證是消息能到達我們想發送的那一方,也就是說A想與B交流怎麼保證B收到的消息是A發過來的
③怎麼保證消息的實時性,也就是說A發一條消息B能實時收到。
要想回答這三個問題其實不難,讀過Android開發之網絡通訊詳解這篇博客的童鞋應該知道,這種及時性比較高的通訊一般采用Socket這種通訊方式,而對於第二個問題如果想讓消息到達我們的指定方,針對A和B需要有一個唯一的標識,這個標識我們可以自己定義,在本文中采用的策略是為A和B定義一個ID來唯一的確定它,在A用戶發送消息的時候只要指定它想把消息發送到的那個用戶的ID就能保證B收到的消息是A發過來的。保證消息的實時性也就是通過使用Socket來解決的。
通訊的過程圖解
從上圖我們可以清楚的看到整個過程服務器充當的是一個中轉的作用,clientSocket1首先會將消息封裝成json發送給服務器,服務器解析後再封裝將消息發送給clientSocket2。
客戶端的運行效果圖(注意:下面是一整張圖,是一張圖片):
上述運行效果就實現了兩個Android機的相互通訊。兩個客戶端分配的id分別為0和1。在發送消息時需要指定消息的到達方。
3.1 客戶端發送消息實現步驟
第一步需要做的當然就是連接到服務器,連接服務器的方法為
clientSocket=new Socket(ip,port);即設置服務器的ip和端口號,建立連接之後通過while(true)就可以不斷的監聽服務器是否發送過來消息了。
第二步就是要輸入你要發送的好友的id號,這樣就能保證你發送的消息能按照你的預期到達接收方。
第三步就是發送消息了在發送消息的時候需要注意,我們是把消息封裝成json發過去的,這個json中包含哪些信息呢?有三種信息①消息發送方id②消息的內容③消息到達方id。
封裝json的代碼如下
//根據clientSocket.getOutputStream得到BufferedWriter對象,從而從輸出流中獲取數據 mWriter=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"utf-8")); 。。。。。 //封裝成json JSONObject json = new JSONObject(); json.put("to", Integer.parseInt(friendId)); json.put("msg", msgContent); //通過BufferedWriter對象向服務器寫數據 mWriter.write(json.toString()+"\n"); //一定要調用flush將緩存中的數據寫到服務器 mWriter.flush();這個json中包含三個信息:①消息到達方id②消息的內容③消息發送方的id。封裝後通過BufferWriter的write方法將消息發送到服務器。
3.2 客戶端接收消息的實現
這裡接收消息是用了while循環不斷的監聽服務器是否有消息發送過來,如果有消息發送過來則用BufferedReader一行一行的去讀取消息的內容,然後顯示,實現的主要代碼如下:
//根據clientSocket.getInputStream得到BufferedReader對象,從而從輸入流中獲取數據 mReader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"utf-8")); //根據clientSocket.getOutputStream得到BufferedWriter對象,從而從輸出流中獲取數據 mWriter=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"utf-8")); while(isReceivingMsgReady){ if(mReader.ready()){ Message msg = handler.obtainMessage(); msg.what=2; msg.obj=mReader.readLine(); handler.sendMessage(msg); } Thread.sleep(200); } mWriter.close(); mReader.close(); clientSocket.close();
可以看到在客戶端通過while循環當mReader.ready()為true時就會讀取服務器返回消息的一行,然後更新顯示。
4、實現兩個手機間的通訊服務器的實現
服務器端的代碼我使用是MyEclipse,首先我們來看看上述發送消息的過程中服務器端運行的截圖:
服務器端的功能是怎麼實現的呢?毫無疑問首先要做的當然是初始化服務器並指定端口號,代碼如下:
serverSocket = new ServerSocket(SOCKET_PORT);
接著當有客戶端連接到服務器時會為每一個客戶端開啟一個子線程,並將這個子線程加入到集合中對應的代碼如下
while (flag) { //有客戶端連接,時serverSocket.accept()方法會返回客戶端socket Socket clientSocket = serverSocket.accept(); SocketThread socketThread = new SocketThread(clientSocket,socketId++); socketThread.start(); mThreadList.add(socketThread); }
在開啟的子線程SocketThread中會有一個while循環監聽客戶端發過來的消息,並將這條消息添加到mThreadList集合,在這個子線程中循環讀取客戶端發過來的消息
//循環讀取客戶端發過來的消息 while (flag) { if (reader.ready()) { String comeData=reader.readLine(); JSONObject msgJson = new JSONObject(comeData); Message msg = new Message(); msg.setTo(msgJson.getInt("to")); msg.setMsg(msgJson.getString("msg")); msg.setFrom(mSocketId); msg.setTime(getTime(System.currentTimeMillis())); mMsgList.add(msg); System.out.println("用戶:"+mSocketId+"向用戶:"+msg.getTo()+"發送的消息內容為:"+msg.getMsg()); } Thread.sleep(100); }
其實也就是說在服務器中為每一個連接到服務器的客戶端開啟一個子線程,並在這個子線程中循環監聽這個客戶端是否發過來消息,在上面我們看到服務器解析消息後,將這條消息封裝到了Message這個bean中並添加到了集合中。Message中包含的信息從上面可以看出。到這裡服務器就可以收到服務器發過來的消息了,服務器收到消息後要做的工作就是將這條消息發送給客戶端,(從實現原理圖中可以看出服務器起到一個中轉的作用)那麼怎樣實現這個功能呢?它的實現也不難,從上面的描述我們可以知道只要客戶端向服務器發送一條消息,我們就會將這條消息放到一個集合mMsgList中,也就是說只要服務器收到消息mMsgList這個集合就不為空,只要mMsgList這個集合不為空就說明服務器還擁有未轉發的消息,需要轉發。怎麼實現轉發呢?
首先這裡有兩個集合一個是Message的集合mMsgList,另一個是為每一個客戶端Socket開啟的一個子線程SocketThread的集合mThreadList。這兩個集合的關系是每一個Message肯定是mThreadList中的一個SocketThread(客戶端)發送的。
當SocketThread的id與Messsage中的to(即消息的到達方)相等時,因為每一個客戶端(假設是clientSocket1)連接到服務器時都要開啟一個SocketThread子線程,在這個子線程中有clientSocket1的引用,所以當相等時就說明這個Message是發送給這個clientSocket1的。然後通過這個clientSocket1的BufferedWriter將這個消息發送給這個客戶端。與其對應的代碼如下
while(flag) { if(mMsgList.size() > 0) { Message from = mMsgList.get(0); for(SocketThread toThread : mThreadList) { //遍歷mThreadList如果to.socketID==from.to說明這個toThread與mMsgList中的這條內容是對應的 //這裡toThread的作用是通過它得到這條消息的BufferedWriter,mMsgList.get(0)得到這條消息,然後通過 //BufferedWriter將這條消息發送到指定方 if(toThread.mSocketId == from.getTo()) { //這裡的writer是SocketThread中的writer,這樣才能保證在調用writer.flush之後消息到達 //我們的指定方 BufferedWriter writer = toThread.writer; JSONObject json = new JSONObject(); json.put("from", from.getFrom()); json.put("msg", from.getMsg()); json.put("time", from.getTime()); writer.write(json.toString()+"\n"); writer.flush(); System.out.println("轉發消息成功"); break; } } mMsgList.remove(0); } Thread.sleep(200); }
這樣將這條消息解析封裝成json後就發送到了指定的客戶端,就完成了兩個android機的通訊。其實個人覺著對這些原理的知識還是需要去好好學習,弄懂的,它的實現思想對我們以後的編程也是很有作用的。
關於實現兩個手機端通訊的討論就到這裡了,可能我們看到的那些通訊的軟件采用的方式不是本文使用的方式,但是原理性的東西是不會變的,這篇博客也是從最原始的地方來理解手機通訊的一些簡單的原理。
如有謬誤,歡迎批評指正,如有疑問歡迎留言。
如果本篇博客對你有幫助就點擊左上角關注,關注吧,鎖定本台觀看更多精彩內容0.0
這裡提醒大家注意的是源碼包含兩部分,一部分是服務端,另一部分是客戶端,服務端是MyEclipse程序,客戶端就是我們的android程序。
什麼是反射?反射是一種能夠在程序運行時動態訪問、修改某個類中任意屬性(狀態)和方法(行為)的機制(包括private實例和方法),java反射機制提供了以下幾個功能:在運
1、在res文件夾下新建drawable文件夾。 2、新建一個xml文件。 3、采用drawable來定義資源。 st
什麼是Android UDP?UDP是User Datagram Protocol的簡稱,中文名是用戶數據包協議,是OSI參考模型中一種無連接的傳輸層協議,提供面向事務的
1.onKeyDown 方法 onKeyDown 方法是KeyEvent.Callback 接口中的一個抽象方法,重寫onKeyDown 方法可以監聽到按鍵被按下的事件,