Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android TCP 和 UDP總結

android TCP 和 UDP總結

編輯:關於Android編程

之前寫過一些關於TCP和UDP數據傳輸的代碼,比如使用TCP傳輸音視頻數據包,P2P打洞中使用UDP等。寫好之後就直接丟下了,沒有總結下都。最近准備找工作,再拿來溫習下。


1、還是先說點啥

暫時把自己的定位很明確,就是android應用層的開發,所以關於TCP/UDP的實現細節,暫時也不想去深究。但是心裡清楚這個必須去看的,有時間推薦大家看看《TCP/IP詳解》,或者網上有很多大牛的總結。


2、TCP

不知道為什麼,這個總結不想寫的太細,不貼代碼寫的細又不知道能總結啥,好糾結,可能就是認識有限吧,公司要是有個架構就好了。不說了,還是安安穩穩的寫總結吧。TCP這個可能是我們用的比較多的或者說我用的比較多的,主要的工作還是進行大量數據的傳輸和心跳保持(想想去年面試的時候都不知道啥是心跳,汗……)。對於心跳保持,就是一個簡單的小心跳包;大量數據的傳輸,這個也總結不了啥東西,代碼就那樣,就是一些細節說一下。

客戶端:這個是我們關注的最多的,也是作為一個手機APP主要關注的,因為我們就是client

a、創建一個client socket

new Socket(ip, prot);
我們可以通過上面的方式創建一個socket,如果失敗,會拋出IOException。參數中的IP和Port是目標服務器的IP和端口號。若你想得到本地的IP和端口可通過這個socket拿到。當然,創建socket還有多種構造方法,比如 new Socket(proxy) ,如果有需要你可以查閱相關說明。

b、發送和接收數據

拿到socket對象之後我們接著要做的事情就是從這個socket中拿到輸入和輸出流,這樣我們才可以進行數據的發送和接收:
InputStream is = mSocket.getInputStream();
OutputStream out = mSocket.getOutputStream();
通過輸出流,我們可以使用is.read(receiveBuffer)和out.write(data);來進行數據的收發。這裡給兩個簡單實例:

接收數據:

	@Override
	public void execute() {
		try {
			int count = is.read(receiveBuffer);
			if (count == -1) {
				notifyError();
			}
			byte[] data = getPacket(receiveBuffer, count, is);
			mReceiverQueue.put(data);
		} catch (InterruptedException e) {
			e.printStackTrace();
			notifyError();
		} catch (IOException e) {
			e.printStackTrace();
			notifyError();
		}
	}
假如我們的數據包協議格式如下:
\
這個時候,如果進行大量數據傳輸的時候我們從InputStream中一次讀取的數據可能不是一個完整的數據包。這個時候我們需要做下面的判斷: a、讀取的數據長度是否達到包頭大小,若沒有包頭長,繼續讀,直到達到或者超過包頭大小; b、從包頭中解出長度字段,循環讀取,直到讀到長度字段標示長度為止; c、校驗數據,去除包頭,取出包體; d、重復上述步驟。

發送數據:

	@Override
	public void execute() {
		try {
			byte[] data = mSenderQueue.take();
			out.write(data);
		} catch (InterruptedException e) {
			e.printStackTrace();
			notifyError();
		} catch (IOException e) {
			e.printStackTrace();
			notifyError();
		}
	}
mSenderQueue和mReceiverQueue一樣,都是阻塞隊列。發送的時候,我們從隊列中取出要發送的數據,然後通過輸出流寫入即可。這個地方比發送簡單了一些。可能你已經注意到,我的發送和接收都用了阻塞隊列,這個原因就是考慮到大量數據的時候做一個緩沖,如果沒有緩沖,可能導致代碼的阻塞。另外就是當我們的阻塞隊列充滿的時候可以手動丟棄一些數據,這個就是具體應用了。

服務端:這個可以簡單了解下,可以java實現,也可C++等實現

首先,我們創建一個ServerSocket對象並指定一個端口號,通過這個對象的accept()方法等待客戶的連接,這個方法是阻塞的;當有客戶端連接上來之後,我們就拿到了連接的Socket,拿到這個socket之後的操作就和客戶端一樣了,最後看一下關鍵代碼:
	try {
		ServerSocket serverSocket = new ServerSocket(9559);
		while (true) {
			Socket socket = serverSocket.accept();
			// new ServiceSocketThread(socket).start();
		}
	} catch (Exception e) {
		e.printStackTrace();
	}
因為服務端不可能只與一個客戶端連接,因此上面的代碼寫在一個死循環中。拿到socket之後起一個新的線程來處理這個socket。

最後,還有一點需要注意的是:從Socket中拿到InputStream和OutputStream之後如果關閉它們,socket也將隨之關閉(未驗證)。

3、UDP

這個東西用的很少,就是當初測試P2P的時候用過。能想到的問題就是數據大小的問題,比如發送數據我們的數據定義為多大合適。但是最後沒有實際的項目驗證,在此也不好回答。先貼一段代碼出來:

public class UDPServer extends BaseThread {

	/** 發送隊列大小 */
	public static final int SENDQUEUESIZE = 10;
	/** 接收隊列大小 */
	public static final int RECEIVEQUEUESIZE = 10;
	/** TCP接收緩存大小 */
	public static final int RECEIVERBUFFERSIZE = 1024;
	/** UDP接收緩存大小 */
	public static final int RECEIVERPACKETSIZE = 1024 * 64;

	private int count = 0;
	private DatagramPacket receivePacket;
	private DatagramSocket mSocket;

	@Override
	public boolean prepare() {
		receivePacket = new DatagramPacket(new byte[RECEIVERPACKETSIZE], RECEIVERPACKETSIZE);
		try {
			mSocket = new DatagramSocket(9559);
		} catch (SocketException e) {
			System.out.println(String.format("udp connect init error: %s", e.getMessage()));
			return false;
		}
		return true;
	}

	@Override
	public void execute() {
		try {
			mSocket.receive(receivePacket);

			byte[] data = receivePacket.getData();
			int length = receivePacket.getLength();
			int offset = receivePacket.getOffset();
			System.out.print(++count
					+ String.format("length:%d|%d, offset:%d, data: %s \n", length, data.length, offset, new String(data, "gbk")));
			System.out.println(data[1024]);
		} catch (SocketException e) {
			System.out.println(String.format("udp connect init error: %s", e.getMessage()));
		} catch (IOException e) {
			System.out.println(String.format("udp connect init error: %s", e.getMessage()));
		}
	}
}
byte[] data = receivePacket.getData();這個地方拿到的data是緩沖區的大小,他們地址是樣的,這個大家可以試試就知道。至於這個data中有多少數據,就需要我們通過receivePacket.getLength();拿到。


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved