天天看點

Android開發筆記: Socket通信--【帶例子】

一、Socket通信簡介 

​​Android​​與伺服器的通信方式主要有兩種,一是Http通信,一是Socket通信。兩者的最大差異在于,http連接配接使用的是“請求—響應方式”,即在請求時建立連接配接通道,當用戶端向伺服器發送請求後,伺服器端才能向用戶端傳回資料。而Socket通信則是在雙方建立起連接配接後就可以直接進行資料的傳輸,在連接配接時可實作資訊的主動推送,而不需要每次由用戶端想伺服器發送請求。 那麼,什麼是socket?Socket又稱套接字,在程式内部提供了與外界通信的端口,即端口通信。通過建立socket連接配接,可為通信雙方的資料傳輸傳提供通道。socket的主要特點有資料丢失率低,使用簡單且易于移植。

1.1什麼是Socket Socket

是一種抽象層,應用程式通過它來發送和接收資料,使用Socket可以将應用程式添加到網絡中,與處于同一網絡中的其他應用程式進行通信。簡單來說,Socket提供了程式内部與外界通信的端口并為通信雙方的提供了資料傳輸通道。

 1.2Socket的分類

 根據不同的的底層協定,Socket的實作是多樣化的。本指南中隻介紹TCP/IP協定族的内容,在這個協定族當中主要的Socket類型為流套接字(streamsocket)和資料報套接字(datagramsocket)。流套接字将TCP作為其端對端協定,提供了一個可信賴的位元組流服務。資料報套接字使用UDP協定,提供資料打包發送服務。 下面,我們來認識一下這兩種Socket類型的基本實作模型。

二、Socket 基本通信模型

Android開發筆記: Socket通信--【帶例子】

三、Socket基本實作原理

 3.1基于TCP協定的Socket 

伺服器端首先聲明一個ServerSocket對象并且指定端口号,然後調用Serversocket的accept()方法接收用戶端的資料。accept()方法在沒有資料進行接收的處于堵塞狀态。(Socketsocket=serversocket.accept()),一旦接收到資料,通過inputstream讀取接收的資料。

  用戶端建立一個Socket對象,指定伺服器端的ip位址和端口号(Socketsocket=newSocket("172.168.10.108",8080);),通過inputstream讀取資料,擷取伺服器發出的資料(OutputStreamoutputstream=socket.getOutputStream()),最後将要發送的資料寫入到outputstream即可進行TCP協定的socket資料傳輸。

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簡單通信

前言:添權重限

1. <!--允許應用程式改變網絡狀态-->    
2. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>    
3.     
4. <!--允許應用程式改變WIFI連接配接狀态-->    
5. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>    
6.     
7. <!--允許應用程式通路有關的網絡資訊-->    
8. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>    
9.     
10. <!--允許應用程式通路WIFI網卡的網絡資訊-->    
11. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>    
12.     
13. <!--允許應用程式完全使用網絡-->    
14. <uses-permission android:name="android.permission.INTERNET"/>      

4.1使用TCP協定通信

android端實作:

伺服器端簡單實作:

