1. 程式人生 > >Android 客戶端Socket 與 Java服務端ServerSocket

Android 客戶端Socket 與 Java服務端ServerSocket

Socket程式設計

 

一、Java網路程式設計基礎知識

       1、兩臺計算機間進行通訊需要以下三個條件:

           1)、 IP地址(例如 : 192.168.1.1)

           2)、 協議(服務端與客戶端之間雙方自行協商定義協議,簡稱自定義協議)

           3)、 埠號(例如 : 8888)

       2、TCP/IP協議:

            是目前世界上應用最為廣泛的協議,是以TCP和IP為基礎的不同層次上多個協議的集合,也成TCP/IP協議族、或TCP/IP協議棧

            TCP:Transmission Control Protocol 傳輸控制協議

            IP:Internet Protocol 網際網路協議

       3、TCP/IP五層模型

            應用層:HTTP、FTP、SMTP、Telnet等

            傳輸層:TCP/IP

            網路層:

            資料鏈路層:

            物理層:網線、雙絞線、網絡卡等

       4、IP地址

            為實現網路中不同計算機之間的通訊,每臺計算機都必須有一個唯一的標識---IP地址。

            32位二進位制

       5、埠

            區分一臺主機的多個不同應用程式,埠號範圍為0-65535,其中0-1023位為系統保留。

            如:HTTP:80  FTP:21 Telnet:23

            IP地址+埠號組成了所謂的Socket,Socket是網路上執行的程式之間雙向通訊鏈路的終結點,是TCP和UDP的基礎

       6、Socket套接字:

            網路上具有唯一標識的IP地址和埠組合在一起才能構成唯一能識別的識別符號套接字。

          Socket原理機制:

             通訊的兩端都有Socket

             網路通訊其實就是Socket間的通訊

             資料在兩個Socket間通過IO傳輸      

       7、Java中的網路支援

             針對網路通訊的不同層次,Java提供了不同的API,其提供的網路功能有四大類:

              InetAddress:用於標識網路上的硬體資源,主要是IP地址

              URL:統一資源定位符,通過URL可以直接讀取或寫入網路上的資料

              Sockets:使用TCP協議實現的網路通訊Socket相關的類

              Datagram:使用UDP協議,將資料儲存在使用者資料報中,通過網路進行通訊。

二、TCP程式設計

         1、TCP協議是面向連線的、可靠的、有序的、以位元組流的方式傳送資料,通過三次握手方式建立連線,形成傳輸資料的通道,在連線中進行大量資料的傳輸,效率會稍低

         2、Java中基於TCP協議實現網路通訊的類

               客戶端的Socket類

               伺服器端的ServerSocket類

        3、通訊步驟

                 ① 服務端建立ServerSocket和Socket   客戶端建立Socket

                  服務端: ServerSocket ss = new ServerSocket(PORT);  //

                                Socket s = ss.accept();  

                  客戶端: Socket clientSocket = new Socket(IP,PORT);

                 ② 開啟連線到Socket的輸入/輸出流

                  InputStream in = server.getInputStream(); 
                  OutputStream out = server.getOutputStream();  

                 ③ 按照協議對Socket進行讀/寫操作

                 ④ 關閉輸入輸出流、關閉Socket

                  in.close();

                  out.close();

三、服務端

public class ServerSocketDemo {

   public static void main(String[] args) throws IOException {
      
      ServerSocket serverSocket = new ServerSocket(9988);
      Socket socket = serverSocket.accept();
      InputStream is = socket.getInputStream();
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      String info = null;
      while ((info = br.readLine()) != null) {
         System.out.println("我是伺服器,客戶端說:" + info);
      }
      socket.shutdownInput();// 關閉輸入流
      // 4、獲取輸出流,響應客戶端的請求
      OutputStream os = socket.getOutputStream();
      PrintWriter pw = new PrintWriter(os);
      pw.write("歡迎您!");
      pw.flush();
      // 5、關閉資源
      pw.close();
      os.close();
      br.close();
      isr.close();
      is.close();
      socket.close();
      serverSocket.close();
   }

}

