編輯:關於Android編程
今天來學習一下android中通信方式中的socket。上兩次我們分別使用了HttpURLConnection , 和 HttpClient來實現通信,他們都是在使用HTTP協議,Socket被稱為套接字,使用的協議有TCP和UDP,TCP和UDP的區別在於TCP是可靠穩定的,自帶容錯處理等優點,所以效率要低一點。然後UDP就不那麼穩定了,當使用UDP發送數據的時候,每次send,那麼socket只管send,不會管send之後對方是否收到,是否順序正確,所以UDP被稱為不穩定的傳輸,但是其效率卻很高,因為做的事情很簡單。
今天我們學習socket是使用tcp協議,在android中使用socket其實就是使用java中的socket,看應用的包 java.net.*; 就知道。
我們來完成一個小的局域網聊天的程序,包含一個服務器,android應用作為客戶端,一台手機發送信息後,服務器會轉發給其他手機,很簡單。代碼比較多,後面附上下載地址,我們先來看怎麼使用socket。
客戶端Socket使用步驟:
(1)Socket mSocket = new Socket( SERVER_IP, SERVER_PORT); // 兩個參數分別為服務器ip地址,和服務器監聽的端口號
(2)BufferedReader mBufferReader = new BufferedReader(new InputStreamReader( mSocket.getInputStream())); // 通過socket.getInputStream() 可以得到輸入流,可從socket獲取服務器發送的數據。為了能一行一行讀取,我們將其轉化為 BufferReader,可以使用BufferReader.readLine() 一行一行得去取等待在socket上的數據。
(3)PrintWriter mPrintWriter = new PrintWriter(mSocket.getOutputStream(), true); // 通過socket.getOutputStream() 可以得到輸入流,就可以通過socket向服務器發送數據, 這裡需要套上 PrintWriter 標准的接口,就可以使用 mPrintWriter.println(“ ... ),直接發送數據。
(4)使用完後斷開連接。
我們來看一看實例:
mSocket = new Socket(SERVER_IP, SERVER_POART); mBufferReader = new BufferedReader(new InputStreamReader( mSocket.getInputStream())); mPrintWriter = new PrintWriter(mSocket.getOutputStream(), true);如果沒有報 Exception那就表示鏈接服務器已經成功,這時就可以使用 mBufferReader和 mPrintWrinter 來實現數據的收發。
讀取數據:
while (true) { if (null != (mStrMsg = mBufferReader.readLine())) { mStrMsg += ; if(mStrMsg.trim().equals(exit)){ mHandler.sendMessage(mHandler.obtainMessage(2)); return ; } mHandler.sendMessage(mHandler.obtainMessage(0)); } }發送數據:
private View.OnClickListener sendListener = new View.OnClickListener() { @Override public void onClick(View v) { String str = mEtMessage.getText().toString().trim(); if(mPrintWriter == null){ showToast(請先連接服務器!); return ; } mPrintWriter.println(str); mPrintWriter.flush(); mEtMessage.setText(); } };斷開連接:
showToast(斷開連接); try { mBufferReader.close(); mPrintWriter.close(); mSocket.close(); mSocket = null; if (mGetMessageThread != null) { mGetMessageThread = null; } } catch (IOException e) { e.printStackTrace(); }
在服務端我們需要有一個ServerSocket,這是用來接收連接請求的,當每接收到一個一個請求後就會返回一個Socket套接字,就可以使用這個套接字與客戶端通信。注意:服務器端應該是一直運行,且可以接收很多連接的程序,服務器程序一定不能被關閉或者崩掉,所以在設計服務器的時候要考慮很多很多事情,我們這裡只是簡單的處理收到客戶端請求連接,然後將其加入到list當中,如果收到消息,就將收到的消息轉發給列表中其他所有socket,很簡單的處理。
使用步驟:
(1)ServerSocket mServerSocket = new ServerSocket(SERVERPORT); // 創建監聽連接ServerSocket
(2)不停監聽 mServerSocket, 使用accept() 接收連接,如果偵測到連接,就啟動一個線程,將返回值socket傳入,那麼每個線程就對應一個客戶端,可以與客戶端通信了。
(3)接下來就是 每個線程如果收到數據,就需要將消息轉發給 客戶單列表中所有其他用戶。
(4)客戶端斷開鏈接後,清除客戶socket信息。
啟動監聽連接,並啟動一個線程池,當監聽到連接請求時創建啟動線程,並放入到線程池中運行:
try { mServerSocket = new ServerSocket(SERVERPORT); mExecutorService = Executors.newCachedThreadPool(); System.out.println(Server Start...); Socket client = null; while (true) { client = mServerSocket.accept(); mClientList.add(client); mExecutorService.execute(new ThreadServer(client)); } } catch (IOException e) { e.printStackTrace(); }線程中接收消息,以及轉發消息:
private class ThreadServer implements Runnable { private Socket mClient; private BufferedReader mBufferedReader; private PrintWriter mPrintWriter; private String mStrMsg; public ThreadServer(Socket client) throws IOException { this.mClient = client; mBufferedReader = new BufferedReader(new InputStreamReader( mClient.getInputStream())); mStrMsg = usr: + this.mClient.getInetAddress() + connected + ,total: + mClientList.size(); sendMessage(mStrMsg); } private void sendMessage(String msg) throws IOException { System.out.println(msg); for (Socket client : mClientList) { mPrintWriter = new PrintWriter(client.getOutputStream(), true); mPrintWriter.println(msg); } } @Override public void run() { try { while (null != (mStrMsg = mBufferedReader.readLine())) { if (mStrMsg.trim().equals(exit)) { mStrMsg = user: + mClient.getInetAddress() + exit! + total: + (mClientList.size() - 1); sendMessage(mStrMsg); mPrintWriter = new PrintWriter( mClient.getOutputStream(), true); mPrintWriter.println(exit); mBufferedReader.close(); mPrintWriter.close(); mClientList.remove(mClient); mClient.close(); break; } else { mStrMsg = mClient.getInetAddress() + : + mStrMsg; sendMessage(mStrMsg); } } } catch (SocketException e) { // e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
如果沒有網絡基礎,這個理解起來還是有點復雜的,下面貼了項目代碼,大家自己去體會一下吧,使用socket其實很簡單,主要是邏輯處理。
(1)android2.3之後不能再UI主線程中調用網絡請求,會直接崩潰,所以需要使用handler來發送消息處理
(2)實例代碼放在你的機子上不一定能使用,SERVER_IP為計算機在局域網的本機地址,需要自己修改。 android客戶端需要連上計算機,這樣客戶端就能找到服務器了。
關於定位,相信大家都不陌生。現在很多App基本都少不了定位的功能,Android本身也提供了定位的功能(LocationManager),但是由於Google牆太厚了,所
本節引言: 本節帶來的是Android多媒體中的——MediaPlayer,我們可以通過這個API來播放音頻和視頻 該類是Androd
前言谷歌對UI測試(UI Tetsting)的概念是:確保用戶在一系列操作過程中(例如鍵盤輸入、點擊菜單、彈出對話框、圖像顯示以及其他UI控件的改變),你的應用程序做出正
1.ServicesService 是一個可以在後台執行長時間運行操作而不使用用戶界面的應用組件。服務可由其他應用組件啟動,而且即使用戶切換到其他應用,服務仍將在後台繼續