zoukankan      html  css  js  c++  java
  • 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的情况下应该差不多~~~改天试试看

  • 相关阅读:
    换肤动画
    手风琴动画图
    Ajax传值原理.aspx文档
    三层框架中单表的增删改查
    用ajax传JSON数据
    利用ajax进行post传值,登录QQ和密码代码
    ado.net增删改查及存储过程
    常用的SQL语句
    金融
    写你的简历应该注意什么
  • 原文地址:https://www.cnblogs.com/chenlong-50954265/p/5526039.html
Copyright © 2011-2022 走看看