一、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 基本通訊模型
三、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通訊實現樣本
伺服器程式
伺服器程式需要在PC上運行,該程式比較的簡單,因此不需要建立Android項目,直接定義一個JAVA類,並且運行該類即可。它僅僅建立ServerSocket監聽,並使用Socket擷取輸入輸出資料流。
import java.io.IOException;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;public class SimpleServer { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //建立一個ServerSocket,用於監聽用戶端socket的串連請求 ServerSocket ss=new ServerSocket(30000); //採用迴圈不斷接受來自用戶端的請求,伺服器端也對應產生一個Socket while(true){ Socket s=ss.accept(); OutputStream os=s.getOutputStream(); os.write("您好,您收到了伺服器的新年祝福!n".getBytes("utf-8")); os.close(); s.close(); } }}
用戶端程式
package my.learn.tcp;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;import java.net.UnknownHostException;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.widget.EditText;public class SimpleClient extends Activity { private EditText show; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); show = (EditText) findViewById(R.id.show); try { Socket socket = new Socket("自己電腦的IP地址", 30000); //設定10秒之後即認為是逾時 socket.setSoTimeout(10000); BufferedReader br = new BufferedReader(new InputStreamReader( socket.getInputStream())); String line = br.readLine(); show.setText("來自伺服器的資料:"+line); br.close(); socket.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block Log.e("UnknownHost", "來自伺服器的資料"); e.printStackTrace(); } catch (IOException e) { Log.e("IOException", "來自伺服器的資料"); // TODO Auto-generated catch block e.printStackTrace(); } }}
需要注意的是,在Manifest.xml檔案當中,需要對互連網的訪問進行授權。
<uses-permission android:name="android.permission.INTERNET"/>