1.     protected void connectServerWithTCPSocket() {  
2.   
3.         Socket socket;  
4. try {// 建立一個Socket對象,并指定服務端的IP及端口号  
5. new Socket("192.168.1.32", 1989);  
6. // 建立一個InputStream使用者讀取要發送的檔案。  
7. new FileInputStream("e://a.txt");  
8. // 擷取Socket的OutputStream對象用于發送資料。  
9.             OutputStream outputStream = socket.getOutputStream();  
10. // 建立一個byte類型的buffer位元組數組,用于存放讀取的本地檔案  
11. byte buffer[] = new byte[4 * 1024];  
12. int temp = 0;  
13. // 循環讀取檔案  
14. while ((temp = inputStream.read(buffer)) != -1) {  
15. // 把資料寫入到OuputStream對象中  
16. 0, temp);  
17.             }  
18. // 發送讀取的資料到服務端  
19.             outputStream.flush();  
20.   
21. /** 或建立一個封包,使用BufferedWriter寫入,看你的需求 **/  
22. //          String socketData = "[2143213;21343fjks;213]";  
23. //          BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(  
24. //                  socket.getOutputStream()));  
25. //          writer.write(socketData.replace("\n", " ") + "\n");  
26. //          writer.flush();  
27. /************************************************/  
28. catch (UnknownHostException e) {  
29.             e.printStackTrace();  
30. catch (IOException e) {  
31.             e.printStackTrace();  
32.         }  
33.   
34.     }      

4.2使用UDP協定通信

1. public void ServerReceviedByTcp() {  
2. // 聲明一個ServerSocket對象  
3. null;  
4. try {  
5. // 建立一個ServerSocket對象,并讓這個Socket在1989端口監聽  
6. new ServerSocket(1989);  
7. // 調用ServerSocket的accept()方法,接受用戶端所發送的請求,  
8. // 如果用戶端沒有發送資料,那麼該線程就停滞不繼續  
9.         Socket socket = serverSocket.accept();  
10. // 從Socket當中得到InputStream對象  
11.         InputStream inputStream = socket.getInputStream();  
12. byte buffer[] = new byte[1024 * 4];  
13. int temp = 0;  
14. // 從InputStream當中讀取用戶端所發送的資料  
15. while ((temp = inputStream.read(buffer)) != -1) {  
16. new String(buffer, 0, temp));  
17.         }  
18.         serverSocket.close();  
19. catch (IOException e) {  
20.         e.printStackTrace();  
21.     }  
22. }      

用戶端發送資料實作:

1. protected void connectServerWithUDPSocket() {  
2.       
3.     DatagramSocket socket;  
4. try {  
5. //建立DatagramSocket對象并指定一個端口号,注意,如果用戶端需要接收伺服器的傳回資料,  
6. //還需要使用這個端口号來receive,是以一定要記住  
7. new DatagramSocket(1985);  
8. //使用InetAddress(Inet4Address).getByName把IP位址轉換為網絡位址    
9. "192.168.1.32");  
10. //Inet4Address serverAddress = (Inet4Address) Inet4Address.getByName("192.168.1.32");    
11. "[2143213;21343fjks;213]";//設定要發送的封包    
12. byte data[] = str.getBytes();//把字元串str字元串轉換為位元組數組    
13. //建立一個DatagramPacket對象,用于發送資料。    
14. //參數一:要發送的資料  參數二:資料的長度  參數三:服務端的網絡位址  參數四:伺服器端端口号   
15. new DatagramPacket(data, data.length ,serverAddress ,10025);    
16. //把資料發送到服務端。    
17. catch (SocketException e) {  
18.         e.printStackTrace();  
19. catch (UnknownHostException e) {  
20.         e.printStackTrace();  
21. catch (IOException e) {  
22.         e.printStackTrace();  
23.     }    
24. }      

用戶端接收伺服器傳回的資料:

1. public void ReceiveServerSocketData() {  
2.     DatagramSocket socket;  
3. try {  
4. //執行個體化的端口号要和發送時的socket一緻,否則收不到data  
5. new DatagramSocket(1985);  
6. byte data[] = new byte[4 * 1024];  
7. //參數一:要接受的data 參數二:data的長度  
8. new DatagramPacket(data, data.length);  
9.         socket.receive(packet);  
10. //把接收到的data轉換為String字元串  
11. new String(packet.getData(), packet.getOffset(),  
12.                 packet.getLength());  
13. //不使用了記得要關閉  
14. "the number of reveived Socket is  :" + flag  
15. "udpData:" + result);  
16. catch (SocketException e) {  
17.         e.printStackTrace();  
18. catch (IOException e) {  
19.         e.printStackTrace();  
20.     }  
21. }      

伺服器接收用戶端實作:

1. public void ServerReceviedByUdp(){  
2. //建立一個DatagramSocket對象,并指定監聽端口。(UDP使用DatagramSocket)    
3.     DatagramSocket socket;  
4. try {  
5. new DatagramSocket(10025);  
6. //建立一個byte類型的數組,用于存放接收到得資料    
7. byte data[] = new byte[4*1024];    
8. //建立一個DatagramPacket對象,并指定DatagramPacket對象的大小    
9. new DatagramPacket(data,data.length);    
10. //讀取接收到得資料    
11.         socket.receive(packet);    
12. //把用戶端發送的資料轉換為字元串。    
13. //使用三個參數的String方法。參數一:資料包 參數二:起始位置 參數三:資料包長    
14. new String(packet.getData(),packet.getOffset() ,packet.getLength());    
15. catch (SocketException e) {  
16.         e.printStackTrace();  
17. catch (IOException e) {  
18.         e.printStackTrace();  
19.     }    
20. }      

五、總結:

使用UDP方式android端和伺服器端接收可以看出,其實android端和伺服器端的發送和接收大庭相徑,隻要端口号正确了,互相通信就沒有問題,TCP使用的是流的方式發送,UDP是以包的形式發送。