Android TCP socket通訊

zpengyong發表於2017-07-09

轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/74896575

之前做過的一個區域網內TCP通訊、聊天的demo(當然不是區域網也可以進行通訊,剛試了一下可以的),週日整理了一下。該demo可以做客戶端,也可以做服務端。兩個手機都安裝該應用,一個做客戶端、一個做服務端,然後進行通訊(連線在同一區域網,或伺服器是外網ip,客戶端可以上網)。
20180728修改:Android7.0以上socket傳送資料失敗,需要將傳送的操作放到子執行緒中,最新demo以更新。

demo下載地址http://www.demodashi.com/demo/10567.html


1 簡介

TCP(Transmission Control Protocol):傳輸控制協議,是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議。

在Internet協議族(Internet protocol suite)中,TCP層是位於IP層之上,應用層之下的中間層。不同主機的應用層之間經常需要可靠的、像管道一樣的連線,但是IP層不提供這樣的流機制,而是提供不可靠的包交換。

Socket 英文原義是“孔”或“插座”。通常稱為”套接字”,用於描述IP地址和埠,是一個通訊鏈的控制程式碼,可以用來實現不同虛擬機器或不同計算機之間的通訊。在Internet上的主機一般執行了多個服務軟體,同時提供幾種服務。每種服務都開啟一個Socket,並繫結到一個埠上,不同的埠對應於不同的服務(客戶若是需要哪種服務,就講插頭連到相應的插座上),客戶的“插頭”也是一個socket。
Socket通訊,需要服務端和客戶端,兩端都要例項化一個Socket。但伺服器和客戶端的Socket是不一樣的。

  • 客戶端:可以連線服務端、傳送資料、接收資料、關閉連線等。
  • 服務端:可以實現繫結繫結埠,接收客戶端的連線、接收資料,傳送資料等。

Android在包java.net包下提供了ServerSocketSocket類,ServerSocket用於建立伺服器的Socket。Socket用於例項化客戶端的Socket。當連線成功,客戶端和服務端都會產生一個Socket例項,通過此Socket進行通訊。
先看下效果圖:
這裡寫圖片描述
這裡寫圖片描述 這裡寫圖片描述


2 服務端

服務端ServerSocket的構造方法有以下幾種:

  • ServerSocket ():構造一個新的未繫結的ServerSocket。
  • ServerSocket (int port):構造一個新的ServerSocket並繫結到指定埠,如果port等於0,則埠由系統自動分配。
  • ServerSocket (int port, int backlog):構造一個新的ServerSocket並繫結到指定埠,並指定進入佇列的數目。如果port等於0,則埠由系統自動分配。
  • ServerSocket (int port, int backlog, InetAddress localAddress):構造一個新的ServerSocket並繫結到指定埠和指定的地址,並指定進入佇列的數目。如果port等於0,則埠由系統自動分配。如果localAddress為null,則可以使用任意地址。
  • -

TCP服務端工作具體步驟:
步驟1:建立一個ServerSocket,並繫結到指定埠上。

try {
    //開啟服務、指定埠號
    ServerSocket mServerSocket = new ServerSocket(5566);
} catch (IOException e) {
    e.printStackTrace();
    Toast.makeText(this, "服務開啟失敗", Toast.LENGTH_SHORT).show();
    return;
}

步驟2:呼叫ServerSocket的accept(),監聽連線請求,如果客戶端請求連線,則接收連線,返回Scoekt物件。

Socket mSocket = mServerSocket.accept();
步驟3:呼叫Socket類的getInputStream()和getOutputStream()獲取輸入輸出流。

class SocketAcceptThread extends Thread{
    @Override
    public void run() {
        try {
            //等待客戶端的連線,Accept會阻塞,直到建立連線,
            //所以需要放在子執行緒中執行。
            mSocket = mServerSocket.accept();
            //獲取輸入流
            mInStream = mSocket.getInputStream();
            //獲取輸出流
            mOutStream = mSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
            mHandler.sendEmptyMessage(MSG_SOCKET_ACCEPTFAIL);
            return;
        }
        Log.i(TAG, "accept success");
        mHandler.sendEmptyMessage(MSG_SOCKET_CONNECT);
    }
}

步驟4:開始傳送、接收資料。
傳送資料:

private void writeMsg(String msg){
    if(msg.length() == 0 || mOutStream == null)
        return;
    try {   //傳送
        mOutStream.write(msg.getBytes());
        mOutStream.flush();
    }catch (Exception e) {
        e.printStackTrace();
    }
}

接收資料:(從輸入流讀取資料,需要在一個子執行緒中迴圈執行下面的方法。)

byte[] buffer = new byte[1024];
//迴圈執行read,用來接收資料。
//資料存在buffer中,count為讀取到的資料長度。
int count = mInStream.read(buffer);

步驟5:服務不再需要,則關閉服務。

if(mServerSocket != null){
    try {
        mServerSocket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

3 客戶端

TCP客戶端工作具體步驟:
步驟1:建立一個Socket,連線到伺服器端、指定埠號。放在子執行緒中執行,否則會有問題。

class SocketConnectThread extends Thread{
    public void run(){
        try {
            //指定ip地址和埠號
            mSocket = new Socket(mIpAddress,mClientPort);
            if(mSocket != null){
                //獲取輸出流、輸入流
                mOutStream = mSocket.getOutputStream();
                mInStream = mSocket.getInputStream();
            }
        } catch (Exception e) {
            e.printStackTrace();
            mHandler.sendEmptyMessage(MSG_SOCKET_CONNECTFAIL);
            return;
        }
        Log.i(TAG,"connect success");
        mHandler.sendEmptyMessage(MSG_SOCKET_CONNECT);
    }

}

步驟2:呼叫Socket類的getInputStream()和getOutputStream()獲取輸入輸出流。
具體程式碼如上所示。
步驟3:傳送、接收資料。(傳送接收資料與服務端方法相同。)
傳送資料:

private void writeMsg(String msg){
    if(msg.length() == 0 || mOutStream == null)
        return;
    try {   //傳送
        mOutStream.write(msg.getBytes());
        mOutStream.flush();
    }catch (Exception e) {
        e.printStackTrace();
    }
}

接收資料:(從輸入流讀取資料,需要在一個子執行緒中迴圈執行下面的方法。)

byte[] buffer = new byte[1024];
//迴圈執行read,用來接收資料。
//資料存在buffer中,count為讀取到的資料長度。
int count = mInStream.read(buffer);

步驟4:關閉Socket

public void closeConnection(){
    try {
        if (mOutStream != null) {
            mOutStream.close(); //關閉輸出流
            mOutStream = null;
        }
        if (mInStream != null) {
            mInStream.close(); //關閉輸入流
            mInStream = null;
           }
        if(mSocket != null){
            mSocket.close();  //關閉socket
            mSocket = null;
        }
       } catch (IOException e) {
           e.printStackTrace();
       }
    if(mReceiveThread != null){
        mReceiveThread.threadExit();
        mReceiveThread = null;
    }
   }

4 總結

在清單檔案中新增許可權

<uses-permission android:name="android.permission.INTERNET"/>

TCP通訊的使用基本就完成了,最後看一下圖片,更容易理解其通訊機制。
這裡寫圖片描述

相關文章