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的情况下应该差不多~~~改天试试看

时间: 2024-08-28 16:45:49

socket在系统休眠情况下调研【转】的相关文章

Android socket在系统休眠情况下调研

做了3年的IM应用,一直没有确认过socket在系统休眠的情况下会不会就收不到消息了,网上也搜过一些资料说android手机分为AP和BP两个部分,系统休眠的时候AP是休眠的,而BP是不休眠的,网络协议栈是运行在BP层的,所以当BP收到数据包的时候,系统会唤醒AP,但是AP运行的时间是很短的.虽然听起来很有道理的样子,但是没有亲手测试过,还是一块心病~~~,今天又想起这事,索性动手自己写代码测试看看结果. Server端code: public class TestServer { public

Linux下使用fdisk命令和partprobe命令,在不重启系统的情况下新建分区并格式化

由于工作的需要,最近一段时间一直在学习Linux.学习一门新的知识,我是喜欢根据谋一本书或者某一个学习视频系统的学习,这样可以对学习的新知识有一个系统全面的认识和了解.所以学习之前,没了一本鸟哥的私房菜做为参考书,开始系统的学习Linux. 根据鸟哥的建议,安装虚拟机时,预留了一块空的容量用来练习分区使用.所以在虚拟机上安装Linux系统分区时,只划分了一块4G的容量挂载到根目录“/”下,还有就是只划分了一个2G的swap分区.还有14G的容量没有分配. 在学习磁盘管理时,使用fdisk将剩余的

【Linux】Centos7安装之后,双系统的情况下,怎么能在CentOS7下访问Windows的磁盘

想要在CentOS7下访问Windows的NTFS格式的磁盘,需要在Linux下下载ntfs-3g步骤1: 进入root用户下,使用yum命令下载ntfs-3g.[前提是已经添加了常用源:http://www.cnblogs.com/sxdcgaq8080/p/7516186.html] [[email protected] ~]$ su root 密码: [[email protected] sxd]# yum install ntfs-3g 已加载插件:fastestmirror, lang

如何在不重装win10系统的情况下将intel主板的RAID设置改为ACHI设置

刚装电脑的时候,为了数据的安全性,安装了两块3T机械硬盘,并且在intel主板中将磁盘设置为了raid0模式 结果用着发现raid问题很多 1.非正常关机后,重启完毕需要同步数据,非常耗时 2.无法准确看到硬盘smart信息,硬盘有报警了都不知道 3.噪音大,一块硬盘没什么感觉,两块硬盘一块动,就能很明显的听到噪音了 4.发热大,一块硬盘的时候不用考虑什么风道,但是两块硬盘就得仔细规划了 结论就是,本意是想使用raid0来保护数据,结果反倒会因为各种原因导致硬盘寿命降低,会对数据造成威胁 所以用

高并发情况下Linux系统及kernel参数优化

众所周知在默认参数情况下Linux对高并发支持并不好,主要受限于单进程最大打开文件数限制.内核TCP参数方面和IO事件分配机制等.下面就从几方面来调整使Linux系统能够支持高并发环境. Iptables相关 如非必须,关掉或卸载iptables防火墙,并阻止kernel加载iptables模块.这些模块会影响并发性能. 单进程最大打开文件数限制 一般的发行版,限制单进程最大可以打开1024个文件,这是远远不能满足高并发需求的,调整过程如下: 在#号提示符下敲入: # ulimit–n 6553

如何在不使用系统函数的情况下实现PHP中数组系统函数的功能

PHP中为我们提供了各种各样的系统函数来实现我们需要的各种功能,那么,在不使用系统函数的情况下我们要怎样来实现这些功能呢?以下就是几种系统函数的实现方式. 首先,我们来定义一个数组: $arr= array(1,2,3,4,5,6,"a"=>7,"b"=>8,"c"=>"haha",10); 以下是对于这个数组可以使用的系统函数和不使用系统函数获得同样效果的方式: 1.返回数组的所有的值,返回数组.(arra

DeskMini无传统机械键盘与鼠标接口的情况下使用U盘安装系统经验总结

总结安装纯净版Win7旗舰版系统安装过程所解决的问题要点: 1:UEFI引导启动的实现. 2:使用Dism++实现系统的安装. 3:使用Dism++解决新主板在安装系统过程中不能使用USB键盘和鼠标的问题. 解决过程: 准备工作: 去MSDN网站下载Win7SP1纯净版的ISO文件.(Windows 7 Ultimate with Service Pack 1 (x64) - DVD (Chinese-Simplified) : ed2k://|file|cn_windows_7_ultimat

在有win7操作系统的情况下安装linux的Centos6.3双系统

在win7下Linux (centos)的安装双系统 装法有两种.(太多了,第二不写了 ) 一.U盘安装 整个过程过程可分为三步. 1.从最后一个硬盘格式化一些空间出来,我的是格式100G, 方法: 在win7下右键点击"我的电脑",进入"管理",再进入"磁盘管理",找到F盘(我最后一个是F盘),点击右键,删除卷,在创建新卷:"30G",(格式为NTFS)(因为我的F盘130G),所以现在剩下100G是空的,别急,空的100G

CentOS系统在不重启的情况下为虚拟机添加新硬盘

一.概述 用过虚拟机的都知道,如果在系统运行的时候去给虚拟机添加一块新设备,比如说硬盘,系统是读取不到这个新硬盘的,因为系统在启动的时候会去检测硬件设备.但是我们也可能会遇到这样的情况,比如正在运行比较重要的程序,这时候不想重启linux系统,又需要添加一块新硬盘,该怎么办呢?今儿个就遇到这个情况,vmware上添加新硬盘,系统不识别,于是百度了一番,有很多文章,不过大多都是要设置lvm的,鄙人比较懒,不想做那么复杂,终于找到了一篇文件讲述如何不重启的情况下添加新硬盘并识别出来,于是乎操作了一般