1. 程式人生 > >Androin學習筆記四十二:Java android Socket通訊檢測(server)連線是否斷開

Androin學習筆記四十二:Java android Socket通訊檢測(server)連線是否斷開

Pre

在利用socket寫通訊程式的時候,想檢測伺服器是否還活著。

從網上找了很多資料,都沒有自己合適的,最後自己想了個辦法,不過也相當於截取了心跳檢測的一部分。

這裡檢測的是遠端server的連線,而不是本地是否連線成功。首先想到socket類的方法isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,但經過試驗並檢視相關文件,這些方法都是本地端的狀態,無法判斷遠端是否已經斷開連線。

而有一個方法sendUrgentData,檢視文件後得知它會往輸出流傳送一個位元組的資料,只要對方Socket的SO_OOBINLINE屬性沒有開啟,就會自動捨棄這個位元組。

或者,其實如果斷開連線了,你傳送過去的資料會收不到,最後client會丟擲io異常。

但是,上面兩個方法,丟擲異常的時間長達15秒!簡直不能忍。

解決思路

當然,這裡的需求環境是:傳送資料次數非常少,幾乎只需要判斷一兩次,資料是集中傳送的。那麼,就可以這樣了:

只要client在傳送資料前,先發送自定義的一個測試資料,並自定義一個String之類的變數(初始值null)來接收server發回的資料,client發完測試資料,睡500毫秒(自定義時間)(非同步接收伺服器訊息),然後立刻檢測這個string是不是null,就可以知道server是否收到訊息了。

程式碼

客戶端app上的部分程式碼


/**客戶端執行緒,用來建立連線和傳送訊息 */
    public class Client implements Runnable{
        Socket s=null;
        DataInputStream dis=null;
        DataOutputStream dos=null;

        private boolean isConnected=false;
        Thread receiveMessage=null;
        /**傳送訊息
         * @param str 傳送的資訊,client僅向server傳送兩次訊息,這是我自己的應用需求,根據實際情況來做你的。
         * @throws
IOException * */
public void sendMessage(String str) throws IOException{ dos.writeUTF(str); dos.flush(); } /**斷開連線*/ public void disConnect(){ try { dos.close(); dis.close(); s.close(); } catch (IOException e) { System.out.println("client closed error"); e.printStackTrace(); } } /**建立socket連線,開啟接收資料執行緒 * */ public void run() { try { s=new Socket(SERVER_HOST_IP,SERVER_HOST_PORT); s.setOOBInline(true); dis=new DataInputStream(s.getInputStream()); dos=new DataOutputStream(s.getOutputStream()); System.out.println("connected!"); isConnected=true; receiveMessage=new Thread(new ReceiveListenerThread()); receiveMessage.start(); //傳送imei sendMessage(IMEI); } catch (UnknownHostException e) { System.out.println("fuwuqoweikaiqi"); e.printStackTrace(); } catch (IOException e) { System.out.println("ioerr"); e.printStackTrace(); } } private class ReceiveListenerThread implements Runnable{ //這一部分接收資料的處理,請根據實際情況修改 String data[]=new String[3]; public void run() { try { if(isConnected){ String receivedMessage=dis.readUTF(); System.out.println(receivedMessage); serverStarted=true; data=receivedMessage.split("_"); isLegal=Integer.parseInt(data[0]); num1=Integer.parseInt(data[1]); num2=Integer.parseInt(data[2]); System.out.println(""+isLegal+num1+""+num2); } if(isConnected){ finalOK=dis.readUTF(); } }catch (SocketException e){ System.out.println("exit!"); } catch (IOException e) { e.printStackTrace(); } } }

呼叫:

Client client=null;
/**客戶端網路執行緒*/
Thread tClient=null;
client=new Client();
tClient=new Thread(client);
tClient.start();

伺服器上:


/** 這是伺服器用來接收處理客戶端的執行緒類 */
    class Client implements Runnable {
        private Socket s;
        private DataInputStream dis = null;
        private DataOutputStream dos = null;
        private boolean isConnected = false;
        public Client(Socket s) {
            this.s = s;
            try {
                dis = new DataInputStream(s.getInputStream());
                dos = new DataOutputStream(s.getOutputStream());
                isConnected = true;
            } catch (IOException e) {
                System.out.println("on clients' data in and out have error");
                // e.printStackTrace();
            }
        }
        public void run() {
            String str;
            try {
                // 先檢查是否是合法的客戶端
                while (isConnected) {
                    str = dis.readUTF();
                        str = dis.readUTF();
                        //此處的具體程式碼省略
                        dos.writeUTF("ok");
                        dos.flush();
                    }
                }
            } catch (EOFException e) {
                System.out.println("Client closed");
                Home.appendMessage((legalNum + 1) + "號客戶端已經登出");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (dis != null)
                        dis.close();
                    if (dos != null)
                        dos.close();
                    if (s != null)
                        s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

客戶端判斷伺服器是否還活著程式碼:

try {
    //客戶端傳送一個測試資訊
        client.sendMessage(cookie);
        System.out.println("send");
        //睡1秒
        SystemClock.sleep(1000);
        //這個finalok是在客戶端的接收執行緒那裡處理的。如果不是null說明伺服器沒問題
        if(finalOK!=null){
            client.disConnect();
            exit("感謝您的使用,本次已經結束~"); 
        }else{
            throw new  IOException() ;
        }
        //超時檢測
    } catch (IOException e) {
        new AlertDialog.Builder(MainActivity.this).setTitle("提示").setPositiveButton("好的", null).setMessage("伺服器關閉了,請聯絡管理員並在伺服器重新開啟後再次點選【傳送】來提交資料").show();
        client.disConnect();
        e.printStackTrace();
    }