Android socket在系統休眠情況下調研

來源:互聯網
上載者:User

Android socket在系統休眠情況下調研

做了3年的IM應用,一直沒有確認過socket在系統休眠的情況下會不會就收不到訊息了,網上也搜過一些資料說android手機分為AP和BP兩個部分,系統休眠的時候AP是休眠的,而BP是不休眠的,網路通訊協定棧是運行在BP層的,所以當BP收到資料包的時候,系統會喚醒AP,但是AP啟動並執行時間是很短的。雖然聽起來很有道理的樣子,但是沒有親手測試過,還是一塊心病~~~,今天又想起這事,索性動手自己寫代碼測試看看結果。

Server端code:
public class TestServer {    public static void main(String[] argv) {        ServerSocket serverSocket;        try {            serverSocket = new ServerSocket(4444);            Socket client;            while((client = serverSocket.accept()) != null) {                new ClientThread(client).start();            }        } catch (IOException e) {            e.printStackTrace();        }    }    public static class ClientThread extends Thread {        private Socket socket;        private OutputStream outputStream;        public ClientThread(Socket client) {            socket = client;            try {                outputStream = socket.getOutputStream();            } catch (IOException e) {                e.printStackTrace();            }        }        public void run() {            int index = 0;            while(true) {                try {                                        outputStream.write((hello+index+).getBytes());                    index++;                    System.out.println(send);                } catch (IOException e) {                    e.printStackTrace();                }                try {                    Thread.sleep(60*1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

代碼很簡單,Server每隔60s給client發送一句hello跟index序號。

Client端code:

public class TestActivity extends Activity {    private FileOutputStream outputStream = null;    private WakeLock mWakelock;    private Handler handler = new Handler() {        public void handleMessage(Message msg) {            try {                outputStream.write((new Date().toString() + ((String) msg.obj) +   savelocal)                        .getBytes());            } catch (IOException e) {                e.printStackTrace();            }//            releaseWakeLock();        }    };    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        new Thread(new Runnable() {            @Override            public void run() {                File file = new File(/sdcard/testlog-lock.txt);                if (file.exists()) {                    file.delete();                }                try {                    file.createNewFile();                } catch (IOException e2) {                    e2.printStackTrace();                }                try {                    outputStream = new FileOutputStream(file);                } catch (FileNotFoundException e2) {                    e2.printStackTrace();                }                try {                    Socket socket = new Socket();                    socket.connect(new InetSocketAddress(10.140.82.31, 4444));                    InputStream inputStream = socket.getInputStream();                    BufferedReader inputStream2 = new BufferedReader(new InputStreamReader(                            inputStream));                    String lineString;                    while ((lineString = inputStream2.readLine()) != null) {//                        acquireWakeLock();                        outputStream.write((new Date().toString() + lineString +  receive)                                .getBytes());                        Message msgMessage = handler.obtainMessage(1, lineString);                        handler.sendMessageDelayed(msgMessage, 5000);                    }                } catch (UnknownHostException e) {                              try {                        outputStream.write(e.getMessage().getBytes());                    } catch (IOException e1) {                                     e1.printStackTrace();                    }                } catch (IOException e) {                                       try {                        outputStream.write(e.getMessage().getBytes());                    } catch (IOException e1) {                                               e1.printStackTrace();                    }                }            }        }).start();    }    private void acquireWakeLock() {        if (mWakelock == null) {            PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);            mWakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lock);        }        mWakelock.acquire();    }    private void releaseWakeLock() {        if (mWakelock != null && mWakelock.isHeld()) {            mWakelock.release();        }        mWakelock = null;    }}

代碼也不複雜,Client啟動的時候會建立一個Thread去串連Server,每收到一個包就馬上往檔案裡寫入收到的內容和時間戳記,然後過5s後再次往檔案裡寫入相同的內容和時間戳記。為什麼要5s呢?因為我想驗證一下socket讀取到包之後,是不是運行一會就馬上又休眠了,如果是的,那麼5s後,第2次是不會準時寫入檔案的,因為系統休眠了,程式是不會執行的, Handler裡面的Message也就不能執行了。重要的地方是那句acquireWakelock和releaseWakelock, 如果wake了,那麼第2次寫入肯定是5s內完成。

    所以我們注釋wakelock和開啟wakelock測試兩次,驗證3件事情:

1. 系統休眠後還能不能收到包,
2. 收到包之後,注釋wakelock,是什麼行為,
3. 開啟wakelock,是什麼行為。

注意測試的時候要斷開usb,因為連著usb的時候手機是不會休眠的,然後運行App,把App放後台關閉手機螢幕,分別測試半小時,看看log來驗證下猜想。
下面是測試下次的Client的log,

1. 不加wakelock

1 Mon Jul 20 22:37:16 CDT 2015hello0 receive
2 Mon Jul 20 22:37:21 CDT 2015hello0 savelocal
3 Mon Jul 20 22:38:15 CDT 2015hello1 receive
4 Mon Jul 20 22:39:15 CDT 2015hello2 receive
5 Mon Jul 20 22:40:15 CDT 2015hello3 receive
6 Mon Jul 20 22:40:15 CDT 2015hello1 savelocal
7 Mon Jul 20 22:41:15 CDT 2015hello4 receive
8 Mon Jul 20 22:42:15 CDT 2015hello5 receive
9 Mon Jul 20 22:42:15 CDT 2015hello2 savelocal
10 Mon Jul 20 22:43:15 CDT 2015hello6 receive
11 Mon Jul 20 22:43:15 CDT 2015hello3 savelocal
12 Mon Jul 20 22:44:15 CDT 2015hello7 receive
13 Mon Jul 20 22:45:15 CDT 2015hello8 receive
14 Mon Jul 20 22:46:15 CDT 2015hello4 savelocal
15 Mon Jul 20 22:47:15 CDT 2015hello10 receive
16 Mon Jul 20 22:48:15 CDT 2015hello11 receive
17 Mon Jul 20 22:48:15 CDT 2015hello5 savelocal
18 Mon Jul 20 22:49:15 CDT 2015hello12 receive
19 Mon Jul 20 22:49:15 CDT 2015hello6 savelocal

這裡只貼了部分log,可以看到資料包都以每個60s的間隔收到了,但是那個5s後save的Message代碼並沒有按照5s的頻率執行,而是等到後續的包收到之後,程式被喚醒了一下,逮到個執行空隙執行了一下。

加wakelock

1 Mon Jul 20 23:27:37 CDT 2015hello0 receive
2 Mon Jul 20 23:27:42 CDT 2015hello0 savelocal
3 Mon Jul 20 23:28:37 CDT 2015hello1 receive
4 Mon Jul 20 23:28:42 CDT 2015hello1 savelocal
5 Mon Jul 20 23:29:37 CDT 2015hello2 receive
6 Mon Jul 20 23:29:42 CDT 2015hello2 savelocal
7 Mon Jul 20 23:30:37 CDT 2015hello3 receive
8 Mon Jul 20 23:30:42 CDT 2015hello3 savelocal
9 Mon Jul 20 23:31:37 CDT 2015hello4 receive
10 Mon Jul 20 23:31:42 CDT 2015hello4 savelocal
11 Mon Jul 20 23:32:37 CDT 2015hello5 receive
12 Mon Jul 20 23:32:42 CDT 2015hello5 savelocal
13 Mon Jul 20 23:33:37 CDT 2015hello6 receive
14 Mon Jul 20 23:33:42 CDT 2015hello6 savelocal
15 Mon Jul 20 23:34:37 CDT 2015hello7 receive

可以看到save的代碼是以5s的延遲之後保證得到了運行。

OK,結論:
1. 在系統休眠的情況下,socket是能準時收到包的
2. 收到包之後,程式馬上就會再次休眠,後續想要執行一段長時間的代碼,最好是擷取一下wakelock保證這些代碼能執行到,之後釋放wakelock。這個其實很像BroadcastReceiver,系統在onReceive函數執行期間是會自動幫我們擷取wakelock的,出了這個函數就會釋放wakelock,所以如果自己想要執行一段長時間的代碼,那麼就要自己擷取跟釋放wakelock, 或者Framework裡面有提供一個叫WakefulBroadcastReceiver替我們做了這些事情。

Note:我只測試了wifi的情況下,那個BP好像只是指radio跟wifi晶片不是一個東西,不過感覺跟3g的情況下應該差不多~~~改天試試看

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.