Android客戶端利用Socket進行通信

上一篇https://blog.csdn.net/Haienzi/article/details/79808077介紹了java服務器端的相關操作。這一篇主要向大家介紹Android客戶端的相關實現步驟。

基本步驟:

  • 用服務器端的IP地址和端口號實例化Socket對象。
  • 調用connect方法,連接到服務器上。
  • 將要發送到服務器的IO流填充到IO對象中,比如DataInputStream,DataOutputStrwam。
  • 調用Socket提供的getInputStream和getOutputStream方法,通過IO流對象,向服務器發送數據流。
  • 通訊完畢後,關閉打開的IO對象和Socket.

客戶端說明

客戶端涉及多個頁面,都要和服務器進行通信,可以寫一個消息監聽接口,用於監聽服務器端傳遞的消息。(這個監聽接口很重要,下面會詳細說明)

  • MessageListener.java
/**
 * 消息監聽接口
 * Created by mqh on 2017/10/30.
 */
public interface MessageListener {
    public void Message(String msg);
}
  • Client.java
import java.net.Socket;

public class Client {
    private int port;//端口號
    private String address = null;//地址
    private Socket mSocket;//Socket對象
    private ClientThread clientThread;//客戶端線程
    public void setSocket(Socket socket) {
        this.mSocket = socket;
    }
    public Client()
    {}

    public Client(String ip,int port)
    {
        this.address = ip;
        this.port = port;
    }
    public boolean start() {
        try {
            //實例化socket對象
            mSocket = new Socket(address,port);
            Log.d("testServer","client start,ip:"+address+",port:"+port);
            if (mSocket.isConnected()) {
                System.out.println("Connected..");
                //開啓對應的客戶端線程
                clientThread = new ClientThread(mSocket);
                clientThread.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    // 直接通過client得到讀線程
    public ClientInputThread getClientInputThread() {
        return clientThread.getIn();
    }

    // 直接通過client得到寫線程
    public ClientOutputThread getClientOutputThread() {
        return clientThread.getOut();
    }

    // 直接通過client停止讀寫消息
    public void setIsStart(boolean isStart) {
        clientThread.getIn().setStart(isStart);
        clientThread.getOut().setStart(isStart);
    }
   public class ClientThread extends Thread {

       private ClientInputThread in;//讀線程
       private ClientOutputThread out;//寫線程

       public ClientThread(Socket socket) {
           in = new ClientInputThread(socket);
           out = new ClientOutputThread(socket);
       }
       //開啓讀線程和寫線程
       public void run() {
           in.setStart(true);
           out.setStart(true);
           in.start();
           out.start();
       }

       // 得到讀消息線程
       public ClientInputThread getIn() {
           return in;
       }

       // 得到寫消息線程
       public ClientOutputThread getOut() {
           return out;
       }
   }

}
  • ClientInputThread.java
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
 * Created by mqh on 2017/10/30.
 */
public class ClientInputThread extends Thread {
    private Socket mSocket;
    private boolean isStart = true;
    private DataInputStream inputStream;// 對象輸入流
    private InputStreamReader iReader;
    private String msg;
    private MessageListener mMessageListener;//消息監聽接口

    public ClientInputThread(Socket socket)
    {
        this.mSocket = socket;
        try{
            inputStream = new DataInputStream(socket.getInputStream());// 實例化數據輸入流
        }catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    //設置消息監聽對象
    public void setMessageListener(MessageListener messageListener)
    {
        this.mMessageListener = messageListener;
    }
    public void setStart(Boolean isStart)
    {
        this.isStart = isStart;
    }
    @Override
    public void run() {
        try {
            System.out.println("Input isStart: " + isStart);
            while (isStart) {
                //接收從服務器發送過來的消息
                iReader = new InputStreamReader(inputStream, "UTF-8");
                //緩衝數組
                char[] buffer = new char[1024];
                int count = 0;
                StringBuffer sBuilder = new StringBuffer();
                while ((count = iReader.read(buffer,0,buffer.length))>-1) {
                    sBuilder.append(buffer,0,count);
                    if(count<1024)
                    {
                        break;
                    }
                }
                //將消息傳遞給監聽器 (發送給需要的頁面)
                mMessageListener.Message(sBuilder.toString());
            }
            if(inputStream !=null)
            {
                inputStream.close();
            }
            if (mSocket != null)
                mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • ClientOutputThread.java
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
/**
 * Created by mqh on 2017/10/30.
 */
public class ClientOutputThread extends Thread {
    private Socket socket;
    private DataOutputStream dataOutputStream;
    private OutputStreamWriter oStreamWriter;
    private boolean isStart = true;
    private String msg;//發送給服務器的消息

    public ClientOutputThread(Socket socket) {
        this.socket = socket;
        try {
            dataOutputStream = new DataOutputStream(socket.getOutputStream());// 在構造器裏面實例化對象輸出流
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setStart(boolean isStart) {
        this.isStart = isStart;
    }

    // 這裏處理跟服務器是一樣的 設置發送給服務器的消息
    public void setMsg(String msg) {
        this.msg = msg;
        synchronized (this) {
            notify();
        }
    }

    @Override
    public void run() {
        try {
            while (isStart) {
                if (msg != null) {
                    if (socket == null)
                        return;
                        //構建輸出流對象
                    oStreamWriter = new OutputStreamWriter(dataOutputStream, "UTF-8");
                    StringBuffer sBuilder = new StringBuffer();
                    sBuilder.append(msg);
                    //將消息發送給服務器
                    oStreamWriter.write(sBuilder.toString());
                    oStreamWriter.flush();
                    synchronized (this) {
                        wait();// 發送完消息後,線程進入等待狀態
                    }

                }
            }
            if(oStreamWriter != null)
            {
                oStreamWriter.close();
            }
            if (dataOutputStream != null)// 循環結束後,關閉流,釋放資源
                dataOutputStream.close();
            // 循環結束後,關閉輸出流和socket
            if (socket != null)
                socket.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

而且Android客戶端在用戶已經登陸的情況下需要一直向服務器傳遞消息,所以,想要保持與服務器的長連接,可以通過創建後臺服務來實現。當應用打開時,開啓後臺服務,在後臺服務中發送和接收與服務器通信的消息,它不會因爲界面的切換,應用程序的切換而輕易中斷。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章