3.2基於UDP協議的數據傳輸
服務器端首先創建一個DatagramSocket對象,並且指點監聽的端 口。接下來創建一個空的DatagramSocket對象用於接收數據 (bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data,data.length)),
使用DatagramSocket的receive方法接收客戶端發送的數據,receive()與serversocket的accepet()類似, 在沒有數據進行接收的處於堵塞狀態。
客戶端也創建個DatagramSocket對象,並且指點監聽的端口。接 下來創建一個InetAddress對象,這個對象類似與一個網絡的發送地址
(InetAddressserveraddress=InetAddress.getByName("172.168.1.120"))
.定義要發送的 一個字符串,創建一個DatagramPacket對象,並制定要講這個數據報包發送到網絡的那個地址以及端口號,
最後使用DatagramSocket 的對象的send()發送數據。
*(Stringstr="hello";bytedata[]=str.getByte(); DatagramPacketpacket=new DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet);)
四、android 實現socket簡單通信
4.1使用TCP協議通信
android端實現:
[java] view plaincopy
- protected void connectServerWithTCPSocket() {
- Socket socket;
- try {// 創建一個Socket對象,並指定服務端的IP及端口號
- socket = new Socket("192.168.1.32", 1989);
- // 創建一個InputStream用戶讀取要發送的文件。
- InputStream inputStream = new FileInputStream("e://a.txt");
- // 獲取Socket的OutputStream對象用於發送數據。
- OutputStream outputStream = socket.getOutputStream();
- // 創建一個byte類型的buffer字節數組,用於存放讀取的本地文件
- byte buffer[] = new byte[4 * 1024];
- int temp = 0;
- // 循環讀取文件
- while ((temp = inputStream.read(buffer)) != -1) {
- // 把數據寫入到OuputStream對象中
- outputStream.write(buffer, 0, temp);
- }
- // 發送讀取的數據到服務端
- outputStream.flush();
- /** 或創建一個報文,使用BufferedWriter寫入,看你的需求 **/
- // String socketData = "[2143213;21343fjks;213]";
- // BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
- // socket.getOutputStream()));
- // writer.write(socketData.replace("\n", " ") + "\n");
- // writer.flush();
- /************************************************/
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
服務器端簡單實現:
[java] view plaincopy
- public void ServerReceviedByTcp() {
- // 聲明一個ServerSocket對象
- ServerSocket serverSocket = null;
- try {
- // 創建一個ServerSocket對象,並讓這個Socket在1989端口監聽
- serverSocket = new ServerSocket(1989);
- // 調用ServerSocket的accept()方法,接受客戶端所發送的請求,
- // 如果客戶端沒有發送數據,那麼該線程就停滯不繼續
- Socket socket = serverSocket.accept();
- // 從Socket當中得到InputStream對象
- InputStream inputStream = socket.getInputStream();
- byte buffer[] = new byte[1024 * 4];
- int temp = 0;
- // 從InputStream當中讀取客戶端所發送的數據
- while ((temp = inputStream.read(buffer)) != -1) {
- System.out.println(new String(buffer, 0, temp));
- }
- serverSocket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
4.2使用UDP協議通信
客戶端發送數據實現:
[java] view plaincopy
- protected void connectServerWithUDPSocket() {
- DatagramSocket socket;
- try {
- //創建DatagramSocket對象並指定一個端口號,注意,如果客戶端需要接收服務器的返回數據,
- //還需要使用這個端口號來receive,所以一定要記住
- socket = new DatagramSocket(1985);
- //使用InetAddress(Inet4Address).getByName把IP地址轉換爲網絡地址
- InetAddress serverAddress = InetAddress.getByName("192.168.1.32");
- //Inet4Address serverAddress = (Inet4Address) Inet4Address.getByName("192.168.1.32");
- String str = "[2143213;21343fjks;213]";//設置要發送的報文
- byte data[] = str.getBytes();//把字符串str字符串轉換爲字節數組
- //創建一個DatagramPacket對象,用於發送數據。
- //參數一:要發送的數據 參數二:數據的長度 參數三:服務端的網絡地址 參數四:服務器端端口號
- DatagramPacket packet = new DatagramPacket(data, data.length ,serverAddress ,10025);
- socket.send(packet);//把數據發送到服務端。
- } catch (SocketException e) {
- e.printStackTrace();
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
客戶端接收服務器返回的數據:
[java] view plaincopy
- public void ReceiveServerSocketData() {
- DatagramSocket socket;
- try {
- //實例化的端口號要和發送時的socket一致,否則收不到data
- socket = new DatagramSocket(1985);
- byte data[] = new byte[4 * 1024];
- //參數一:要接受的data 參數二:data的長度
- DatagramPacket packet = new DatagramPacket(data, data.length);
- socket.receive(packet);
- //把接收到的data轉換爲String字符串
- String result = new String(packet.getData(), packet.getOffset(),
- packet.getLength());
- socket.close();//不使用了記得要關閉
- System.out.println("the number of reveived Socket is :" + flag
- + "udpData:" + result);
- } catch (SocketException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
服務器接收客戶端實現:
[java] view plaincopy
- public void ServerReceviedByUdp(){
- //創建一個DatagramSocket對象,並指定監聽端口。(UDP使用DatagramSocket)
- DatagramSocket socket;
- try {
- socket = new DatagramSocket(10025);
- //創建一個byte類型的數組,用於存放接收到得數據
- byte data[] = new byte[4*1024];
- //創建一個DatagramPacket對象,並指定DatagramPacket對象的大小
- DatagramPacket packet = new DatagramPacket(data,data.length);
- //讀取接收到得數據
- socket.receive(packet);
- //把客戶端發送的數據轉換爲字符串。
- //使用三個參數的String方法。參數一:數據包 參數二:起始位置 參數三:數據包長
- String result = new String(packet.getData(),packet.getOffset() ,packet.getLength());
- } catch (SocketException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
五、總結:
使用UDP方式android端和服務器端接收可以看出,其實android端和服務器端的發送和接收大庭相徑,只要端口號正確了,相互通信就沒有問題,TCP使用的是流的方式發送,UDP是以包的形式發送。
Android操作HTTP實現與服務器通信
本示例以Servlet爲例,演示Android與Servlet的通信。
衆所周知,Android與服務器通信通常採用HTTP通信方式和Socket通信方式,而HTTP通信方式又分get和post兩種方式。至於Socket通信會在以後的博文中介紹。
HTTP協議簡介:
HTTP (Hypertext Transfer Protocol ),是Web聯網的基礎,也是手機聯網常用的協議之一,HTTP協議是建立在TCP協議之上的一種協議。
HTTP連接最顯 著的特點是客戶端發送的每次請求都需要服務器回送響應,在請求結束後,會主動釋放連接。從建立連接到關閉連接的過程稱爲“一次連接”。 在HTTP 1.0中,客戶端的每次請求都要求建立一次單獨的連接,在處理完本次請求後,就自動釋放連接。 在HTTP 1.1中則可以在一次連接中處理多個請求,並且多個請求可以重疊進行,不需要等待一個請求結束後再發送下一個請求。
由 於HTTP在每次請求結束後都會主動釋放連接,因此HTTP連接是一種“短連接”、“無狀態”,要保持客戶端程序的在線狀態,需要不斷地向服務器發起連接 請求。通常的做法是即使不需要獲得任何數據,客戶端也保持每隔一段固定的時間向服務器發送一次“保持連接”的請求,服務器在收到該請求後對客戶端進行回 復,表明知道客戶端“在線”。若服務器長時間無法收到客戶端的請求,則認爲客戶端“下線”,若客戶端長時間無法收到服務器的回覆,則認爲網絡已經斷開。
基於HTTP1.0協議的客戶端在每次向服務器發出請求後,服務器就會向客戶端返回響應消息,在確認客戶端已經收到響應消息後,服務端就會關閉網絡連接。在這個數據傳輸過程中,並不保存任何歷史信息和狀態信息,因此,HTTP協議也被認爲是無狀態的協議。
HTTP1.1 和HTTP1.0相比較而言,最大的區別就是增加了持久連接支持。當客戶端使用HTTP1.1協議連接到服務器後,服務器就將關閉客戶端連接的主動權交還 給客戶端;也就是說,只要不調用Socket類的close方法關閉網絡連接,就可以繼續向服務器發送HTTP請求。
HTTP連接使用的是“請求—響應”的方式(2次握手),不僅在請求時需要先建立連接,而且需要客戶端向服務器發出請求後,服務器端才能回覆數據。而Socket連接在雙方建立起連接後就可以直接進行數據的傳輸
HTTP協議的特點:
支持B/S及C/S模式;
簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。
靈活:HTTP 允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type 加以標記;
無狀態:HTTP 協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味着如果後續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。
HTTP協議請求方法:
請求行中包括了請求方法,解釋如下:
GET 請求獲取Request-URI 所標識的資源;
POST 在Request-URI 所標識的資源後附加新的數據;
HEAD 請求獲取由Request-URI 所標識的資源的響應消息報頭
PUT 請求服務器存儲一個資源,並用Request-URI 作爲其標識
DELETE 請求服務器刪除Request-URI 所標識的資源;
TRACE 請求服務器回送收到的請求信息,主要用於測試或診斷
CONNECT 保留將來使用
OPTIONS 請求查詢服務器的性能,或者查詢與資源相關的選項和需求
Get與Post請求區別:
Post 請求可以向服務器傳送數據,而且數據放在HTML HEADER內一起傳送到服務端URL地址,數據對用戶不可見。而get是把參數數據隊列加到提交的URL中,值和表單內各個字段一一對應, 例如(http://www.baidu.com/s?w=%C4&inputT=2710)
get 傳送的數據量較小,不能大於2KB。post傳送的數據量較大,一般被默認爲不受限制。但理論上,IIS4中最大量爲80KB,IIS5中爲100KB。
get安全性非常低,post安全性較高。
在Android開發中我們經常會用到網絡連接功能與服務器進行數據的交互,爲此Android的SDK提供了Apache的HttpClient來方便我們使用各種Http服務
///
Get() 先創建一個HttpClient 然後再創建一個HttpGet,通過HttpClient的execute方法來發送一個HttpGet並且返回String內容。
try {
// 創建一個默認的HttpClient
HttpClient httpclient =new DefaultHttpClient();
// 創建一個GET請求
HttpGet request =new HttpGet("www.google.com");
// 發送GET請求,並將響應內容轉換成字符串
String response = httpclient.execute(request, new BasicResponseHandler());
Log.v("response text", response);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
///////////////////////////////
Post()
publicstatic String post(String url, NameValuePair... params) {
try {
// 編碼參數
List<NameValuePair> formparams =new ArrayList<NameValuePair>(); // 請求參數
for (NameValuePair p : params) {
formparams.add(p);
}
UrlEncodedFormEntity entity =new UrlEncodedFormEntity(formparams,
CHARSET);
// 創建POST請求
HttpPost request =new HttpPost(url);
request.setEntity(entity);
// 發送請求
HttpClient client = getHttpClient();
HttpResponse response = client.execute(request);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
thrownew RuntimeException("請求失敗");
}
HttpEntity resEntity = response.getEntity();
return (resEntity ==null) ?null : EntityUtils.toString(resEntity, CHARSET);
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (ClientProtocolException e) {
Log.w(TAG, e.getMessage());
returnnull;
} catch (IOException e) {
thrownew RuntimeException("連接失敗", e);
}
}