四、客戶端

1、建立一個單例Socket管理類·

public class SocketManager {

    private static final String TAG = "SocketManager";
    public static Socket clientSocket = null;
    private int PORT;     //埠號
    private String IP;

    /**
     * 埠
     */

    public static SocketManager instance = new SocketManager();

    private SocketManager() {
        clientSocket = connect();
    }

    public static SocketManager getInstance() {
        return instance;
    }

    public static Socket getClientSocket() {
        return clientSocket;
    }

    public static void setClientSocket(Socket socket){
        clientSocket = socket;
    }

    /**
     * 獲取當前socket例項
     */
    public Socket connect() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    clientSocket = new Socket(IP,PORT);
                    setClientSocket(clientSocket);
                    readSocketData(clientSocket);
                    //sendHeartBeat(clientSocket);
                    LogUtils.e("TAG","連線成功...");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        return clientSocket;
    }

    /**
     * 傳送心跳包

     * ThreadPoolManager.getSingleInstance().execute()   執行緒管理類
     * */
    public void sendHeartBeat(Socket socket){
        ThreadPoolManager.getSingleInstance().execute(new SendData(socket));
    }

    /**
     * 接收服務端資料
     * */
    public void readSocketData(Socket socket){
        ThreadPoolManager.getSingleInstance().execute(new ReceiveData(socket));
    }

    /**
     * 斷開連線
     */
    public void disConnect() throws IOException {
        if (clientSocket != null) {
            clientSocket.close();
            clientSocket = null;
        }
    }

    /**
     * 釋放單例, 及其所引用的資源
     */
    public void release() throws IOException {
        if (instance != null) {
            if (clientSocket != null) {
                clientSocket.close();
                clientSocket = null;
            }
            instance = null;
        }
    }
}

2、建立一個SendData執行緒類來負責傳送資料


public class SendData implements Runnable {
    private Socket sendsocket;
    private PrintWriter printWriter = null;

    public SendData(Socket socket) {
        this.sendsocket = socket;
    }

    public void run() {
        Socket socket = SocketManager.getClientSocket();
        try {
            LogUtils.e("TAG", "傳送的資料包:" + JsonUtil.getData());
           sendHeartBeatPackage(socket, "要傳送的資料");//資料包
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    /**
     * 傳送資料包到服務端
     */
    public int sendHeartBeatPackage(Socket socket1, String msg) {
        int returnCode = 0;
        if (socket1.isClosed() || socket1 == null) {
            returnCode = 0;
        }
        try {
            printWriter = new PrintWriter(socket1.getOutputStream());
            printWriter.println(msg);
            printWriter.flush();
            socket1.getOutputStream().flush();
            returnCode = 1;
        } catch (Exception e) {
            returnCode = 0;
        }
        return returnCode;
    }
}

3、建立一個ReceiveData接收執行緒類


public class ReceiveData implements Runnable {
    private Socket socket = null;
    private byte[] buffer = new byte[1024];
    private int bytes;
    InputStream mmInStream = null;

    public ReceiveData(Socket mSocket) {
        this.socket = mSocket;
    }

    @Override
    public void run() {
        try {
            mmInStream = socket.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        while (true) {
            try {
                if ((bytes = mmInStream.read(buffer)) > 0) {
                    byte[] buf_data = new byte[bytes];
                    for (int i = 0; i < bytes; i++) {
                        buf_data[i] = buffer[i];
                    }
                    String msg = new String(buf_data);
                    LogUtils.e("TAG", "來自服務端的資料:" + msg);
                }
            } catch (IOException e) {
                try {
                    mmInStream.close();
                    LogUtils.e("TAG", "讀取出現異常...");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                break;
            }
        }
    }
}

五、未完待續。。。

有疑問可直接提問博主,文中可能存在講解不到之處,望大家諒解,也可對博主指出不到之處,之後進行改正。