Android環境下使用SocketClient

        最近對原來寫的SocketClient代碼進行優化,從整體架構到具體細節,修改的地方比較多。今天有時間把SocketClient的相關知識整理一下。如果有錯誤的地方,還望指正!!!


一、整體流程:

wKiom1ftj6fzlPcdAAB3-wJZrrU347.png-wh_50

   

 描述如下:

               1.  在Android環境下,SocketClient長連接,需要使用service。

               2.  SocketManagerService是在APK啓動時啓動。

               3.  SocketManagerService啓動時則SocketClientThread也啓動。

               4.  View調用SocketManagerServicesendCmd方法發送命令。

               5.  如果SocketClient連接斷開,則重新建立連接,並且發送該命令。

               6. 狀態返回則通過自定義Listener實現。  


二、預備知識:

 

      1. 判斷SocketClient是否與SocketServer連接:

 

        1) . public void sendUrgentData(int value) throws IOException

                源碼註釋: 

                      Sends the given single byte data which is represented by the lowest octet of {@code value} as "TCP urgent data". 

                翻譯:

                      發送給定的代表最低字節碼值的單字節數據,作爲TCP緊急數據 。   

                個人理解:

                      該方法用於判斷SocketClient是否與SocketServer連接。

             

     2.關於SocketClient的超時的理解:

 

         1) . public void connect(SocketAddress remoteAddr, int timeout) throws IOException 

              源碼註釋:    

                    Connects this socket to the remote host address and port number specified by the 

                    {@code SocketAddress} object with the given timeout. This method will block indefinitely if the timeout is set to zero.

               翻譯:

                     在有超時的情況下,socket連接指定地遠程主機的地址和端口。如果timeout是0,則方法永遠阻塞。      

                    

               個人理解:  

                   該方法的作用是SocketClient與SocketServer之間建立連接時的超時判斷。

 

         2). public synchronized void setSoTimeout(int timeout) throws SocketException 

             源碼註釋:

                   Sets this socket's {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds.

                   Use 0 for no timeout. To take effect, this option must be set before the blocking method was called.

             翻譯:

                   設置socketClient讀的超時時間。0表示沒有超時。該方法必須在阻塞方法之間調用。   

             個人理解:  

                    InputStream的read方法,在timeout的時間內沒有接收到數據,則超時。超時後read方法停止阻塞狀態。


三、問題解答  :

1.  如何實現SocketClient的重新連接?


           1). SocketClient設置setSoTime(int timeout) 當超時後,則read停止阻塞,所以線程停止運行。我代碼中timeout設置爲30分鐘。

           2). 在SocketManagerService中實現發送命令的方法,代碼如下: 

       

public void sendCameraCmdThread(byte[] cmd) {
          if (cmd == null) return;
            Log.i("TEST","====================================sendCameraCmd");
          try {
               socketClientThread.sendUrgentData();
               socketClientThread.sendCameraCmdThread(cmd);
          } catch (Exception e) {
               //重新連接的代碼
               e.printStackTrace();
               socketClientThread = new SocketClientThread();
               socketClientThread.setByteArrCommand(cmd);
               socketClientThread.start();
          }
     }


 2. SocketClient重新連接後,如何重發命令

  因爲SocketClient重新連接,所以必須在SocketClient重新連接後才能重發命令。在線程中增加 public void setCommandArr(byte[] cmds) 方法。具體代碼如下:             

@Override
public void run() {
    super.run();
    Timer timer = new Timer();
    try {
        if (clientSocket == null) {
            clientSocket = new Socket();
            clientSocket.connect(new InetSocketAddress(IP,PORT),5000);
            if (clientSocket!=null) {
                clientSocket.setReceiveBufferSize(SOCKET_RECV_BUFFER_SIZE);
                clientSocket.setSoTimeout(30*60*1000);
                cameraOutputStream = clientSocket.getOutputStream();
                cameraInputStream = clientSocket.getInputStream();

                if (cameraInputStream!=null) {
                    try {
                        byte[] buffers = new byte[56];
                        int size = 0;
                        timer.schedule(new TimerTask() {
                            @Override
                            public void run() {
                                if(cmdArr!=null) {
                                    for (int i = 0; i < cmdArr.length; i++) {
                                        sendCameraCmdThread(cmdArr[i]);
                                    }
                                }
                            }
                        }, 100);
                        Log.i("TEST","======================>start time");
                        while (clientSocket!=null&&(size = cameraInputStream.read(buffers))!= -1) {
                            Log.i("TEST", "===================> receive msg: " +Utils.bytesToHexString(buffers));
                        }
                    } catch (Exception e) {
                    }
                } else {
                    Log.e("TEST","=================> cameraInputStream is null");
                }
            } else {

            }
        }
    } catch (Exception e) {

    } finally {
        Log.i("TEST","===================>Client Close!");
        if(timer!=null) {
            timer.cancel();
        }
        if (cameraOutputStream!=null) {
            try {
                cameraOutputStream.close();
                cameraOutputStream=null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (cameraInputStream!=null) {
            try {
                cameraInputStream.close();
                cameraInputStream = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (clientSocket!=null) {
            try {
                clientSocket.close();
                clientSocket=null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

SocketClient重新連接後,則使用Timer延時100毫秒後,則發送命令。這樣就能保證發送的命令成功。


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