Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

Qt+Caffe+OpenCV——【一个基于VGG网络的人脸识别考勤系统】

$
0
0

前言

将PC端的一个基于深度学习的考勤系统的初版在这里发一发,会不断的更新。这一次的代码比以往的有一个【基于深度学习的人脸识别系统】要更加简洁完善,并且外带了GUI,可以移植到USB摄像头,正在开发连接网络摄像头的接口。

DEMO

登录界面:
这里写图片描述
系统初始:
这里写图片描述
进行注册的时候:
这里写图片描述
这里写图片描述
进行识别的时候:
这里写图片描述
这里写图片描述

当然,这个里面还有人脸文件、标注的存取等功能,识别的时候暂时没有开发同时识别多个人脸,要写上去也是可以的。

难点

这个是一个初级的版块。GUI做的肯定要改改,然后说说碰到的几个问题。
1、使用多线程在Qt下实时候的人脸检测;
2、人脸识别时候的一些依赖Caffe的代码;
3、Qt这块也是刚刚接触,语法不熟悉。

总的来说,Qt做界面还是比MFC舒服多了,打算把这个一步一步来记录,边开发边总结。

作者:Mr_Curry 发表于2016/12/19 21:41:42 原文链接
阅读:27 评论:0 查看评论

从零开始学习Android开发-Android概览

$
0
0

        没有开发过Android、IOS等移动端的开发,记录从零开始学习Android开发历程。学过、用过那么多的语言、开发模式却很少留下记录,一方面是由于曾经的工作环境影响,网络受控;一方面是自己长久以来对文字的尊重,总以为非深思熟虑不能成文,非别具匠心不可以发表;还有就是自己的懒惰,懒得动笔。

人的状态总还是多少受环境影响的,时得清闲,又对Android有几分兴趣,虽然Android已经发展多年,现在学习Android可能太晚,但我不求先行,只求窥其一斑;不求文章准确精美,只求雁过留声。记录下学习Android的过程,若是能给路人的带来点启发,那就是无意间点积德善举,若是错误百出,那也不要怨言,因为每片博文均一气写成,逻辑、文字错误均没检查,甚至写完后再没有看过,我本就把博文当做随笔,留个纪念而已。

我这人学东西一般是不求甚解,无论什么语言,什么框架均喜欢先学习整个结构如何,事件如何处理、数据如何存储、界面如何展示、各页面如何调用等。正如每次买到一本新书,总喜欢把先把目录和前言好好看看,有个大概的映像再去分解阅读。我这样的人往往难得深入,一般是了解结构、方法,遇到问题再由点解决问题,就好像是一座楼房只建了框架,哪层卖出去了才建哪层的围墙,从外看来,不是栋美观高上大楼房,但也不会影响居住,总是难得讨人喜欢罢了。

Android这些年来积累的学习资源可为丰富至极,但我一般还是喜欢看官网的资料,一来准确,二来权威。所幸Android的官网资料丰富,不久有讲解,还有实例(Android Studio中可以直接导入example),大部分还有中文说明,真是方便。开发工具当然选的是Android Studio,Google已经宣称不再支持Eclipse的Android插件了。Android开发的官网是:https://developer.android.com/guide/index.html。学习的方式也按我以往的基本步骤:官网基础知识,典型开发模式和开发框架,典型实例、调试、测试、打包及更新,自定义Demo。

在官网目录中有Training和Api Guides两个目录,我大略看了一下,可能在学习过程中以Api Guides为主,部分例子可参考Training和Samples。

如官网所说:Android 提供了一个内容丰富的应用框架,支持您在 Java 语言环境中为移动设备开发创新应用和游戏。Android不仅仅应用于我们熟知的Pad、Phone,还应用于智能终端、各类传感器等多种移动终端。

Android应用提供多个入口点:Android 应用都是将各种可单独调用的不同组件加以组合开发而成。例如,组件可以是为用户界面提供一个屏幕的单个“Activity”,也可以是在后台独立执行工作的“服务”。这一点真的很吸引人,在一般的应用中只有唯一的入口,如VC、VB等应用只有一个入口main函数。在Android中都是组件化的,每个组件可以相互独立,又可以相互调用组合完成一个完整的事务,我感觉现在逐渐升温的微服务以及云计算里的Dock采用了相似的思路,将功能独立化,不仅使得节约了开发成本,也提高系统健壮性,可测性,好处多多。嗯,我不禁迫切想知道组件之间是如何独立运行又相互调用的。

Android操作系统是一种多用户的Linux系统,Android应用采用Java语言编写,最终应用将数据、代码和资源一起编译到一个.apk的存档文件。一个应用以不同的Linux用户,具有唯一的Linux用户ID,只能访问本用户资源,如果希望多个应用访问共同资源可以采用以下方法:

1.为不同应用设置同一Linux 用户id

2.通过调用其他组件访问相关资源

Android有四类组件:

1.Activity

主要用于用户界面展示

2.Service

用于在后台长时间运行,没有界面,跟Windows等后台服务类似。

3.ContentProvider

  主要用于数据等存取,如:文件系统、SQLite 数据库、网络上或您的应用可以访问的任何其他永久性存储位置。

4.BroadcaseReceive

用于响应系统等各类消息。

如何启动组件?

四种组件类型中的三种 — Activity、服务和广播接收器 — 通过名为 Intent 的异步消息进行启动。组件间相互调用,主要依赖于Intent。各组件调用等方法不同,但都通过Intent传递数据。

1.Activity启动方法

  • 直接调用采用startActivity(),
  • 需要获取返回值采用startActivityForResult()

2.Service启动方法

  • 直接启动采用startService(),
  • 需要绑定该服务采用bindService(),即启动者销毁,绑定的服务同时销毁。

3.BroadCast启动方法

通过sendBroadcast(),sendOrderedBroadcast() 或 sendStickyBroadcast() 等方法来发起广播

4.ContentResolver调用方法

采用query()调用。

Android项目文件目录

1.mainfests

项目文件清单:声明项目中的各个组件,组件的访问权限等。

2.java

项目的源码目录:包括源码、测试代码

3.res

项目资源文件:包括页面布局、本地化设置、全局的字符串定义、图标等。





作者:loveu2000000 发表于2016/12/19 21:56:30 原文链接
阅读:31 评论:0 查看评论

Gradle 1.12用户指南翻译——第五十二章. Maven 插件

$
0
0
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见:
http://blog.csdn.net/column/details/gradle-translation.html
翻译项目请关注Github上的地址:
https://github.com/msdx/gradledoc
本文翻译所在分支:
https://github.com/msdx/gradledoc/tree/1.12。
直接浏览双语版的文档请访问:
http://gradledoc.qiniudn.com/1.12/userguide/userguide.html。
另外,Android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,目前0.5版本兼容 Android 2.3以上系统,项目地址如下:
https://github.com/msdx/gradle-doc-apk
翻译不易,转载请注明本文在CSDN博客上的出处:
http://blog.csdn.net/maosidiaoxian/article/details/53749725

关于我对Gradle的翻译,以Github上的项目及http://gradledoc.qiniudn.com 上的文档为准。如发现翻译有误的地方,将首先在以上两个地方更新。因时间精力问题,博客中发表的译文基本不会同步修改。

另外,目前Gradle1.12版本的文档我电脑上已经翻译到第六十三章,所以该版本的翻译也进入校稿阶段,校稿的方式可以为到该项目https://github.com/msdx/gradledoc 提交issue或者是pull request。校稿的结果不只是在此版本更新,也会用于改善Gradle下一版本(2.0)文档的翻译。


第五十二章. Maven 插件

此章节还在完善中。

Maven 插件添加了将项目部署到 Maven 仓库的支持。

52.1. 用法

要使用 Maven 插件,请在构建脚本中包含以下语句:

示例 52.1. 使用 Maven 插件

build.gradle

apply plugin: 'maven'

52.2. 任务

Maven 插件定义了以下任务:

表 52.1. Maven 插件 - 任务

任务名称依赖于类型描述
install所有构建相关archives的任务。Upload将相关的构件安装到本地的 Maven 缓存,包括 Maven 元数据的生成。默认情况下 install 任务是与archives配置相关联的。该项配置在默认情况下只包含默认的 jar 文件。要了解更多关于安装到本地资源库的内容,请参阅:第 52.6.3 节,“安装到本地仓库”

52.3. 依赖管理

Maven 插件不定义任何依赖配置。

52.4. 约定属性

Maven 插件定义了下列约定属性:

表 52.2. Maven 插件 - 属性

属性名称类型默认值描述
pomDirNameStringpoms相对于构建目录,用于写入生成的POM的文件夹路径。
pomDirFile (read-only)buildDir/pomDirName生成的POM所写入的目录。
conf2ScopeMappingsConf2ScopeMappingContainern/a将Gradle配置映射到Maven scopes的说明。见 52.6.4.2 节,“依赖映射”

这些属性由一个MavenPluginConvention 的约定对象提供。

52.5. 约定方法

Maven 插件提供了用于创建 POM 的工厂方法,如果你需要一个 POM 文件但是没有上传到 Maven 仓库的场景,这个工厂方法将非常有用。

示例 52.2. 创建一个单独的 pom。

build.gradle

task writeNewPom << {
    pom {
        project
            inceptionYear '2008'
            licenses {
                license {
                    name 'The Apache Software License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    distribution 'repo'
                }
            }
        }
    }.writeTo("$buildDir/newpom.xml")
}

除其他事项外,Gradle支持和polyglot Maven同样的生成器语法。如果要了解关于 Gradle Maven POM 对象的更多信息,请参阅MavenPom。请参见: MavenPluginConvention

52.6. 与 Maven 仓库的交互

52.6.1. 介绍

通过 Gradle你可以部署到远程 Maven 仓库,或者是安装到你的本地 Maven 仓库。这包括所有的 Maven 元数据操纵,并且 Maven snapshot一样可用。事实上,Gradle 的部署是 100%兼容 Maven的,因为我们在hood下使用的是本地的 Maven Ant 任务。

如果你没有一个POM文件,部署到 Maven 仓库只有一半的乐趣。幸运的是 Gradle 可以使用它的依赖信息为你生成这个 POM。

52.6.2. 部署到 Maven 仓库

让我们假设你的项目只是产生默认的 jar 文件。现在你想要将这个 jar 文件部署到远程 Maven 仓库。

示例 52.3. 上传文件到远程 Maven 仓库

build.gradle

apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
        }
    }
}

就这些了。调用uploadArchives任务将生成 POM,并将部署构件和 POM 到指定的仓库。

如果你需要支持文件之外的其他协议,那么你还需要再做一些事情。在这种情况下,我们必须将委派本地的Maven代码给第三方库实现。具体是哪些库,将取决于你需要的协议。表 52.3. “Maven 部署的协议jar”列出了可用的协议以及相应的库(这些库又有具有传递依赖,而这些依赖也有其自己的传递依赖)。[19] 举个例子,要使用ssh协议,你可以:

示例 52.4. 通过 SSH 上传文件

build.gradle

configurations {
    deployerJars
}

repositories {
    mavenCentral()
}

dependencies {
    deployerJars "org.apache.maven.wagon:wagon-ssh:2.2"
}

uploadArchives {
    repositories.mavenDeployer {
        configuration = configurations.deployerJars
        repository(url: "scp://repos.mycompany.com/releases") {
            authentication(userName: "me", password: "myPassword")
        }
    }
}

Maven deployer有很多配置选项。这个配置通过一个 Groovy builder 来完成。这个配置树的所有元素都是 Java beans。你可以传一个map到bean元素中,来配置简单的属性。如果要添加另一个bean元素到它的parent,你可以使用一个闭包。在上例中repositoryauthentication都是这样的 bean 元素。表 52.4,"MavenDeployer 的配置元素"列出了可用的 bean 元素,以及 javadoc 中相应类的链接。在javadoc 中你可以看到可能的属性,这些属性你可以设置为特定的元素。

在 Maven 中你可以定义仓库和snapshot仓库。如果没有定义任何snapshot 仓库,release和snapshot都将部署到repository元素中。否则,snapshots将部署到snapshotRepository元素中。

表 52.3. Maven 部署的协议 jars

协议Library
httporg.apache.maven.wagon:wagon-http:2.2
sshorg.apache.maven.wagon:wagon-ssh:2.2
ssh-externalorg.apache.maven.wagon:wagon-ssh-external:2.2
ftporg.apache.maven.wagon:wagon-ftp:2.2
webdavorg.apache.maven.wagon:wagon-webdav:1.0-beta-2
file-

52.6.3. 安装到本地仓库

Maven 插件将install任务添加到你的项目。这个任务依赖于archives配置的所有archives任务。它将这些archives安装到你的本地 Maven 仓库中。本地仓库的默认位置是否在 Maven settings.xml中被重新定义,这项任务也会考虑到。

52.6.4. Maven POM 生成

当部署一个artifact 到一个 Maven 库时,Gradle 会自动为它生成一个POM。下表展示了用于POM的groupIdartifactIdversionpackaging元素的默认值。这些dependency元素由project 的依赖声明所创建。

表 52.5. Maven POM 生成的默认值

Maven 元素默认值
groupIdproject.group
artifactIduploadTask.repositories.mavenDeployer.pom.artifactId(如果有设置的话)或archiveTask.baseName.
versionproject.version
packagingarchiveTask.extension

在这里, uploadTaskarchiveTask分别指向上传和分别生成archive的任务(例如uploadArchivesjar)。archiveTask.baseName默认为project.archivesBaseName,后者默认为project.name

当你将archiveTask.baseName设置为非默认值时,请确保将uploadTask.repositories.mavenDeployer.pom.artifactId设置为相同的值。否则,在相同的构建中,这个项目可能会被其他项目所生成的POMs 中错误的 artifact ID所引用到。

生成的 POMs 可以在<buildDir>/poms看到。它们可以通过MavenPom API 进一步定制化。例如,你可能希望部署到 Maven 仓库中的artifact 有不同的版本,或者是不同于 Gradle 生成的artifact 的名称。如果要自定义这些你可以这样做:

示例 52.5. pom定制

build.gradle

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
            pom.version = '1.0Maven'
            pom.artifactId = 'myMavenName'
        }
    }
}

如果要向 POM 添加其他的内容,可以使用pom.project 生成器。通过这个生成器,Maven POM 参考中列出的任何元素都可以被添加进来。

示例 52.6. pom 的生成器类型自定义

build.gradle

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
            pom.project {
                licenses {
                    license {
                        name 'The Apache Software License, Version 2.0'
                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        distribution 'repo'
                    }
                }
            }
        }
    }
}

注:groupIdartifactIdversionpackaging应该始终直接在pom对象上设置。

示例 52.7. 修改自动生成的内容

build.gradle

[installer, deployer]*.pom*.whenConfigured {pom ->
    pom.dependencies.find {dep -> dep.groupId == 'group3' && dep.artifactId == 'runtime' }.optional = true
}

如果你有超过一个的artifact 要发布,那么要做的事情就会有些不同。请参阅第 52.6.4.1 节,“一个项目多个构件”

要为 Maven installer(见第 52.6.3 条,“安装到本地资源库”) 自定义设置,你可以:

示例 52.8. Maven installer 的自定义

build.gradle

install {
    repositories.mavenInstaller {
        pom.version = '1.0Maven'
        pom.artifactId = 'myName'
    }
}

52.6.4.1. 一个项目多个构件

Maven 只可以处理一个项目一个构件。这也反映在 Maven POM 的结构中。我们认为在很多情况下,有意义一个项目有超多一个的构件。在这种情况下,你需要生成多个 POMs。在这种情况下,你必须显式声明你想要发布到一个 Maven 仓库的每一个构件。MavenDeployer和 MavenInstaller 都为此提供了一个 API:

示例 52.9. 多个 poms 的生成

build.gradle

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
            addFilter('api') {artifact, file ->
                artifact.name == 'api'
            }
            addFilter('service') {artifact, file ->
                artifact.name == 'service'
            }
            pom('api').version = 'mySpecialMavenVersion'
        }
    }
}

你需要为你想发布的每一个构件声明一个过滤器。这个过滤器为每一个它接受的 Gradle 构件定义了一个布尔表达式。每个过滤器都有一个你可以进行配置的POM与它关联。要了解更多关于它的信息,你可以看一下PomFilterContainer和其关联的类。

52.6.4.2. 依赖映射

Maven 插件配置了由Java插件和War插件添加的Gradle configurations 与Maven scopes之间的默认映射。大多数情况下你不需要去接触它,并且你可以安全地跳过本节。映射过程像下面所示。你可以把一个configuration映射到一个并且只能是一个scope上。不同的configurations可以映射到一个或不同的scopes。一个configuration可以指定到一个特定的 configuration-to-scope 映射的优先级。你可以参考Conf2ScopeMappingContainer来了解更多的信息。要访问映射配置,你可以:

示例 52.10. 访问映射配置

build.gradle

task mappings << {
    println conf2ScopeMappings.mappings
}

如果有可能,Gradle排除的规则会被转换为Maven excludes。如果 Gradle 排除规则中group和module名字被指定的话(相比于Ivy,Maven对这两个都需要),这种转换是可能的。每一个configuration的排除规则如果可以被转换的话,也会包含在Maven POM中。



[19已经计划在将来的发行版中为其提供开箱即用的支持。


作者:maosidiaoxian 发表于2016/12/19 22:13:47 原文链接
阅读:21 评论:0 查看评论

三、网络评分机制

$
0
0

在前两节简单介绍了连接管理的大致框架,数据链接的准备工作,包括APN的初始化与默认APN使能,DcTracker的构造,包括各种事件的注册等工作。但是数据链接的打开不止是只有用户主动去打开,Android可以提供数据业务的对象主要有,移动数据网络、WIFI、蓝牙、网线等,这些连接本身都可以独立使用,但是对于用户来说,每一时刻又最多只能使用一种方式接入网络,那么当这些功能同时打开时,比如即使用户打开了移动数据连接,但是又打开了wifi,那么只要wifi畅通,移动数据链接是不会用于上网的,那究竟如何选择最佳的接入环境呢?这就需要提供一个能够动态管理他们的打开与断开的功能,Android专门设计了一套管理方法来实现上面的这种机制,包括ConnectivityManager、ConnectivityService、NetworkAgent等对象之间的关系以及消息流走向,本节在这些知识的基础上介绍连接管理的核心机制,即连接管理中的评分机制,其中ConnectivityService是管理员身份,没种网络都会去向它注册,网络的使用权全靠它来分配。

连接管理通过一个评分机制来实现不同接入方式的选择。具体来说就是,每一种上网方式在初始化时,都向ConnectivityService标明自己网络的分值(比如数据连接50,WIFI60,蓝牙69,网线70),当有更高分数的网络就绪时,就将当前分值低的连接断开。而当当前网络被断开时,就寻找当前就绪的其他网络连接,选取分值高的进行接入。并且,每一个网络接入时,都会进行有效性检测,如果检测不通过,将会被扣掉一定分数,此时该网络的优先级也会相应的下降。下面我们利用三个部分来分析评分机制的原理:
1、NetworkFactory
2、NetworkAgent
3、NetworkMonitor
其中NetworkFactory是每一种网络持有一个,比如WIFI和Telephony会分别注册一个,但是NetworkAgent和NetworkMonitor是一种数据类型就会有一个,比如数据连接总的APN TYPE有8种,其中任意一种链接上之后都会各注册一个。

1、NetworkFactory

NetworkFactory直译就是网络工厂,开机之后每种网络都必须注册自己的NetworkFactory,NetworkFactory的作用是用来创建NetworkAgent,同时作为ConnectivityService与网络之间的通讯枢纽

private DctController(PhoneProxy[] phones) {
    for (int i = 0; i < mPhoneNum; ++i) {
        // Register for radio state change
        PhoneBase phoneBase = (PhoneBase)mPhones[i].getActivePhone();
        updatePhoneBaseForIndex(i, phoneBase);
    }
}    

private void updatePhoneBaseForIndex(int index, PhoneBase phoneBase) {
    phoneBase.getServiceStateTracker().registerForDataConnectionAttached(mRspHandler,
               EVENT_DATA_ATTACHED + index, null);
    phoneBase.getServiceStateTracker().registerForDataConnectionDetached(mRspHandler,
               EVENT_DATA_DETACHED + index, null);

    mNetworkFilter[index] = new NetworkCapabilities();
    mNetworkFilter[index].addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_RCS);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);

    mNetworkFactory[index] = new TelephonyNetworkFactory(this.getLooper(),
            mPhones[index].getContext(), "TelephonyNetworkFactory", phoneBase,
            mNetworkFilter[index]);
    mNetworkFactory[index].setScoreFilter(50);
    mNetworkFactoryMessenger[index] = new Messenger(mNetworkFactory[index]);
    cm.registerNetworkFactory(mNetworkFactoryMessenger[index], "Telephony");
}

可以看出来一个NetworkFactory 支持多种网络类型(NetworkCapabilities),网络类型与APN的TYPE相对应。
以移动数据网络为例,TelephonyNetworkFactory 将会继承NetworkFactory ,并重写其中两个重要的方法,needNetworkFor和releaseNetworkFor,这两个方法就是ConnectivityService与移动网络之间桥梁,分别负责请求当前网络和断开当前网络。

private class TelephonyNetworkFactory extends NetworkFactory {
    protected void needNetworkFor(NetworkRequest networkRequest, int score) {
        // figure out the apn type and enable it
        if (!SubscriptionManager.isUsableSubIdValue(mPhone.getSubId())) {
            mPendingReq.put(networkRequest.requestId, networkRequest);
            return;
        }
        if (getRequestPhoneId(networkRequest) == mPhone.getPhoneId()) { 
            DcTrackerBase dcTracker =((PhoneBase)mPhone).mDcTracker;
            String apn = apnForNetworkRequest(networkRequest);
            if (dcTracker.isApnSupported(apn)) {
                requestNetwork(networkRequest, dcTracker.getApnPriority(apn));
            }
        } else {
            mPendingReq.put(networkRequest.requestId, networkRequest);
        }
    }  
    protected void releaseNetworkFor(NetworkRequest networkRequest) {
        if (!SubscriptionManager.isUsableSubIdValue(mPhone.getSubId())) {
            mPendingReq.remove(networkRequest.requestId);
            return;
        }
        if (getRequestPhoneId(networkRequest) == mPhone.getPhoneId()) { 
            DcTrackerBase dcTracker =((PhoneBase)mPhone).mDcTracker;
            String apn = apnForNetworkRequest(networkRequest);
            if (dcTracker.isApnSupported(apn)) {
                releaseNetwork(networkRequest);
            }
        }
    }     

再看NetworkFactory 的注册cm.registerNetworkFactory(mNetworkFactoryMessenger[index], “Telephony”);其中mNetworkFactoryMessenger是一个包装了mNetworkFactory的Messenger对象,这个主要是建立AsyncChannel通道时用。

@ConnectivityService.java
public void registerNetworkFactory(Messenger messenger, String name) {
    enforceConnectivityInternalPermission();
    NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
    mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
}

handleRegisterNetworkFactory处理EVENT_REGISTER_NETWORK_FACTORY消息

private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
    mNetworkFactoryInfos.put(nfi.messenger, nfi);
    nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
}

在这里,ConnectivityService做了两个事情:
1、将新注册的NetworkFactoryInfo 保存到mNetworkFactoryInfos中;
2、利用刚才创建的AsyncChannel向NetworkAgent发起单向连接请求;
nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);即利用传入的Messenger对象建立起ConnectivityService与NetworkFactory的通讯通道,ConnectivityService后续的消息都将通过这个asyncChannel传入到数据网络中的NetworkFactory。
当asyncChannel通道建立成功后ConnectivityService会收到CMD_CHANNEL_HALF_CONNECTED消息。

@Override
public void handleMessage(Message msg) {
    NetworkInfo info;
    switch (msg.what) {
        case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
            handleAsyncChannelHalfConnect(msg);
            break;
        }
}
private void handleAsyncChannelHalfConnect(Message msg) {
    AsyncChannel ac = (AsyncChannel) msg.obj;
    if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {  //此时是链接的是NetworkFactory,走这个path
        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
            // A network factory has connected.  Send it all current NetworkRequests.
            for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                if (nri.isRequest == false) continue;
                NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
                ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,(nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
            }
        } else {
            mNetworkFactoryInfos.remove(msg.obj);
        }
    } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {

    }
}

此时是链接的是NetworkFactory,走这个path,mNetworkFactoryInfos是在handleRegisterNetworkFactory时保存的。
在这里,ConnectivityService通过AsyncChannel通道向当前的NetworkFactory发起CMD_REQUEST_NETWORK的请求,需要注意的是,该请求所附带的第二个参数选择,由于当前处于初始化阶段,因此当前的mNetworkForRequestId中为空,也就是说此时传递的第二个参数必然为0。
我们接下来看NetworkFactory收到该请求时的处理:

@NetworkFactory.java
public void handleMessage(Message msg) {
    switch (msg.what) {
        case CMD_REQUEST_NETWORK: {
            handleAddRequest((NetworkRequest)msg.obj, msg.arg1);
            break;
        }
    }
}
private void handleAddRequest(NetworkRequest request, int score) {
    NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
    if (n == null) {
        if (DBG) log("got request " + request + " with score " + score);
        n = new NetworkRequestInfo(request, score);
        mNetworkRequests.put(n.request.requestId, n);
    } else {
        n.score = score;
    }
    evalRequest(n);
}

接下来评估网络评分,是需要链接网络还是断开网路

private void evalRequest(NetworkRequestInfo n) {
    if (n.requested == false && n.score < mScore &&
            n.request.networkCapabilities.satisfiedByNetworkCapabilities(
            mCapabilityFilter) && acceptRequest(n.request, n.score)) {
        needNetworkFor(n.request, n.score);
        n.requested = true;
    } else if (n.requested == true &&
            (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(
            mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
        releaseNetworkFor(n.request);
        n.requested = false;
    } 
}

该逻辑就是整个网络评价系统最关键的地方,如果NetworkRequestInfo没有被requested过,并且其分值(n.score)小于当前NetworkFactory自己的分值(mScore),那么就说明,当前NetworkFactory所处的网络优先级高于其他网络的优先级,就会触发当前NetworkFactory所在网络的needNetworkFor()流程,也就是连接建立流程,并将标记NetworkRequestInfo.requested=true。
当NetworkRequestInfo被requested过(也就是当前网络被needNetworkFor过),此时如果再次收到请求,并且携带的新score大于当前NetworkFactory所处网络的mScore,那么就说明当前NetworkFactory所在网络优先级已经不是最高,需要将其releaseNetworkFor掉,并标记NetworkRequestInfo.requested=false。

evalRequest中调用TelephonyNetworkFactory 重写的needNetworkFor或者releaseNetworkFor,分别是链接网络和断开网络,后续的流程如下图(请求网络的情况)
这里写图片描述
在此数据链接的NetworkFactory算是创建完毕,并将自己注册到ConnectivityService中。

2、NetworkAgent

前面提到NetworkFactory是在系统初始化时就被创建,而NetworkAgent是在真正接入网络时才会创建,NetworkAgent的创建在DataConnection状态机里的DcActiveState状态时。

private class DcActiveState extends State {
    @Override public void enter() {
        // If we were retrying there maybe more than one, otherwise they'll only be one.
        notifyAllOfConnected(Phone.REASON_CONNECTED);

        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED,
                mNetworkInfo.getReason(), null);
        mNetworkInfo.setExtraInfo(mApnSetting.apn);
        updateTcpBufferSizes(mRilRat);

        final NetworkMisc misc = new NetworkMisc();
        misc.subscriberId = mPhone.getSubscriberId();
        mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
                "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,
                50, misc);
    }
}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
        NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
    super(looper);

    mContext = context;
    ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
            Context.CONNECTIVITY_SERVICE);
    cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
            new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
}  

当网络链接完成之后,就会新建一个DcNetworkAgent,接着分析NetworkAgent的构造,和NetworkFactory类似,也是将自己注册到ConnectivityService中去,继续看registerNetworkAgent

public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
        LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
        int currentScore, NetworkMisc networkMisc) {

    NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
        new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
        new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,
        new NetworkMisc(networkMisc), mDefaultRequest);
    synchronized (this) {
        nai.networkMonitor.systemReady = mSystemReady;
    }
    mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
}

private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
    mNetworkAgentInfos.put(na.messenger, na);
    assignNextNetId(na);
    na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
    NetworkInfo networkInfo = na.networkInfo;
    na.networkInfo = null;
    updateNetworkInfo(na, networkInfo);
}

在这里,ConnectivityService做了三个事情:
1、将新注册的NetworkAgentInfo保存到mNetworkAgentInfos中;
2、利用刚才创建的AsyncChannel向NetworkAgent发起单向连接请求;
3、更新最新的NetworkAgentInfo状态;

@Override
public void handleMessage(Message msg) {
    NetworkInfo info;
    switch (msg.what) {
        case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
            handleAsyncChannelHalfConnect(msg);
            break;
        }
}

以上流程和NetworkFactory注册时几乎一模一样的模式

private void handleAsyncChannelHalfConnect(Message msg) {
    AsyncChannel ac = (AsyncChannel) msg.obj;
    if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {  

    }  else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {  //此时是链接的是NetworkAgent,走这个path
        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
            // A network agent has requested a connection.  Establish the connection.
            mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
                    sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
        } 
    }
}

唯一的区别是在handleAsyncChannelHalfConnect中这里,当ConnectivityService与NetworkAgent之间单向通道建立完成后,又发起了双向通道的请求,此时在NetworkAgent端,将会收到CMD_CHANNEL_FULL_CONNECTION的消息,建立双向通道的目的是,有时候网络也需要通过AsyncChannel向ConnectivityService发送消息。至此,NetworkAgent的初始化完毕。
现在的问题是NetworkAgent如何影响网络链接的?
NetworkAgent提供了两种方法更新评分管理:
1、sendNetworkScore

public void sendNetworkScore(int score) {
    queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));
}

2、sendNetworkInfo

public void sendNetworkInfo(NetworkInfo networkInfo) {
    queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
}

先来分析第二种情况,比如移动数据网络的断开时就会调用此方法:

@DataConnection.java
private class DcActiveState extends State {
    public void exit() {
        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
                mNetworkInfo.getReason(), mNetworkInfo.getExtraInfo());
        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
        mNetworkAgent = null;
    }
}

接着就会进入ConnectivityService

@Override
public void handleMessage(Message msg) {
    NetworkInfo info;
        case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
            NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
            info = (NetworkInfo) msg.obj;
            updateNetworkInfo(nai, info);
            break;
        }
}
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
    if (state == NetworkInfo.State.CONNECTED && !networkAgent.created) {

    } else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) {
        networkAgent.asyncChannel.disconnect();        
    }   

由于是断开数据网络,因此这里是断开AsyncChannel,从而进入

AsyncChannel.CMD_CHANNEL_DISCONNECTED
        @Override
        public void handleMessage(Message msg) {
            NetworkInfo info;
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
                    handleAsyncChannelDisconnected(msg);
                    break;
                }
        }
private void handleAsyncChannelDisconnected(Message msg) {  
    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);  
    if (nai != null) {  
        //删掉当前NetworkAgent对象  
        mNetworkAgentInfos.remove(msg.replyTo);  
        final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();  
        for (int i = 0; i < nai.networkRequests.size(); i++) {  
            NetworkRequest request = nai.networkRequests.valueAt(i);  
            NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);  
            if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {  
                mNetworkForRequestId.remove(request.requestId);  
                //将0分更新到各个NetworkFactory中  
                sendUpdatedScoreToFactories(request, 0);  
            }  
        }  
    }  
}  
private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
    for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
        nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0,networkRequest);
    }
}

在这里,由于当前连接是断开状态,因此其分值必然为0,这样就把他的0分值通知到各个NetworkFactory中,由NetworkFactory判断是否需要开启自己的网络,通知方法同样是CMD_REQUEST_NETWORK,也就是说,无论是直接更新NetworkAgent中的分数,还是更新NetworkAgent的状态,最终都会触发NetworkFactory中的评分机制。

3、NetworkMonitor

NetworkMonitor的构造是在注册NetworkAgent,构造NetworkAgentInfo是创建的,其实质ping网络是在updateNetworkInfo中,细节不分析,但是NetworkMonitor对网络可用性的评分是有影响的,即当网络链接上之后,会去ping当前网络是否可用,如果不可用则会影响getCurrentScore获取的分数值,getCurrentScore是每次网络评分获取的分数的必经之路:

private int getCurrentScore(boolean pretendValidated) {
    int score = currentScore;

    if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
    if (score < 0) score = 0;

    if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE;

    return score;
}

当一个网络连接建立时,系统将用该连接Ping一个Google的网站来判断该连接是否真的可以上网,如果不可以,那么就会扣掉该网络40分,从而可能导致该网络的评分低于其他网络评分
如果是用户指定了网络那么分数直接等于EXPLICITLY_SELECTED_NETWORK_SCORE(100分)
至此网络评分就分析完毕

作者:xiabodan 发表于2016/12/20 18:15:03 原文链接
阅读:64 评论:0 查看评论

四、 数据业务APN参数的创建

$
0
0

前面在DcTracker初始化过程中注册了大量监听器,其中有两个监听器可以触发APN的创建过程:1、SIM载入完毕;2、APN改变。其中SIM载入完毕的注册是EVENT_RECORDS_LOADED事件,APN改变是注册了一个ApnChangeObserver类来监听。
当SIM载入完毕时,将会触发onRecordsLoaded()

private void onRecordsLoaded() {
    logi("onRecordsLoaded: createAllApnList");
    mAutoAttachOnCreationConfig = mPhone.getContext().getResources()
            .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation);

    createAllApnList();
    setInitialAttachApn();
    if (mPhone.mCi.getRadioState().isOn()) {
        if (DBG) log("onRecordsLoaded: notifying data availability");
        notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
    }
    setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
}

当APN改变时,用户指定APN,将会触发onApnChanged()

/**
 * Handles changes to the APN database.
 */
private void onApnChanged() {
    DctConstants.State overallState = getOverallState();
    boolean isDisconnected = (overallState == DctConstants.State.IDLE ||
            overallState == DctConstants.State.FAILED);

    createAllApnList();
    setInitialAttachApn();
    cleanUpConnectionsOnUpdatedApns(!isDisconnected);

    // FIXME: See bug 17426028 maybe no conditional is needed.
    if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubId()) {
        setupDataOnConnectableApns(Phone.REASON_APN_CHANGED);
    }
}

两个事件都会调用createAllApnList()和setInitialAttachApn(),分别是初始化当前卡可用的所有APN和设置默认联网用的APN,首先看createAllApnList()

private void createAllApnList() {
    mAllApnSettings = new ArrayList<ApnSetting>();
    IccRecords r = mIccRecords.get();
    String operator = (r != null) ? r.getOperatorNumeric() : "";
    if (operator != null) {
        String selection = "numeric = '" + operator + "'";
        Cursor cursor = mPhone.getContext().getContentResolver().query(
                Telephony.Carriers.CONTENT_URI, null, selection, null, null);
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                mAllApnSettings = createApnList(cursor);
            }
            cursor.close();
        }
    }

    addEmergencyApnSetting(); // 添加emergencyApnSettings
    dedupeApnSettings();      // 去除重复的APN
    if (mAllApnSettings.isEmpty()) {
        mPreferredApn = null;
    } else {
        mPreferredApn = getPreferredApn();
        if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
            mPreferredApn = null;
            setPreferredApn(-1);
        }
    }
    setDataProfilesAsNeeded();
}

这里面主要做了三件事
1、创建一个APN的列表,其中包含:当前SIM对应的APN、紧急APN;
APN的来源是telephony.db数据库中表carries,数据库的的参数是更新于apns-conf.xml文件
2、合并相同的APN;
在apns-conf.xml中的APN有可能又重复的
3、寻找一个当前Prefer的APN参数;
用户使用一张卡时,可能手动选择过使用的APN,因此,当用户再次插拔卡后,getPreferredApn用于找出用户之前选择的APN
这个mPreferredApn会在buildWaitingApns中被检查
如果mPreferredApn满足用户数据链接的需求,那么buildWaitingApns就直接会返回mPreferredApn用于联网使用的APN
如果mPreferredApn已经不能满足用户数据链接的需求时,才会从mAllApnSettings(createAllApnList)中去找合适的APN用于联网

这就是为什么setupData中getNextWaitingApn要去拿list的第0个APN联网,因为当mPreferredApn有效时,只会有一个APN存在apnContext中
以上就是APN的初始化和设置默认值

作者:xiabodan 发表于2016/12/20 18:18:48 原文链接
阅读:85 评论:0 查看评论

五、 数据业务APN参数的开机默认使能

$
0
0

在DcTracker的创建及准备工作中,initApnContexts()将初始化好当前系统支持的ApnContexts类型,但是这些APN参数默认都是没有被Enable的,只有当APN被Enable之后,该APN才可以被使用,下面我们就来看如何将一个APN参数激活

protected void initApnContexts() {
    // Load device network attributes from resources
    String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
            com.android.internal.R.array.networkAttributes);
    for (String networkConfigString : networkConfigStrings) {
        NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
        ApnContext apnContext = null;

        switch (networkConfig.type) {
        case ConnectivityManager.TYPE_MOBILE:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_MMS:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_SUPL:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_DUN:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_HIPRI:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_FOTA:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_IMS:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_CBS:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_IA:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig);
            break;
        case ConnectivityManager.TYPE_MOBILE_EMERGENCY:
            apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig);
            break;
        default:
            continue;
        }
    }
}

可以看出总共初始化了8种ApnContext,每一种的Type对应一种数据连接方式,他们的对应关系如下:
APN_TYPE_DEFAULT :默认网络连接,当激活时所有数据传输都使用该连接,不能与其他网络连接同时使用
APN_TYPE_MMS :彩信专用连接,此连接与default类似,用于与载体的多媒体信息服务器对话的应用程序,此连接能与default连接同时使用。适用场合:使用彩信服务时,必须有mms类型的接入点,不必选中,应用程序会自动使用此接入点
APN_TYPE_SUPL :是Secure User Plane Location“安全用户面定位”的简写,此连接与default类似,用于帮助定位设备与载体的安全用户面定位服务器对话的应用程序,此连接能与default连接同时使用,
APN_TYPE_DUN :Dial Up Networking拨号网络的简称,此连接与default连接类似,用于执行一个拨号网络网桥,使载体能知道拨号网络流量的应用程序,此连接能与default连接同时使用
APN_TYPE_HIPRI :高优先级网络,与default类似,但路由设置不同
APN_TYPE_FOTA :
APN_TYPE_IMS :
APN_TYPE_CBS :
APN_TYPE_IA :
APN_TYPE_EMERGENCY:紧急APN
addApnContext就是将相应的apnContext添加到mApnContexts这个List中去

private ApnContext addApnContext(String type, NetworkConfig networkConfig) {
    ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG, networkConfig,
            this);
    mApnContexts.put(type, apnContext);
    mPrioritySortedApnContexts.add(apnContext);
    return apnContext;
}

ApnContext的构造如下,其中apnType被设置为了指定的8种类型之一,一一对应关系;mDataEnabled 被初始化为了false,因此是不能联网的,需要使能之后才能联网;使用的优先级priority时根据解析frameworks/base/core/res/res/values/config.xml文件得到的,如下图

public ApnContext(Context context, String apnType, String logTag, NetworkConfig config,
        DcTrackerBase tracker) {
    mContext = context;
    mApnType = apnType;
    mState = DctConstants.State.IDLE;
    setReason(Phone.REASON_DATA_ENABLED);
    mDataEnabled = new AtomicBoolean(false);
    mDependencyMet = new AtomicBoolean(config.dependencyMet);
    mWaitingApnsPermanentFailureCountDown = new AtomicInteger(0);
    priority = config.priority;
    LOG_TAG = logTag;
    mDcTracker = tracker;
}       

这里写图片描述
第一种情况是开机后默认使能APN_TYPE_DEFAULT类型的APN
第二种情况是其他的类型使能,开机不会默认使能,而是通过TelephonyNetworkFactory中的needNetworkFor()方法触发的,当当前网络的评分比其他网络高时,就会通过needNetworkFor()方法触发当前网络的建立。比如当前WIFI断开时,如果发现数据网络是打开的,此时就会通过该方法激活数据流量,从而实现从WIFI到数据的转换过程。
这里先分析开机情况时默认使能APN_TYPE_DEFAULT类型的APN,激活的条件是EVENT_DATA_ATTACHED,这个事件的注册是在DctController中,如下

private DctController(PhoneProxy[] phones) {
    for (int i = 0; i < mPhoneNum; ++i) {
        // Register for radio state change
        PhoneBase phoneBase = (PhoneBase)mPhones[i].getActivePhone();
        updatePhoneBaseForIndex(i, phoneBase);
    }
}    
private void updatePhoneBaseForIndex(int index, PhoneBase phoneBase) {
    phoneBase.getServiceStateTracker().registerForDataConnectionAttached(mRspHandler,
               EVENT_DATA_ATTACHED + index, null);
    phoneBase.getServiceStateTracker().registerForDataConnectionDetached(mRspHandler,
               EVENT_DATA_DETACHED + index, null);
}

此处只关注EVENT_DATA_ATTACHED 事件注册,这个事件的触发是由GsmServiceStateTracker或者CdmaServiceStateTracker发出的,当DataRegState的状态由STATE_OUT_OF_SERVICE -> STATE_IN_SERVICE时就会触发EVENT_DATA_ATTACHED 事件,具体的流程如下图
这里写图片描述
注意:DctController是动态数据链接的管理者,也就是和ConnectivityService耦合的部分,ConnectivityService决定了采取哪种方式,具体的细节在此不分析,另外分析这节。

作者:xiabodan 发表于2016/12/20 18:23:38 原文链接
阅读:72 评论:0 查看评论

kafka文档(11)----0.10.1-Document-文档(3)-configures-broker配置信息

$
0
0

3. CONFIGURATION

Kafka uses key-value pairs in the property file format for configuration. These values can be supplied either from a file or programmatically.


3、配置信息

Kafka使用key-value格式配置信息。这些配置可以从配置文件中获取或者是程序中的默认值。

3.1 Broker Configs

The essential configurations are the following:
  • broker.id
  • log.dirs
  • zookeeper.connect
Topic-level configurations and defaults are discussed in more detail below.


3.1 Broker配置

基本的配置信息包含以下:

-broker.id

-log.dirs

-zookeeper.connect

Topic-level的配置以及默认值请阅读下面


NAME DESCRIPTION TYPE DEFAULT VALID VALUES IMPORTANCE
zookeeper.connect Zookeeper host string

zookeeper host字符串
string

high
advertised.host.name DEPRECATED: only used when `advertised.listeners` or `listeners` are not set. Use `advertised.listeners` instead. Hostname to publish to ZooKeeper for clients to use. In IaaS environments, this may need to be different from the interface to which the broker binds. If this is not set, it will use the value for `host.name` if configured. Otherwise it will use the value returned from java.net.InetAddress.getCanonicalHostName().

已废弃:只有当‘advertised.listeners'或者’listeners'没有设置时才使用。目前使用‘advertised.listeners'代替。主机名传递到zookeeper,以供客户端使用。在laaS环境中,这个名字可能与broker绑定的名字不同。如果这个值没有设置,如果‘host.name’选项设置了,系统将会使用’host.name'的值,否则系统会返回java.net.InetAddress.getCanonicalHostName()错误。
string null
high
advertised.listeners Listeners to publish to ZooKeeper for clients to use, if different than the listeners above. In IaaS environments, this may need to be different from the interface to which the broker binds. If this is not set, the value for `listeners` will be used.

如果这个值和上面的listeners配置不同,将会传递此值到zookeeper以供客户端使用。在laaS环境中,这个值可能与brokers绑定的名字不同。如果没有设置这个值,系统会使用‘listeners'
string null
high
advertised.port DEPRECATED: only used when `advertised.listeners` or `listeners` are not set. Use `advertised.listeners` instead. The port to publish to ZooKeeper for clients to use. In IaaS environments, this may need to be different from the port to which the broker binds. If this is not set, it will publish the same port that the broker binds to.

已废弃:只有当没有设置‘advertised.listeners'和’listeners'时才使用这个值。目前使用‘advertised.listeners'作为替代。这是发布到zookeeper上,以供客户端使用。在laaS环境中,这个可能和broker绑定的端口不同。如果这个值没有设置,一般会使用broker绑定的端口。
int null
high
auto.create.topics.enable Enable auto creation of topic on the server

是否允许在server上自动创建topic
boolean true
high
auto.leader.rebalance.enable Enables auto leader balancing. A background thread checks and triggers leader balance if required at regular intervals

是否允许leader的自动平衡。如果允许的话,会有后台线程检查并触发leader的均衡操作。
boolean true
high
background.threads The number of threads to use for various background processing tasks

后台处理任务的线程数
int 10 [1,...] high
broker.id The broker id for this server. If unset, a unique broker id will be generated.To avoid conflicts between zookeeper generated broker id's and user configured broker id's, generated broker ids start from reserved.broker.max.id + 1.

当前server的broker id。如果没有设置,系统会自动分配一个唯一的broker id。为了避免在zookeeper自动产生的broker id和用户配置的broker id之间产生冲突,自动产生的broker一般是从reserved.broker.max.id + 1开始的。
int -1
high
compression.type Specify the final compression type for a given topic. This configuration accepts the standard compression codecs ('gzip', 'snappy', 'lz4'). It additionally accepts 'uncompressed' which is equivalent to no compression; and 'producer' which means retain the original compression codec set by the producer.

指定某个topic消息压缩类型。此配置接受标准压缩编码器(’gzip‘,’snappy‘,’lz4‘)。另外也接受非压缩模式。一般是由producer进行压缩。
string producer
high
delete.topic.enable Enables delete topic. Delete topic through the admin tool will have no effect if this config is turned off

是否允许删除topic。如果设置为否,则官方版本的工具将无法删除topic
boolean false
high
host.name DEPRECATED: only used when `listeners` is not set. Use `listeners` instead. hostname of broker. If this is set, it will only bind to this address. If this is not set, it will bind to all interfaces

已废弃:
只有当’listeners'没有设置时,才使用这个值。目前采用‘listeners'作为替代。如果设置了这个选项,broker只会绑定到这个地址,如果没有设置这个值,broker将会绑定到所有对外host name。
string ""
high
leader.imbalance.check.interval.seconds The frequency with which the partition rebalance check is triggered by the controller

controlles检查是否进行partitions重新负载均衡的频率,单位为秒
long 300
high
leader.imbalance.per.broker.percentage The ratio of leader imbalance allowed per broker. The controller would trigger a leader balance if it goes above this value per broker. The value is specified in percentage.

每个broker允许的leader失衡比例。如果某个broker的leader失衡数已经大于这个数值,则controller会触发leader的负载均衡。这个值以百分比的方式给出。
int 10
high
listeners Listener List - Comma-separated list of URIs we will listen on and their protocols. Specify hostname as 0.0.0.0 to bind to all interfaces. Leave hostname empty to bind to default interface. Examples of legal listener lists: PLAINTEXT://myhost:9092,TRACE://:9091 PLAINTEXT://0.0.0.0:9092, TRACE://localhost:9093

监听列表-以逗号分隔的URIs列表,指明了broker需要监听的hostname以及协议。需要指出的是,当指定hostname为0.0.0.0时,就是绑定此broker到所有hostname。如果留空hostname,则绑定到默认hostname。合法监听列表为:
PLAINTEXT://myhost:9092,TRACE://:9091 PLAINTEXT://0.0.0.0:9092, TRACE://localhost:9093
string null
high
log.dir The directory in which the log data is kept (supplemental for log.dirs property)

日志存储的目录,log.dirs作为此配置的补充选项
string /tmp/kafka-logs
high
log.dirs The directories in which the log data is kept. If not set, the value in log.dir is used

日志存储的多个目录列表。如果没有配置此选项,则使用log.dir配置
string null
high
log.flush.interval.messages The number of messages accumulated on a log partition before messages are flushed to disk

消息回刷到磁盘之前,内存所保存的每个partition的消息总数
long 9223372036854775807 [1,...] high
log.flush.interval.ms The maximum time in ms that a message in any topic is kept in memory before flushed to disk. If not set, the value in log.flush.scheduler.interval.ms is used

消息回刷到磁盘之前,消息在内存中保存的最长时间。如果没有设置,则使用log.flush.scheduler.interval.ms的值。
long null
high
log.flush.offset.checkpoint.interval.ms The frequency with which we update the persistent record of the last flush which acts as the log recovery point

由于内存中的日志并不是立刻回刷到磁盘,所以确定回刷到磁盘的消息才是在当前broker崩溃重启之后可以恢复的点。查看broker日志目录,可以看到两个文件,其中一个文件就是保存每个topic-partition的recover point的文件。因此,这个值就是更新这个恢复点的频率间隔。

int 60000 [0,...] high
log.flush.scheduler.interval.ms The frequency in ms that the log flusher checks whether any log needs to be flushed to disk

日志回刷器检查是否将任何日志回刷到磁盘的频率。
long 9223372036854775807
high
log.retention.bytes The maximum size of the log before deleting it

日志删除之前的最大尺寸
long -1
high
log.retention.hours The number of hours to keep a log file before deleting it (in hours), tertiary to log.retention.ms property

日志删除之前保存的小时数,默认时168小时,即2周;优先级相对于log.retention.ms为第三
int 168
high
log.retention.minutes The number of minutes to keep a log file before deleting it (in minutes), secondary to log.retention.ms property. If not set, the value in log.retention.hours is used

日志删除前保存的分钟数。优先级相对于log.retention.ms为第二,如果没有设置这个值,则使用log.retention.hours
int null
high
log.retention.ms The number of milliseconds to keep a log file before deleting it (in milliseconds), If not set, the value in log.retention.minutes is used

日志删除之前保存的ms数。如果没有设置,则使用log.retention.minutes
long null
high
log.roll.hours The maximum time before a new log segment is rolled out (in hours), secondary to log.roll.ms property

滚动生成新日志的最大时间间隔,优先级相对于log.roll.ms为第二
int 168 [1,...] high
log.roll.jitter.hours The maximum jitter to subtract from logRollTimeMillis (in hours), secondary to log.roll.jitter.ms property

相对于logRollTimeMillis出现的最大时间偏差,相对于log.poll.jitter.ms为第二优先级。
int 0 [0,...] high
log.roll.jitter.ms The maximum jitter to subtract from logRollTimeMillis (in milliseconds). If not set, the value in log.roll.jitter.hours is used

相对于logRollTimeMillis出现的最大时间偏差,如果没有设置此值,则使用log.roll.jitter.hours
long null
high
log.roll.ms The maximum time before a new log segment is rolled out (in milliseconds). If not set, the value in log.roll.hours is used

滚动生成新日志的最大时间间隔,如果没有设置此值,则使用log.roll.hours
long null
high
log.segment.bytes The maximum size of a single log file

单独的日志文件最大尺寸。
int 1073741824 [14,...] high
log.segment.delete.delay.ms The amount of time to wait before deleting a file from the filesystem

从文件系统中删除文件所等待的最长时间。
long 60000 [0,...] high
message.max.bytes The maximum size of message that the server can receive

server可以接收的最大消息尺寸
int 1000012 [0,...] high
min.insync.replicas When a producer sets acks to "all" (or "-1"), min.insync.replicas specifies the minimum number of replicas that must acknowledge a write for the write to be considered successful. If this minimum cannot be met, then the producer will raise an exception (either NotEnoughReplicas or NotEnoughReplicasAfterAppend).
When used together, min.insync.replicas and acks allow you to enforce greater durability guarantees. A typical scenario would be to create a topic with a replication factor of 3, set min.insync.replicas to 2, and produce with acks of "all". This will ensure that the producer raises an exception if a majority of replicas do not receive a write.

当producer设置ack选项为‘all'或者’-1‘时,此值指定了server成功写入的最少备份数,只有写入达到了此备份数,server才能返回正确写入的确认消息。如果没有实现成功写入这个最少备份数,server会抛出异常(either NotEnoughReplicas or NotEnoughReplicasAfterAppend)。一块使用min.sync.replicas和acks可以提高写入消息可用性。典型的用法是,将topic的备份数设置为3,将此值设置为2,然后producer可以设置ack为‘all’。这将使得server在大部分备份节点没有成功写入消息抛出异常。
int 1 [1,...] high
num.io.threads The number of io threads that the server uses for carrying out network requests

server用来获取网络请求的io线程数。
int 8 [1,...] high
num.network.threads the number of network threads that the server uses for handling network requests

server用来处理网络请求的网络线程数
int 3 [1,...] high
num.recovery.threads.per.data.dir The number of threads per data directory to be used for log recovery at startup and flushing at shutdown

在启动和正常终止期间,用于每个数据目录进行日志恢复的线程数
int 1 [1,...] high
num.replica.fetchers Number of fetcher threads used to replicate messages from a source broker. Increasing this value can increase the degree of I/O parallelism in the follower broker.

用于从leader broker获取消息的线程数。提高这个值可以提高follower broker的并行处理能力。
int 1
high
offset.metadata.max.bytes The maximum size for a metadata entry associated with an offset commit

与offset提交相关联的元数据条目的最大大小
int 4096
high
offsets.commit.required.acks The required acks before the commit can be accepted. In general, the default (-1) should not be overridden

提交接受之前所要求的acks。一般来说。默认值-1不应当改变。
注:日志发送到broker,虽然broker成功接收到,但是并没有提交到日志中去,所以在真正提交到日志之前,需要所有的broker都真正收到这条日志。
short -1
high
offsets.commit.timeout.ms Offset commit will be delayed until all replicas for the offsets topic receive the commit or this timeout is reached. This is similar to the producer request timeout.

在topics的备份接收到这次提交之前或者超时之前,此次offset提交可以等待的时间。这个和producer请求的超时时间比较相似。
int 5000 [1,...] high
offsets.load.buffer.size Batch size for reading from the offsets segments when loading offsets into the cache.

加载offsets到缓存时从offsets段中批量读取的数量
int 5242880 [1,...] high
offsets.retention.check.interval.ms Frequency at which to check for stale offsets

检查稳定offset的频率
long 600000 [1,...] high
offsets.retention.minutes Log retention window in minutes for offsets topic

对offsets topic来说,日志删除窗口时间
int 1440 [1,...] high
offsets.topic.compression.codec Compression codec for the offsets topic - compression may be used to achieve "atomic" commits

对于offsets topic的压缩编码器-压缩可以实现原子提交
int 0
high
offsets.topic.num.partitions The number of partitions for the offset commit topic (should not change after deployment)

offset提交topic的partitions数目(一旦部署,不应该改变)
int 50 [1,...] high
offsets.topic.replication.factor The replication factor for the offsets topic (set higher to ensure availability). To ensure that the effective replication factor of the offsets topic is the configured value, the number of alive brokers has to be at least the replication factor at the time of the first request for the offsets topic. If not, either the offsets topic creation will fail or it will get a replication factor of min(alive brokers, configured replication factor)

offsets topic的备份数,值越大可靠性越高。为保证offsets topic有效备份数是配置的数值,活跃brokers的数目最低为备份数目。如果达不到这个数值,offsets topic会创建失败,或者只能获得二者之中较小者(活跃的brokers,所配置的备份数目)
short 3 [1,...] high
offsets.topic.segment.bytes The offsets topic segment bytes should be kept relatively small in order to facilitate faster log compaction and cache loads

offsets topic段字节应当相对比较小,以便于获取更快的日志压缩以及缓存负载。
int 104857600 [1,...] high
port DEPRECATED: only used when `listeners` is not set. Use `listeners` instead. the port to listen and accept connections on

已废弃:
只有当‘listeners'没有设置时才使用。使用’listeners'作为替代。监听的端口号以及接受链接的端口号。
int 9092
high
queued.max.requests The number of queued requests allowed before blocking the network threads

队列中请求的最大个数,超过这个值就会阻塞网络请求。
int 500 [1,...] high
quota.consumer.default DEPRECATED: Used only when dynamic default quotas are not configured for or in Zookeeper. Any consumer distinguished by clientId/consumer group will get throttled if it fetches more bytes than this value per-second

已废弃:
只有没有为zookeeper或者在zookeeper中没有配置默认的动态配额时才会使用。任何由clientid或者consumer group区分的consumer只要每秒获取的数据会小于这个值。
long 9223372036854775807 [1,...] high
quota.producer.default DEPRECATED: Used only when dynamic default quotas are not configured for , or in Zookeeper. Any producer distinguished by clientId will get throttled if it produces more bytes than this value per-second

已废弃:
只有当没有为zookeeper或者在zookeeper中没有配置动态的配额时才回使用。任何以clientid区分的producer在每秒中获取的字节数会小于这个值。
long 9223372036854775807 [1,...] high
replica.fetch.min.bytes Minimum bytes expected for each fetch response. If not enough bytes, wait up to replicaMaxWaitTimeMs

每次抓取消息时所期待应答的最小尺寸。如果没有足够的字节,等待 replicaMaxWaitTimeMs长的时间。
int 1
high
replica.fetch.wait.max.ms max wait time for each fetcher request issued by follower replicas. This value should always be less than the replica.lag.time.max.ms at all times to prevent frequent shrinking of ISR for low throughput topics

followers备份时抓取消息等待的最长时间。这个值一般小于replica.lag.time.max.ms,以防止ISR列表由于follower的超时的不断变化
int 500
high
replica.high.watermark.checkpoint.interval.ms The frequency with which the high watermark is saved out to disk

高水印保存到磁盘的频率。这个涉及到kafka的内存管理,由于写入kafka的数据分为两种:一种是写入kafka broker内存的,但是并没有写入磁盘,这种数据是不可恢复的;一种是写入内存也写入磁盘的,这种数据是可以恢复的,高水印其实就是这两种数据的分界线。
long 5000
high
replica.lag.time.max.ms If a follower hasn't sent any fetch requests or hasn't consumed up to the leaders log end offset for at least this time, the leader will remove the follower from isr

如果follower没有发送任何同步请求或者没有从leader没有同步到最新offset,如果上述情况持续了这个值代表的时间,那么leader会从isr将这个follower移除。
long 10000
high
replica.socket.receive.buffer.bytes The socket receive buffer for network requests

网络请求中socket 收到缓存的最大尺寸。
int 65536
high
replica.socket.timeout.ms The socket timeout for network requests. Its value should be at least replica.fetch.wait.max.ms

网络请求中socket超市时间。它的值最小是replica.fetch.wait.max.ms
int 30000
high
request.timeout.ms The configuration controls the maximum amount of time the client will wait for the response of a request. If the response is not received before the timeout elapses the client will resend the request if necessary or fail the request if retries are exhausted.

客户端等待broker应答的超时时间。如果超时了,客户端没有收到应答,如果必要的话可能会重发请求,如果重试都失败了也可能会报请求失败
int 30000
high
socket.receive.buffer.bytes The SO_RCVBUF buffer of the socket sever sockets. If the value is -1, the OS default will be used.

server 的socket缓存SO_RCVBUF。如果设置为-1,将使用OS的默认值
int 102400
high
socket.request.max.bytes The maximum number of bytes in a socket request

socket请求的最大字节数
int 104857600 [1,...] high
socket.send.buffer.bytes The SO_SNDBUF buffer of the socket sever sockets. If the value is -1, the OS default will be used.

server的socket的SO_SNDBUF缓存。如果设置为-1,将使用OS的默认值
int 102400
high
unclean.leader.election.enable Indicates whether to enable replicas not in the ISR set to be elected as leader as a last resort, even though doing so may result in data loss

指明是否允许不在ISR列表中的备份节点称为新leader,即使这么做会造成数据丢失
boolean true
high
zookeeper.connection.timeout.ms The max time that the client waits to establish a connection to zookeeper. If not set, the value in zookeeper.session.timeout.ms is used

客户端与zookeeper建立链接时等待的最长时间。如果没有设置,将会使用zookeeper.session.timeout.ms的值
int null
high
zookeeper.session.timeout.ms Zookeeper session timeout

zookeeper回话超时时间
int 6000
high
zookeeper.set.acl Set client to use secure ACLs

设置客户端使用安全的ACLs权限控制
boolean false
high
broker.id.generation.enable Enable automatic broker id generation on the server. When enabled the value configured for reserved.broker.max.id should be reviewed.

允许server自动分配broker id。当设置这个值时,需要仔细察看reserved.broker.max.id的值,以防止自动产生的broker.id和配置的broker.id冲突
boolean true
medium
broker.rack Rack of the broker. This will be used in rack aware replication assignment for fault tolerance. Examples: `RACK1`, `us-east-1d`

broker的支架?
用来在支架感知备份中的容错;例如:
‘RACK1’, ‘us-east-1d'
string null
medium
connections.max.idle.ms Idle connections timeout: the server socket processor threads close the connections that idle more than this

空闲链接的超时时间:server socket处理线程会关闭超时的链接。
long 600000
medium
controlled.shutdown.enable Enable controlled shutdown of the server

是否允许server受控的终止。
boolean true
medium
controlled.shutdown.max.retries Controlled shutdown can fail for multiple reasons. This determines the number of retries when such failure happens

受控制的终止因为多种原因失败。这个决定了控制终止失败时重试的次数
int 3
medium
controlled.shutdown.retry.backoff.ms Before each retry, the system needs time to recover from the state that caused the previous failure (Controller fail over, replica lag etc). This config determines the amount of time to wait before retrying.

在每次重试之前,系统需要时间从引发先前失败的状态恢复过来(控制失败有可能因为replica lag等)。这个配置决定了在重试之前等待的时间。
long 5000
medium
controller.socket.timeout.ms The socket timeout for controller-to-broker channels

controller-to-broker的信道socket的超时时间
int 30000
medium
default.replication.factor default replication factors for automatically created topics

自动创建的topic默认的备份数
int 1
medium
fetch.purgatory.purge.interval.requests The purge interval (in number of requests) of the fetch request purgatory

抓取请求的清除时间间隔
int 1000
medium
group.max.session.timeout.ms The maximum allowed session timeout for registered consumers. Longer timeouts give consumers more time to process messages in between heartbeats at the cost of a longer time to detect failures.

每个已注册consumers的最大会话超时时间。超时越长,consumers在两次心跳之间处理消息的时间就越长,同样需要花费更多的时间去检测失联错误。
int 300000
medium
group.min.session.timeout.ms The minimum allowed session timeout for registered consumers. Shorter timeouts leader to quicker failure detection at the cost of more frequent consumer heartbeating, which can overwhelm broker resources.

已注册的consumers最小的会话超市时间。超时越小,leader越快检查失联错误,同样需要更多的consumers心跳链接,这可能过度耗费brokers的资源。
int 6000
medium
inter.broker.protocol.version Specify which version of the inter-broker protocol will be used. This is typically bumped after all brokers were upgraded to a new version. Example of some valid values are: 0.8.0, 0.8.1, 0.8.1.1, 0.8.2, 0.8.2.0, 0.8.2.1, 0.9.0.0, 0.9.0.1 Check ApiVersion for the full list.

指定了broker内部的协议版本。这个一般是在所有brokers都升级到新版本之后才能升级的。例如,正确的值是:
0.8.0, 0.8.1, 0.8.1.1,
0.8.2, 0.8.2.0, 0.8.2.1,0.9。0.0, 0.9.0.1.查看API版本可以获取完整的版本列表
string 0.10.1-IV2
medium
log.cleaner.backoff.ms The amount of time to sleep when there are no logs to clean

当没有日志清除时,cleaner睡眠的时间
long 15000 [0,...] medium
log.cleaner.dedupe.buffer.size The total memory used for log deduplication across all cleaner threads

日志删除线程所需要的内存总大小
long 134217728
medium
log.cleaner.delete.retention.ms How long are delete records retained?

保存删除日志多长时间
long 86400000
medium
log.cleaner.enable Enable the log cleaner process to run on the server? Should be enabled if using any topics with a cleanup.policy=compact including the internal offsets topic. If disabled those topics will not be compacted and continually grow in size.

是否允许server运行日志删除进程。如果内部offsets topic使用的cleanup.policy=compact,则需要允许。如果不允许的话,则topics的数据不会压缩,并且越来越大
boolean true
medium
log.cleaner.io.buffer.load.factor Log cleaner dedupe buffer load factor. The percentage full the dedupe buffer can become. A higher value will allow more log to be cleaned at once but will lead to more hash collisions

日志清除器复制缓存的负载因子。??
更高的值
double 0.9
medium
log.cleaner.io.buffer.size The total memory used for log cleaner I/O buffers across all cleaner threads int 524288 [0,...] medium
log.cleaner.io.max.bytes.per.second The log cleaner will be throttled so that the sum of its read and write i/o will be less than this value on average double 1.7976931348623157E308
medium
log.cleaner.min.cleanable.ratio The minimum ratio of dirty log to total log for a log to eligible for cleaning double 0.5
medium
log.cleaner.min.compaction.lag.ms The minimum time a message will remain uncompacted in the log. Only applicable for logs that are being compacted. long 0
medium
log.cleaner.threads The number of background threads to use for log cleaning int 1 [0,...] medium
log.cleanup.policy The default cleanup policy for segments beyond the retention window. A comma separated list of valid policies. Valid policies are: "delete" and "compact" list [delete] [compact, delete] medium
log.index.interval.bytes The interval with which we add an entry to the offset index int 4096 [0,...] medium
log.index.size.max.bytes The maximum size in bytes of the offset index int 10485760 [4,...] medium
log.message.format.version Specify the message format version the broker will use to append messages to the logs. The value should be a valid ApiVersion. Some examples are: 0.8.2, 0.9.0.0, 0.10.0, check ApiVersion for more details. By setting a particular message format version, the user is certifying that all the existing messages on disk are smaller or equal than the specified version. Setting this value incorrectly will cause consumers with older versions to break as they will receive messages with a format that they don't understand. string 0.10.1-IV2
medium
log.message.timestamp.difference.max.ms The maximum difference allowed between the timestamp when a broker receives a message and the timestamp specified in the message. If log.message.timestamp.type=CreateTime, a message will be rejected if the difference in timestamp exceeds this threshold. This configuration is ignored if log.message.timestamp.type=LogAppendTime. long 9223372036854775807 [0,...] medium
log.message.timestamp.type Define whether the timestamp in the message is message create time or log append time. The value should be either `CreateTime` or `LogAppendTime` string CreateTime [CreateTime, LogAppendTime] medium
log.preallocate Should pre allocate file when create new segment? If you are using Kafka on Windows, you probably need to set it to true. boolean false
medium
log.retention.check.interval.ms The frequency in milliseconds that the log cleaner checks whether any log is eligible for deletion long 300000 [1,...] medium
max.connections.per.ip The maximum number of connections we allow from each ip address int 2147483647 [1,...] medium
max.connections.per.ip.overrides Per-ip or hostname overrides to the default maximum number of connections string ""
medium
num.partitions The default number of log partitions per topic int 1 [1,...] medium
principal.builder.class The fully qualified name of a class that implements the PrincipalBuilder interface, which is currently used to build the Principal for connections with the SSL SecurityProtocol. class class org.apache.kafka.common.security.auth.DefaultPrincipalBuilder
medium
producer.purgatory.purge.interval.requests The purge interval (in number of requests) of the producer request purgatory int 1000
medium
replica.fetch.backoff.ms The amount of time to sleep when fetch partition error occurs. int 1000 [0,...] medium
replica.fetch.max.bytes The number of bytes of messages to attempt to fetch for each partition. This is not an absolute maximum, if the first message in the first non-empty partition of the fetch is larger than this value, the message will still be returned to ensure that progress can be made. The maximum message size accepted by the broker is defined viamessage.max.bytes (broker config) ormax.message.bytes (topic config). int 1048576 [0,...] medium
replica.fetch.response.max.bytes Maximum bytes expected for the entire fetch response. This is not an absolute maximum, if the first message in the first non-empty partition of the fetch is larger than this value, the message will still be returned to ensure that progress can be made. The maximum message size accepted by the broker is defined viamessage.max.bytes (broker config) ormax.message.bytes (topic config). int 10485760 [0,...] medium
reserved.broker.max.id Max number that can be used for a broker.id int 1000 [0,...] medium
sasl.enabled.mechanisms The list of SASL mechanisms enabled in the Kafka server. The list may contain any mechanism for which a security provider is available. Only GSSAPI is enabled by default. list [GSSAPI]
medium
sasl.kerberos.kinit.cmd Kerberos kinit command path. string /usr/bin/kinit
medium
sasl.kerberos.min.time.before.relogin Login thread sleep time between refresh attempts. long 60000
medium
sasl.kerberos.principal.to.local.rules A list of rules for mapping from principal names to short names (typically operating system usernames). The rules are evaluated in order and the first rule that matches a principal name is used to map it to a short name. Any later rules in the list are ignored. By default, principal names of the form {username}/{hostname}@{REALM} are mapped to {username}. For more details on the format please seesecurity authorization and acls. list [DEFAULT]
medium
sasl.kerberos.service.name The Kerberos principal name that Kafka runs as. This can be defined either in Kafka's JAAS config or in Kafka's config. string null
medium
sasl.kerberos.ticket.renew.jitter Percentage of random jitter added to the renewal time. double 0.05
medium
sasl.kerberos.ticket.renew.window.factor Login thread will sleep until the specified window factor of time from last refresh to ticket's expiry has been reached, at which time it will try to renew the ticket. double 0.8
medium
sasl.mechanism.inter.broker.protocol SASL mechanism used for inter-broker communication. Default is GSSAPI. string GSSAPI
medium
security.inter.broker.protocol Security protocol used to communicate between brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL. string PLAINTEXT
medium
ssl.cipher.suites A list of cipher suites. This is a named combination of authentication, encryption, MAC and key exchange algorithm used to negotiate the security settings for a network connection using TLS or SSL network protocol. By default all the available cipher suites are supported. list null
medium
ssl.client.auth Configures kafka broker to request client authentication. The following settings are common:
  • ssl.client.auth=required If set to required client authentication is required.
  • ssl.client.auth=requested This means client authentication is optional. unlike requested , if this option is set client can choose not to provide authentication information about itself
  • ssl.client.auth=none This means client authentication is not needed.
string none [required, requested, none] medium
ssl.enabled.protocols The list of protocols enabled for SSL connections. list [TLSv1.2, TLSv1.1, TLSv1]
medium
ssl.key.password The password of the private key in the key store file. This is optional for client. password null
medium
ssl.keymanager.algorithm The algorithm used by key manager factory for SSL connections. Default value is the key manager factory algorithm configured for the Java Virtual Machine. string SunX509
medium
ssl.keystore.location The location of the key store file. This is optional for client and can be used for two-way authentication for client. string null
medium
ssl.keystore.password The store password for the key store file. This is optional for client and only needed if ssl.keystore.location is configured. password null
medium
ssl.keystore.type The file format of the key store file. This is optional for client. string JKS
medium
ssl.protocol The SSL protocol used to generate the SSLContext. Default setting is TLS, which is fine for most cases. Allowed values in recent JVMs are TLS, TLSv1.1 and TLSv1.2. SSL, SSLv2 and SSLv3 may be supported in older JVMs, but their usage is discouraged due to known security vulnerabilities. string TLS
medium
ssl.provider The name of the security provider used for SSL connections. Default value is the default security provider of the JVM. string null
medium
ssl.trustmanager.algorithm The algorithm used by trust manager factory for SSL connections. Default value is the trust manager factory algorithm configured for the Java Virtual Machine. string PKIX
medium
ssl.truststore.location The location of the trust store file. string null
medium
ssl.truststore.password The password for the trust store file. password null
medium
ssl.truststore.type The file format of the trust store file. string JKS
medium
authorizer.class.name The authorizer class that should be used for authorization string ""
low
metric.reporters A list of classes to use as metrics reporters. Implementing the MetricReporter interface allows plugging in classes that will be notified of new metric creation. The JmxReporter is always included to register JMX statistics. list []
low
metrics.num.samples The number of samples maintained to compute metrics. int 2 [1,...] low
metrics.sample.window.ms The window of time a metrics sample is computed over. long 30000 [1,...] low
quota.window.num The number of samples to retain in memory for client quotas int 11 [1,...] low
quota.window.size.seconds The time span of each sample for client quotas int 1 [1,...] low
replication.quota.window.num The number of samples to retain in memory for replication quotas int 11 [1,...] low
replication.quota.window.size.seconds The time span of each sample for replication quotas int 1 [1,...] low
ssl.endpoint.identification.algorithm The endpoint identification algorithm to validate server hostname using server certificate. string null
low
ssl.secure.random.implementation The SecureRandom PRNG implementation to use for SSL cryptography operations. string null
low
zookeeper.sync.time.ms How far a ZK follower can be behind a ZK leader int 2000   low




作者:beitiandijun 发表于2016/12/20 18:41:05 原文链接
阅读:91 评论:0 查看评论

七、数据链接更新路由表

$
0
0

数据链接响应

sp<RILRequest> RIL::processSolicited(const Parcel& p) {
    switch (rr->mRequest) {
        case RIL_REQUEST_SETUP_DATA_CALL:
                ret =  responseSetupDataCall(p);
                break;
    }

    …....

       } else {
            if (rr->mResult != NULL) {
                AsyncResult::forMessage(rr->mResult, ret, NULL);
                rr->mResult->sendToTarget();
            }
        }
}
sp<Object> RIL::responseSetupDataCall(const Parcel & p) {
    dataCall = getDataCallResponse(p, ver);
    return dataCall;
}
sp<DataCallResponse> RIL::getDataCallResponse(const Parcel & p, int32_t version) {
      dataCall->status = p.readInt32();
            dataCall->suggestedRetryTime = p.readInt32();
            dataCall->cid = p.readInt32();
            dataCall->active = p.readInt32();
            dataCall->type = readString(p);
            dataCall->ifname = readString(p);
            sp<String> addresses = readString(p);
            sp<String> dnses = readString(p);
            sp<String> gateways = readString(p);

            return dataCall;
}
bool DataConnection::DcActivatingState::processMessage(const sp<Message>& msg) {
    switch (msg->what) {
        case EVENT_SETUP_DATA_CONNECTION_DONE: {
        DataCallResponse::SetupResult result = pDC->onSetupConnectionCompleted(ar);
            switch (result.getValue()) {
                    case DataCallResponse::SetupResult::SUCCESS: {
                    pDC->mDcFailCause = DcFailCause::NONE;
                    pDC->transitionTo(pDC->mActiveState);//状态机状态转化
                    break;
                }
        }
    }
}
DataCallResponse::SetupResult DataConnection::onSetupConnectionCompleted(const sp<AsyncResult>& ar) {
    result = updateLinkProperty(response)->setupResult;
}
sp<DataConnection::UpdateLinkPropertyResult> DataConnection::updateLinkProperty(const sp<DataCallResponse>& newState) {
    result->setupResult = setLinkProperties(newState, result->newLp);
}
void DataConnection::DcActiveState::enter() {
    pDC->notifyAllOfConnected(Phone::REASON_CONNECTED());
}
void DataConnection::notifyAllOfConnected(const android::sp<String>& reason) {
    notifyAllWithEvent(NULL, DctConstants::EVENT_DATA_SETUP_COMPLETE, reason);
}
void DcTrackerBase::handleMessage(const sp<Message>& msg) {
    switch (msg->what) {
          case DctConstants::EVENT_DATA_SETUP_COMPLETE:
        mCidActive = msg->arg1;
        onDataSetupComplete(safe_cast<AsyncResult*>(msg->obj));
        break;
    }
}
void DcTracker::onDataSetupComplete(const android::sp<AsyncResult>& ar) {
    apnContext->setState(DctConstants::State::CONNECTED);
}
void MobileDataStateReceiver::onReceive(const sp<Context>& context, const sp<Intent>& intent) {
    switch (state) {
        case PhoneConstants::DataState::CONNECTED:                  
            mdst->setDetailedState(NetworkInfo::DetailedState::CONNECTED, reason, apnName);
            break;
    }
}
void MobileDataStateTracker::setDetailedState(NetworkInfo::DetailedState state, const sp<String>& reason,const sp<String>& extraInfo) {
    sp<Message>msg=mTarget->obtainMessage(NetworkStateTracker::EVENT_STATE_CHANGED,new NetworkInfo(mNetworkInfo));
      msg->sendToTarget();
}

ConnectivityService.cpp

void ConnectivityService::MyHandler::handleMessage(const sp<Message>& msg) {
    if (msg->what == NetworkStateTracker::EVENT_STATE_CHANGED) {


        } else if (state == NetworkInfo::State::CONNECTED) { 
                             mConnectivityService->handleConnect(info); 
            } 
    }
}
void ConnectivityService::handleConnect(const sp<NetworkInfo>& info) {
    handleConnectivityChange(info, false);
}
void ConnectivityService::handleConnectivityChange(const sp<NetworkInfo>& replacedInfo, bool doReset) { 
        mNetIdtoInterfaces->put(ifa, new Integer(newNetId)); 
                mNetd->createPhysicalNetwork(newNetId); //binder到NetworkManagementService.cpp
                mNetd->addInterfaceToNetwork(ifa, newNetId);  //  1、 addInterfaceToNetwork 

        // 2、 updateRoutes
        bool resetDns = updateRoutes(newLp, curLp, (*mNetConfigs)[netType]->isDefault());
}

1、 addInterfaceToNetwork
NetworkManagementService.cpp

void NetworkManagementService::addInterfaceToNetwork(const android::sp<String> & iface, int netId) { 
    modifyInterfaceInNetwork(new String("add"), netId, iface); 
} 

void NetworkManagementService::modifyInterfaceInNetwork(const android::sp<String> & action, int netId, const android::sp<String> & iface) { 

    mConnector->doCommand(cmd, ret); 
}

NativeDaemonConnector.cpp

Vector<sp<String> > NativeDaemonConnector::doCommand(const sp<String>& cmd, int & ret) { 
    return doCommandLocked(cmd, ret); 
} 
Vector<sp<String> > NativeDaemonConnector::doCommandLocked(const sp<String>& cmd, int& ret) { 
    bool rc = sendCommandLocked(newCmd); 
}
bool NativeDaemonConnector::sendCommandLocked(const sp<String>& command) { 
    return sendCommandLocked(command, NULL); 
} 
bool NativeDaemonConnector::sendCommandLocked(const sp<String>& command, const sp<String>& argument) { 
     if (mOutputStream == NULL) { 
        return false; 
    } else { 
               mOutputStream->write(outCommand, 0, outCommand->length()); 
    } 
    return true; 
} 

socket(netd)
这个socket是在NetlinkManager中创建的
CommandListener.cpp

int CommandListener::NetworkCommand::runCommand(SocketClient* client, int argc, char** argv) { 
        if (!strcmp(argv[2], "add")) { 
            if (int ret = sNetCtrl->addInterfaceToNetwork(netId, argv[4])) { 
                return operationError(client, "addInterfaceToNetwork() failed", ret); 
            } 
        } else if (!strcmp(argv[2], "remove")) { 
            if (int ret = sNetCtrl->removeInterfaceFromNetwork(netId, argv[4])) { 
                return operationError(client, "removeInterfaceFromNetwork() failed", ret); 
            } 
        }   
}

NetworkController.cpp

int NetworkController::addInterfaceToNetwork(unsigned netId, const char* interface) { 
    RouteController::addInterfaceToLocalNetworkL(netId, interface); 

    return getNetworkLocked(netId)->addInterface(interface); 
} 

PhysicalNetwork.cpp

int PhysicalNetwork::addInterface(const std::string& interface) { 
     if (int ret = RouteController::addInterfaceToPhysicalNetwork(mNetId, interface.c_str(), 
                                                                 mPermission)) { 
        return ret; 
    } 
    return 0; 
} 

RouteController.cpp

int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* interface, 
                                                   Permission permission) { 
    if (int ret = modifyPhysicalNetwork(netId, interface, permission, ACTION_ADD)) { 
        return ret; 
    } 
    updateTableNamesFile(); 
    return 0; 
} 
WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interface, 
                                             Permission permission, bool add) { 
    uint32_t table = getRouteTableForInterface(interface); 
    if (table == RT_TABLE_UNSPEC) { 
        return -ESRCH; 
    } 

    if (int ret = modifyIncomingPacketMark(netId, interface, permission, add)) { 
        return ret; 
    } 
    if (int ret = modifyExplicitNetworkRule(netId, table, permission, INVALID_UID, INVALID_UID, add)) { 
        return ret; 
    } 
    if (int ret = modifyOutputInterfaceRule(interface, table, permission, INVALID_UID, INVALID_UID, add)) { 
        return ret; 
    } 
    return modifyImplicitNetworkRule(netId, table, permission, add); 
} 
WARN_UNUSED_RESULT int modifyExplicitNetworkRule(unsigned netId, uint32_t table, 
                                                 Permission permission, uid_t uidStart, 
                                                 uid_t uidEnd, bool add) { 

    return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_EXPLICIT_NETWORK, table, fwmark.intValue, mask.intValue, IIF_NONE, OIF_NONE, uidStart, uidEnd); 
} 
WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,uint32_t fwmark, uint32_t mask, const char* iif, const char* oif, uid_t uidStart, uid_t uidEnd) { 
    for (size_t i = 0; i < ARRAY_SIZE(AF_FAMILIES); ++i) { 
        rule.family = AF_FAMILIES[i]; 
        if (int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov))) { 
            return ret; 
        } 
    } 
}
 int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) { 
    int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 
    if (sock != -1 && 
            connect(sock, reinterpret_cast<const sockaddr*>(&NETLINK_ADDRESS), 
                    sizeof(NETLINK_ADDRESS)) != -1 && 
            writev(sock, iov, iovlen) != -1 && 
            (ret = recv(sock, &response, sizeof(response), 0)) != -1) { 
        if (ret == sizeof(response)) { 
            ret = response.err.error;  // Netlink errors are negative errno. 
        }
}

2、 updateRoutes

ConnectivityService.cpp
bool ConnectivityService::updateRoutes(const sp<LinkProperties>& newLp, const sp<LinkProperties>& curLp, bool isLinkDefault) {
        if (isLinkDefault || !(r->isDefaultRoute())) { 
            addRoute(newLp, r, TO_DEFAULT_TABLE); 
        } else { 
            addRoute(newLp, r, TO_SECONDARY_TABLE); 
        } 
}
bool ConnectivityService::addRoute(const sp<LinkProperties>& p, const sp<RouteInfo>& r, 
                                   bool toDefaultTable) { 
    sp<String> pIfName = p->getInterfaceName(); 
    return  (pIfName, p, r, 0, ADD, toDefaultTable); 
} 
bool ConnectivityService::modifyRoute(const sp<String>& ifaceName, const sp<LinkProperties>& lp, const sp<RouteInfo>& r, int32_t cycleCount, bool doAdd, bool toDefaultTable) {

    if (r->getDestination() != NULL && r->getDestination()->getNetworkPrefixLength() == 32 && prefixLength != 32) { 
               sp<LinkAddress> l = new LinkAddress(r->getDestination()->getAddress(), prefixLength); 
               sp<RouteInfo> ri = new RouteInfo(l, r->getGateway()); 
               mAddedRoutes->add(ri); 
               mNetd->addRoute(ifaceName,netId, ri); 
           } else { 
               mAddedRoutes->add(r); 
               mNetd->addRoute(ifaceName,netId, r); 
           } 
}
void NetworkManagementService::addRoute(const android::sp<String> & ifname,int32_t netId, const sp<RouteInfo>& route) { 
    modifyRoute(ifname, netId, mADD, route, DEFAULT()); 
} 
void NetworkManagementService::modifyRoute(const android::sp<String> & ifname, int32_t netId, int32_t action, const sp<RouteInfo>& route, const sp<String>& type) {

    Vector<sp<String> > rsp = mConnector->doCommand(cmd->toString(), ret);
}

NativeDaemonConnector.cpp

Vector<sp<String> > NativeDaemonConnector::doCommand(const sp<String>& cmd, int & ret) { 
    return doCommandLocked(cmd, ret); 
} 
Vector<sp<String> > NativeDaemonConnector::doCommandLocked(const sp<String>& cmd, int& ret) { 
    bool rc = sendCommandLocked(newCmd); 
}
bool NativeDaemonConnector::sendCommandLocked(const sp<String>& command) { 
    return sendCommandLocked(command, NULL); 
} 
bool NativeDaemonConnector::sendCommandLocked(const sp<String>& command, const sp<String>& argument) { 
     if (mOutputStream == NULL) { 
        return false; 
    } else { 
               mOutputStream->write(outCommand, 0, outCommand->length()); 
    } 
    return true; 
} 

socket(netd)
这个socket是在NetlinkManager中创建的

CommandListener.cpp

int CommandListener::NetworkCommand::runCommand(SocketClient* client, int argc, char** argv) { 
         if (add) { 
            ret = sNetCtrl->addRoute(netId, interface, destination, nexthop, legacy, uid); 
        } else { 
            ret = sNetCtrl->removeRoute(netId, interface, destination, nexthop, legacy, uid); 
        } 
}
NetworkController.cpp
int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination, 
                                const char* nexthop, bool legacy, uid_t uid) { 
    return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid); 
} 
int NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination, 
                                   const char* nexthop, bool add, bool legacy, uid_t uid) { 
            if(add) { 
     RouteController::addRoute(interface, destination, nexthop, RouteController::LOCAL_NETWORK); 
            } else { 
                RouteController::removeRoute(interface, destination, nexthop, RouteController::LOCAL_NETWORK); 
            } 
}

RouteController.cpp

int RouteController::addRoute(const char* interface, const char* destination, const char* nexthop, 
                              TableType tableType) { 
    return modifyRoute(RTM_NEWROUTE, interface, destination, nexthop, tableType); 
}
int modifyRoute(uint16_t action, const char* interface, const char* destination, const char*                nexthop, RouteController::TableType tableType) { 
    int ret = modifyIpRoute(action, table, interface, destination, nexthop); 
    return 0; 
} 
int modifyIpRoute(uint16_t action, uint32_t table, const char* interface, 
                                     const char* destination, const char* nexthop) { 
    return sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov));
}
 int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) { 
    int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 
    if (sock != -1 && 
            connect(sock, reinterpret_cast<const sockaddr*>(&NETLINK_ADDRESS), 
                    sizeof(NETLINK_ADDRESS)) != -1 && 
            writev(sock, iov, iovlen) != -1 && 
            (ret = recv(sock, &response, sizeof(response), 0)) != -1) { 
        if (ret == sizeof(response)) { 
            ret = response.err.error;  // Netlink errors are negative errno. 
        }
}

注:socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 套接字AF_NETLINK,则是用于与kernel通讯的接口。通过向量IO向kernel中发送 iov数据,并同时接收响应,错误处理。

NETD
Android5.0之后,网络的功能实现完全转移到netd上面,主要包括ip,路由配置,dns代理设置,带宽控制和流量统计等。
下面是Netd框架示意图,NetworkManagerService和NativeDeamonConnect是java代码,NetworkManagerService作为service随系统启动,java层所有对网络的操作都通过它来完成。
其他都是c++代码,主要完成两个工作:
1、接收上层的命令,完成指定对网络的操作;
2、接收kernel netlink信息,传递到上层。
接收上层命令的工作,通过4个socket完成:
/dev/socket/netd ————– CommandListener
/dev/socket/dnsproxyd ————– DnsproxyListener
/dev/socket/mdns –————– MdnsSdListener
/dev/socket/fwmarkd –————– FwmarkServer

CommandListener接收配置ip,路由,iptables的命令
DnsproxyListener接收查询dns的操作

MdnsSdListener接收针对mdnsd的操作

FwmarkServer用于对特定的socket设置mark值
这里写图片描述
下图是Netlink部分,模块调用关系示例NetlinkManager启动3个socket,用于监听3种不同的event:Uevent,RouteEvent,QuotaEvent。 通过SocketListener实现监听功能,netlink信息,最终通过/dev/socket/netd送到 NetworkManagementService(java代码),分配到注册到它里面的各个观察者实例(Ethernet,wifi等)。

这里写图片描述

作者:xiabodan 发表于2016/12/20 18:45:43 原文链接
阅读:74 评论:0 查看评论

金融时间序列分析:2. 数学分析模型

$
0
0

1. 时间序列模型

1.1 数学模型

随机变量序列{Yt:t=0,1,2,......}称为一个时间序列模型。
t = 0, 1,2,3….
均值函数:

μ=E(Yt)

方差函数:
Var(Yt)=E[(Ytμ)2]

自相关函数:
γt,s=Cov(Yt,Ys)=E[(Ytμ)(Ysμ)]

k阶自相关函数:
γk=Cov(Yt,Ytk)=E[(Ytμ)(Ytkμ)]

自相关系数:
ρk=γkVar(Yt)

自相关函数:Autocorrelation Function(ACF)
这里写图片描述

ACF是一个很重要的概念,在后面你会经常遇到ACF检验,就是通过这个概念去验证一个时间序列是否是平稳的。

1.2 均值,方差,协方差,相关系数

关于样本均值和方差的概念我就不解释了。
下面谈谈协方差和相关系数:
协方差
称E{(X - E(X)) (Y-E(Y))}为随机变量X与Y的协方差,记为Cov(X,Y),即

Cov(X,Y)=E{(XE(X))(YE(Y))}=E(XY)E(X)E(Y)

相关系数
随机变量X,Y的相关系数:

ρxy=Cov(X,Y)Var(X)Var(Y)

|ρxy|<=1

相关系数是用来度量两个随机变量的相关程度指标
ρxy=0时称X,Y不相关;
|ρxy|=1称X,Y完全相关,此时,X,Y之间具有线性函数关系;
|ρxy|=1时,X的变动引起Y的部分变动,|ρxy|越大,X的变动引起Y的变动就越大

1.3 自相关函数,自相关系数

此时我们再来分析下自相关函数,自相关系数
自相关函数
ρt,s度量随机序列Y在t时刻和s时刻的相关程度,由于t和s分别为两个变量,所以ρt,s是一个关于t,s的函数。

一般情况下不会研究两个随意的时刻t,s,通常都是研究固定间隔的时间,比如s = t - l

自相关系数
ρˆl是用于度量随机序列Y在时间间隔为l的相关性。

是由ρt,tl, t = l, l+1, ….一组序列计算而来

这里写图片描述


2. 平稳性

包括严平稳和弱平稳两种, 一般的时间序列都是弱平稳的,所以我们说一个时间序列是平稳的都是指弱平稳。

2.1 定义

严平稳
  定义:给定随机过程X(t),t属于T,其有限维分布组为F(x1,x2,…xn;t1,t2,…,tn),t1,t2,…,tn属于T,对任意n任意的t1,t2,…,tn属于T,任意满足t1+h,t2+h,…,tn+h属于T的h,总有
  F(x1,x2,…xn;t1,t2,…,tn)=F(x1,x2,…xn;t1+h,t2+h,…,tn+h)称此过程严平稳.

严平稳是一种条件比较苛刻的平稳性定义,它认为只有当序列所有的统计性质都不会随着时间的推移而发生变化时,该序列才能被认为平稳.

一般的时间序列都不是严平稳的

弱平稳
弱平稳才是我们考察时间序列的平稳性。
其定义如下:
假定某个时间序列由某一随机过程(stochastic process)生成,即假定时间序列{Xt}(t=1, 2, …)的每一个数值都是从一个概率分布中随机得到的。如果经由该随机过程所生成的时间序列满足下列条件:

  • 均值E(Xt)=m是与时间t 无关的常数;
  • 方差Var(Xt)=s^2是与时间t 无关的常数;
  • 协方差Cov(Xt,Xt+k)=gk 是只与时期间隔k有关,与时间t 无关的常数;

2.2 意义

所谓平稳性通俗讲就是,时间序列的统计规律不会随着时间的推移而发生变化。
一个时间序列只有是平稳的,才能够进行预测分析,否则一切分析的结果都没有任何意义。


3. 弱平稳时间序列自相关性

这部分需要假设检验的知识,可以参考我之前的一篇文章:
假设检验
其基本原理是:在一个已知的假设下,如果一个特定事件发生的概率格外小,那么我们认为, 这个假设可能不对。

3.1 ACF检验

假设

H0:ρ1=0vsHa:ρ10

检验统计量
这里写图片描述

判别条件:
如果 |t| > Zα/2 或者 p-value < α,则拒绝H0。

3.2 混成检验 Ljung-Box

这里写图片描述

作者:xiyanlgu 发表于2016/12/20 18:53:56 原文链接
阅读:58 评论:0 查看评论

【nginx源码学习与运用 九】搭建第一个nginx的http模块

$
0
0

【nginx源码学习与运用】系列博客中的示例代码在csdn的代码托管服务器CODE上,地址https://code.csdn.net/u012819339/nginx_study ,你可以将其自由的下载到本地,或者通过Git来实时获取更新


本篇博客将简单展示在nginx上开发一个简单的模块来处理请求的整个流程,并给出实例。至于细节部分还需各位童鞋多多参考其他资料,多多领悟

创建自己的代码目录

在nginx的src目录下新建一个目录mymodule,并在该目录下创建两个文件config文件和ngx_http_mytest_module.c文件

编写config

config内容及解释如下:

ngx_addon_name=ngx_http_mytest_module
HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"

ngx_addon_name:是代指模块名称,仅在configure执行时使用
HTTP_MODULES:保存nginx中所有的HTTP模块名称,名称之间空格隔开
NGX_ADDON_SRCS:指定编译模块的源代码
ngx_addon_dir:等价于执行configure的时候–add-module=PATH的PATH参数

编写自己的模块源码

ngx_http_mytest_module.c源码如下:

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_http.h>

//处理用户请求的方法
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
    //设定mytest模块只处理GET或HEAD请求
    if(!(r->method &(NGX_HTTP_GET|NGX_HTTP_HEAD)))
        return NGX_HTTP_NOT_ALLOWED;

    //丢弃请求中的包体
    ngx_int_t rc = ngx_http_discard_request_body(r);
    if(rc != NGX_OK)
        return rc;

    ngx_str_t type = ngx_string("text/plain");
    ngx_str_t respone = ngx_string("hello world, arvik test!"); 
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = respone.len;
    r->headers_out.content_type = type;
    //发送HTTP头部
    rc = ngx_http_send_header(r);
    if(rc == NGX_ERROR || rc > NGX_OK || r->header_only)
    {
        return rc;
    }

    //构造ngx_buf_t结构体准备发送包体
    ngx_buf_t *b;
    b = ngx_create_temp_buf(r->pool, respone.len);
    if(b == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;

    ngx_memcpy(b->pos, respone.data, respone.len);
    b->last = b->pos + respone.len;
    b->last_buf = 1;

    //构造ngx_chain_t传给filter使用
    ngx_chain_t out;
    out.buf = b;
    out.next = NULL;

    return ngx_http_output_filter(r, &out);
}


static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t *clcf;
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_mytest_handler;

    return NGX_CONF_OK;
}


static ngx_command_t ngx_http_mytest_commands[] =
{
    {
        ngx_string("mytest"),
        NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
        ngx_http_mytest,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL
    },
    ngx_null_command
};

//模块接口描述的8个阶段,函数指针都可置NULL
static ngx_http_module_t ngx_http_mytest_module_ctx = 
{
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
};

ngx_module_t ngx_http_mytest_module = 
{
    NGX_MODULE_V1,
    &ngx_http_mytest_module_ctx,
    ngx_http_mytest_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};

生成Makefile

执行以下命令:

./configure --add-module=./src/mymodule/

编译、安装nginx源码

#make
#make install

编译安装好后自己的模块也就嵌在nginx模块里了

修改配置

打开/usr/local/nginx/conf/nginx.conf文件
对应位置增加几行代码如下:

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        //以下3行内容为增加内容
        location /test {
                mytest;
        }
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

启动nginx

/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

运行结果

本地浏览器地址输入http://localhost/test,结果如下:
这里写图片描述

代码已经存上传到这个位置 https://code.csdn.net/u012819339/nginx_study ,在项目的test9目录中,童鞋们可自行下载演示

作者:u012819339 发表于2016/12/20 19:40:42 原文链接
阅读:109 评论:0 查看评论

Android简易实战教程--第四十九话《满屏拖动的控件》

$
0
0

今天做个有意思的效果吧,控件的拖拽,简单实用,逻辑清晰点3分钟看完。

说的很高大上,其实就是拖动Button按钮跟着鼠标位置满手机屏幕跑罢了。


直接上简单的代码吧:

public class MainActivity extends Activity implements View.OnTouchListener {
    private Button mButton;
    private ViewGroup mViewGroup;
    private int xDelta;
    private int yDelta;
    public static final String TAG = "YDL";
    private RelativeLayout.LayoutParams mParams;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mViewGroup = (ViewGroup) findViewById(R.id.root);

        mButton = (Button) findViewById(R.id.id_text);

        mParams = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        mParams.leftMargin = 50;
        mParams.topMargin = 50;

        mButton.setLayoutParams(mParams);

        mButton.setOnTouchListener(this);

    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        //手指触摸控件,就会执行这里。鼠标点击控件位置相对屏幕的坐标
        final int x = (int) event.getRawX();
        final int y = (int) event.getRawY();
        Log.d(TAG, "onTouch: x= " + x + "y=" + y);//x= 192y=185
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                xDelta = x - mParams.leftMargin;//xDelta= 142192-50yDelta=135185-50)得到控件相对自己的坐标位置。(鼠标点击点距离控件左上角)
                yDelta = y - mParams.topMargin;
                Log.d(TAG, "ACTION_DOWN: xDelta= " + xDelta + "yDelta=" + yDelta);//xDelta= 142yDelta=135
                break;
            case MotionEvent.ACTION_MOVE:

                int xDistance = x - xDelta;//x= 199y=185(鼠标移动后下一位置的坐标)- 鼠标相对控件本身的坐标 = 控件位于屏幕上的新坐标位置       xDistance= 57yDistance=50
                int yDistance = y - yDelta;
                Log.d(TAG, "ACTION_MOVE: xDistance= " + xDistance + "yDistance=" + yDistance);//xDistance= 57yDistance=50

                mParams.leftMargin = xDistance;//把新坐标位置设置给控件
                mParams.topMargin = yDistance;
                view.setLayoutParams(mParams);//把坐标位置重新赋值给button
                break;
        }
        return true;
    }


MainActivity实现了OnTouchListener接口,覆写了onTouch方法,每次回调这个方法通过x和y变量记录当前的坐标。

ACTION_DOWN是在按下的时候调用(没抬起来只调用一次),通过xDelta和yDelta来记录第一次按下的点相对于控件左上角的位置,也就是相对距离。

ACTION_MOVE移动的时候不断调用,通过xDistance和yDistance来记录移动的相对距离作为leftMargin和topMargin再动态设置给控件。

最后,调用setLayoutParams方法重新设置控件坐标位置。


文字解释不够多?下面一张图应该更清楚吧?


运行程序快点满屏跑动吧!


喜欢我的朋友可以关注我的博客专栏。

也可以打开微信搜索公众号  Android程序员开发指南  或者手机扫描下方二维码 在公众号阅读更多Android文章。

微信公众号图片:



作者:qq_32059827 发表于2016/12/20 20:06:16 原文链接
阅读:57 评论:0 查看评论

Flutter基础—定位对齐之大小比例

$
0
0

SizedBox控件能强制子控件具有特定宽度、高度或两者都有

import 'package:flutter/material.dart';
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('强制大小'),
      ),
      body: new SizedBox(
        width: 250.0,
        height: 250.0,
        child: new Container(
          decoration: new BoxDecoration(
            backgroundColor: Colors.lightBlueAccent[100],
          ),
        ),
      ),
    );
  }
}
void main() {
  runApp(
    new MaterialApp(
      title: 'Flutter教程',
      home: new LayoutDemo(),
    ),
  );
}

AspectRatio控件能强制子小部件的宽度和高度具有给定的宽高比,以宽度与高度的比例表示。

import 'package:flutter/material.dart';
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('强制比例'),
      ),
      body: new AspectRatio(
        aspectRatio: 3.0 / 2.0,
        child: new Container(
          decoration: new BoxDecoration(
            backgroundColor: Colors.lightBlueAccent[100],
          ),
        ),
      ),
    );
  }
}
void main() {
  runApp(
    new MaterialApp(
      title: 'Flutter教程',
      home: new LayoutDemo(),
    ),
  );
}
作者:hekaiyou 发表于2016/12/20 20:11:50 原文链接
阅读:60 评论:0 查看评论

Linux基本命令-关机与重启命令

$
0
0

shutdown命令(安全)

命令:shutdown [选项] 时间
[选项]:

  • -c:取消前一个关机命令
  • -h:关机
  • -r:重启
    时间格式为 XX:XX,now为马上
    Ex:
    这里写图片描述

其他关机命令

  • halt
  • poweroff
  • init

其他重启命令

  • reboot
  • init 6

系统运行级别

查看系统当前所在级别

命令:runlevel

如下图:5为之前所在级别,3为现在所在级别
这里写图片描述

系统级别大小

这里写图片描述

大小 状态
0 关机
1 单用户(最小程序界面)
2 不完全多用户,不含NFS服务(文件共享服务)
3 完全多用户(字符界面)
4 未分配
5 图形界面
6 重启

退出登录命令

  • logout

在远程登录需要正确退出

作者:u011391629 发表于2016/12/20 20:31:48 原文链接
阅读:58 评论:0 查看评论

个人记录-LeetCode 53. Maximum Subarray

$
0
0

问题:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

More practice:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

问题要求:找到连续的字串能得到的最大和。
如果找到O(N)解法后,试着也使用分治方法解决。

代码示例:

1、普通的O(N)算法
分析可得出如下结论:
1 最大和对应的字串,一定从一个正数开始(负数对和没有任何增益)。
-1 2 3的和,一定小于2 3

2 连续子串中间可以有负数,但负数之前的正数和一定要大于该负数。
1 2 -1 3的和,大于任何单独子串的和。

按照该分析可以写出如下代码:

public class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0];

        int sum = 0;
        for (int i = 0; i < nums.length; ++i) {
            sum += nums[i];

            //记录每次的最大值
            if (sum > max) {
                max = sum;
            }

            //当前连续的子串和为负值,不会有任何增益,舍弃
            if (sum < 0) {
                sum = 0;
            }
        }

        return max;
    }
}

2、分治
分治的思想是将一个大问题,转换为若干个小问题。
对于这个题目,一种可行的思路是:
1 选出数组的中间项,那么最终结果对应的子串,可能包含中间项,也可能不包含中间项。
2.1 如果最终结果对应的子串,不包含中间项,那么可以继续对中间项左边的子串、及右边的子串使用分治算法
2.2 如果最终结果对应的子串,包含中间项,那么最终的结果等于从中间项开始,以左、以右连续最大子串的和。
3 真正的结果,等于以上3种结果的最大值。

按照该分析可以写出如下代码:

public class Solution {
    public int maxSubArray(int[] nums) {
        //divide and conquer
        return maxSubArrayDC(nums, 0, nums.length-1);
    }

    private int maxSubArrayDC(int[] nums, int begin, int end) {
        if (begin == end) {
            return nums[begin];
        }

        int middle = (begin + end) / 2;
        //不包含中间项,计算左边子串的结果
        int leftMax = maxSubArrayDC(nums, begin, middle);

        //不包含中间项,计算右边子串的结果
        int rightMax = maxSubArrayDC(nums, middle+1, end);

        //包含中间项的连续子串
        int leftSum = nums[middle];
        int tmp = nums[middle];
        //左边的最大值
        for (int i = middle - 1; i >= begin; --i) {
            tmp += nums[i];
            if (tmp > leftSum) {
                leftSum = tmp;
            }
        }

        //右边的最大值
        int rightSum = nums[middle+1];
        tmp = nums[middle+1];
        for (int i = middle + 2; i <= end; ++i) {
            tmp += nums[i];
            if (tmp > rightSum) {
                rightSum = tmp;
            }
        }

        //最大值即为结果
        return Integer.max((leftSum+rightSum), Integer.max(leftMax, rightMax));
    }
}
作者:Gaugamela 发表于2016/12/20 21:04:58 原文链接
阅读:50 评论:0 查看评论

经典算法之一:快速排序

$
0
0
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影。

总的说来,要直接默写出快速排序还是有一定难度的,因为本人就自己的理解对快速排序作了下白话解释,希望对大家理解有帮助,达到快速排序,快速搞定

 

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

该方法的基本思想是:

1.先从数列中取出一个数作为基准数。

2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。

3.再对左右区间重复第二步,直到各区间只有一个数。

 

虽然快速排序称为分治法,但分治法这三个字显然无法很好的概括快速排序的全部步骤。因此我的对快速排序作了进一步的说明:挖坑填数+分治法

先来看实例吧,定义下面再给出(最好能用自己的话来总结定义,这样对实现代码会有帮助)。

 

以一个数组作为示例,取区间第一个数为基准数。

0

 1 

72

57

88

60

42

83

73

48

85

初始时,i = 0;  j = 9;   X = a[i] = 72

由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。

从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8]; i++;  这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3]; j--;

 

数组变为:

 1 

48

57

88

60

42

83

73

88

85

 i = 3;   j = 7;   X=72

再重复上面的步骤,先从后向前找,再从前向后找

从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;

从i开始向后找,当i=5时,由于i==j退出。

此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。

 

数组变为:

 1 

9 

48

6

57

42

60

72

83

73

88

85

可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。

上述过程详细步骤:

0:72,6,57,88,60,42,83,73,48,85,x=72

1:48,6,57,88,60,42,83,73,__,85 

2:48,6,57,__,66,42,83,73,88,85

3:48,6,57,42,66,__,83,73,88,85

3:48,6,57,42,66,__,83,73,88,85

4:48,6,57,42,66,72,83,73,88,85

经过这一轮排序后,基准数(72)左边的数都比72小,右边的都比它大,剩下的就是利用分治算法分别解决左右两边的数了。


对挖坑填数进行总结

1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。

2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。

3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。

4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。

照着这个总结很容易实现挖坑填数的代码:

int AdjustArray(int s[], int l, int r) //返回调整后基准数的位置
{
    int i = l, j = r;
    int x = s[l]; //s[l]即s[i]就是第一个坑
    while (i < j)
    {
        // 从右向左找小于x的数来填s[i]
        while(i < j && s[j] >= x)
            j--;
        if(i < j)
        {
            s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑
            i++;
        }

        // 从左向右找大于或等于x的数来填s[j]
        while(i < j && s[i] < x)
            i++;
        if(i < j)
        {
            s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑
            j--;
        }
    }
    //退出时,i等于j。将x填到这个坑中。
    s[i] = x;

    return i;
}

再写分治法的代码:

void quick_sort1(int s[], int l, int r)
{
    if (l < r)
    {
        int i = AdjustArray(s, l, r);//先成挖坑填数法调整s[]
        quick_sort1(s, l, i - 1); // 递归调用
        quick_sort1(s, i + 1, r);
    }
}


这样的代码显然不够简洁,对其组合整理下:

//快速排序
#include <bits/stdc++.h>
using namespace std;
void P(int a[],int n)
{
    for(int i=0; i<n; i++)
        cout<<a[i]<<" ";
    cout<<endl;
}
void quick_sort(int s[], int l, int r)
{
    if (l < r)
    {
        //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
        int i = l, j = r, x = s[l];
        while (i < j)
        {
            while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
                j--;
            if(i < j)
                s[i++] = s[j];

            while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
                i++;
            if(i < j)
                s[j--] = s[i];
        }
        s[i] = x;
        quick_sort(s, l, i - 1); // 递归调用
        quick_sort(s, i + 1, r);
    }
}
int main()
{
    //int a[]= {72,6,57,88,60,42,83,73,48,85};
    int a[]= {10,9,8,7,6,5,4,3,2,1};
    P(a,10);
    quick_sort(a,0,9);//注意最后一个参数是n-1!!!!!
    P(a,10);
    return 0;
}



快速排序还有很多改进版本,如随机选择基准数,区间内数据较少时直接用另的方法排序以减小递归深度。有兴趣的筒子可以再深入的研究下。

注1,有的书上是以中间的数作为基准数的,要实现这个方便非常方便,直接将中间的数和第一个数进行交换就可以了。

本文在此篇博客上做补充:

参考博客:

http://www.cnblogs.com/Braveliu/archive/2013/01/11/2857222.html

http://developer.51cto.com/art/201403/430986.htm

http://blog.csdn.net/wolinxuebin/article/details/7456330

http://www.cnblogs.com/surgewong/p/3381438.html

http://www.ruanyifeng.com/blog/2011/04/quicksort_in_javascript.html


作者:hurmishine 发表于2016/12/20 21:28:01 原文链接
阅读:35 评论:0 查看评论

OpenCV2.4.13+VS2012开发环境配置与实例

$
0
0

1.下载和安装OpenCV SDK

在OpenCV官网的下载页面: http://opencv.org/downloads.html   找到对应OpenCV for Windows版本下载。目前(2016/07/02)官网的最新版本是2015/12/21发布的Version 3.1.0,最新发布是2016/05/19日的Version 2.4.13。

Version 3.1.0只有64位的开发包,还没(不知道未来会不会)支持32位的编译环境,这里使用Version 2.4.13。



下载完成之后双击“opencv-2.4.13.exe”,弹出安装(解压)对话框:


选择安装路径,这里使用的是“D:\ProgramFilesD”,点击“Extract”后开始解压;

值得注意的一点是不需要在安装目录里额外建“opencv”的文件夹,OpenCV安装包解压出来的根目录就是“opencv”。


2.本机环境变量和路径配置

点击开始菜单,右击计算机->属性->高级系统设置->高级->环境变量,打开环境变量设置对话框,如下图:



 


在用户变量里新建变量OpenCV,变量值:D:\ProgramFilesD\opencv\build;



在用户变量里新建变量path,变量值:D:\ProgramFilesD\opencv\build\x86\vc11\bin;

在这里可能有人会有疑问:编译器是VS2012,变量值不应该是XX\vc12\bin吗?注意,在OpenCV配置中,vc11即对应VS2012,vc12对应的是VS2013。

另一点要关注的是上述变量值到底应该是x86还是x64?这里x86还是x64的选择跟你的电脑是32位还是64位无关,vs2012编译环境默认的使用win32编译器,所以选择x86。


在系统变量里编辑(或添加)Path变量,变量值:D:\ProgramFilesD\opencv\build\x86\vc11\bin,注意要使用英文输入下的分号和前面已有的路径分开,添加完之后需要重启或注销计算机,环境变量才会生效。



3. IDE工程项目属性配置

新建Win32控制台应用程序,工程名命名为MyFirstOpenCV,在其后的选项里选择空项目:




右击MyFirstOpenCV工程->添加新建项,在弹出的对话框中选择C++ 文件(.cpp),添加源文件,命名为MyFirstOpenCV.cpp:



在视图目录的下拉菜单中打开属性管理器,在属性管理器的Debug|Win32目录上单击选择“添加新项目属性表”,新建属性表,并命名为OpenCV_Debug_Setting.props,如下图所示:



双击打开属性表OpenCV_Debug_Setting.props。选择通用属性->VC++目录,在包含目录里添加3个目录:

D:\ProgramFilesD\opencv\build\include\opencv2

D:\ProgramFilesD\opencv\build\include\opencv

D:\ProgramFilesD\opencv\build\include




同样在VC++目录下,在库目录里添加1个目录:

D:\ProgramFilesD\opencv\build\x86\vc11\lib




选择通用属性->链接器->输入->附加依赖项,在附加依赖项里添加库文件:

opencv_ml2413d.lib

opencv_calib3d2413d.lib

opencv_contrib2413d.lib

opencv_core2413d.lib

opencv_features2d2413d.lib

opencv_flann2413d.lib

opencv_gpu2413d.lib

opencv_highgui2413d.lib

opencv_imgproc2413d.lib

opencv_legacy2413d.lib

opencv_objdetect2413d.lib

opencv_ts2413d.lib

opencv_video2413d.lib

opencv_nonfree2413d.lib

opencv_ocl2413d.lib

opencv_photo2413d.lib

opencv_stitching2413d.lib

opencv_superres2413d.lib

opencv_videostab2413d.lib




OK,至此,VS2012环境下配置OpenCV2.4.13的工作已经全部完成了,对于之后创建的OpenCV工程,只需要添加本工程的属性配置即可,不再需要一步一步重复配置。

方法:首先保存本工程的属性配置文件OpenCV_Debug_Setting.props到备用文件夹,该属性配置文件在本项目中的路径是:

D:\VS2012Test\MyFirstOpenCV\MyFirstOpenCV

之后在新创建的工程中,在属性管理器中添加OpenCV_Debug_Setting.props属性表即可:



4.OpenCV项目测试

最后让我们来测试一下所做的配置是否OK。

在程序的源文件MyFirstOpenCV.cpp文件中加入如下代码,用于在窗口中显示一幅图片:


  1. <pre name="code" class="cpp">#include <iostream>  
  2. #include<core/core.hpp>  
  3. #include<highgui/highgui.hpp>  
  4.   
  5.   
  6. using namespace cv;  
  7. using namespace std;  
  8.   
  9.   
  10. int main()  
  1. //读入图片,注意图片路径  
  2. Mat image=imread("D:\\Picture\\lena.jpg");  
  3.     
  4. //图片读入成功与否判定  
  5. if(!image.data)  
  6. {  
  7. cout<<"you idiot!where did you hide lena!"<<endl;    
  8.   
  9. //等待按键  
  10. system("pause");  
  11. return -1;  
  12. }  
  13.   
  14.   
  15. //创建一个名字为“Lena”的图像显示窗口,(不提前声明也可以)  
  16. namedWindow("Lena",1);    
  17.   
  18. //显示图像  
  19. imshow("Lena",image);    
  20.   
  21. //等待按键  
  22. waitKey();  
  23. return 0;  
  24. }  



作者:baidu_21578557 发表于2016/12/20 21:58:41 原文链接
阅读:13 评论:0 查看评论

Codeforces Round #388 (Div. 2)D. Leaving Auction(水题呀?)

$
0
0

题目链接:点击打开链接

思路:

我们只要把每个人竞价的最大值存起来, 并且把每个人的所有竞价维护在一个有序数组(方便二分), 对于一组询问,  我们从大到小遍历这k个数,把不在这k个数的最终竞价最大的两个人找到(复杂度O(K)), 然后在竞价最大的那个人的set里二分第二大的人的竞价最大值就行了。

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <ctime>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 2e5 + 10;
int T,n,m,a[maxn],b[maxn],maxv[maxn];
set<int> g[maxn];
set<int> :: iterator it;
struct node {
    int id, pos;
    node(int id=0, int pos=0):id(id), pos(pos) {}
    bool operator < (const node& rhs) const {
        if(pos != rhs.pos) return pos < rhs.pos;
        else return id < rhs.id;
    }
};
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d%d", &a[i], &b[i]);
        g[a[i]].insert(b[i]); /// 每个人拍卖的价格
        maxv[a[i]] = b[i];
    }
    vector<node> res;
    for(int i = 1; i <= n; i++) {
        if(maxv[i]) res.push_back(node(i, maxv[i])); ///所有来参加竞拍的人, id和最大拍卖价格
    }
    sort(res.begin(), res.end());
    int q; scanf("%d", &q);
    while(q--) {
        int k; scanf("%d", &k);
        vector<node> cur;
        for(int i = 1; i <= k; i++) {
            int v; scanf("%d", &v);
            if(maxv[v]) cur.push_back(node(v, maxv[v]));  /// 扔掉的人
        }
        sort(cur.begin(), cur.end());
        int len = cur.size();
        int l1 = res.size()-1, l2 = cur.size()-1;
        vector<node> ans;
        while(true) {
            if(l1 < 0) break;
            else if(l2 < 0 && l1 >= 0) ans.push_back(res[l1]), l1--;
            else if(cur[l2].pos < res[l1].pos) ans.push_back(res[l1]), l1--;
            else if(cur[l2].pos == res[l1].pos) l1--, l2--;
            if(ans.size() >= 2) break;
        }
        if(ans.size() == 0) printf("0 0\n");
        else if(ans.size() == 1) {
            it = g[ans[0].id].begin();
            printf("%d %d\n", ans[0].id, *it);
        }
        else {
            int v = maxv[ans[1].id];
            it = g[ans[0].id].upper_bound(v);
            printf("%d %d\n", ans[0].id, *it);
        }
    }
    return 0;
}


作者:weizhuwyzc000 发表于2016/12/20 22:02:50 原文链接
阅读:20 评论:0 查看评论

React实战-javascript访问服务端数据大全

$
0
0

 

React作为新的前端的开发框架,确切的说只是前端页面库。然而在整个前端应用中,数据控制,数据模型、访问服务端则具有很大的灵活性,这也是Reactjs与Angular的主要不同点之一。在数据控制和数据模型方面,主流的是采用Redux,而在服务器访问方面则没有哪个成为主流方式,你可以自己写调用方法,也可以采用第三方JS库,通常有以下几种方法:

  • 通过XMLHttpRequest对象进行访问

XMLHttpRequest对象自身就带有访问服务端端功能,在ie老版本中为ActiveXObject,含有open,send, onreadystatechange等方法,分别负责定义请求,发送请求,获取返回值等功能。如:

var xhttp;

  xhttp=new XMLHttpRequest();

  xhttp.onreadystatechange = function() {

    if (this.readyState == 4 && this.status == 200) {

      cFunction(this);

    }

 };

  xhttp.open("GET", url, true);

  xhttp.send();

}

  • 通过Jquery对象进行访问

Jquery是至今运用最为广泛的js库了,它提供了丰富的服务端访问方法。调用和设置也不复杂,主要通过$.ajax进行方法。如:$.post(...)

  .done(function (data) {    

    //...

  }).fail(function (jqXHR, status, error) {    

    console.log(jqXHR.responseText);    

  });

  • Angular访问方式

由于Angular是完整的前端框架,控制和访问也提供了完整的方式,如:

angular.module('cfd', [])


.factory('StudentService', ['$http', function ($http) {

    var path = 'data/people/students.json';

    var students = [];


    /* In the real app, instead of just updating the students array

     * (which will be probably already done from the controller)

     * this method should send the student data to the server */

    var save = function (student) {

        if (student.id === null) {

            students.push(student);

        } else {

            for (var i = 0; i < students.length; i++) {

                if (students[i].id === student.id) {

                    students[i] = student;

                    break;

                }

            }

        }

    };


    /* Populate the students array with students from the server */

    $http.get(path).success(function (data) {

        data.forEach(function (student) {

            students.push(student);

        });

    });


    return {

        students: students,

        save:     save

    };     

}])

  • Fetch访问方式

Fetch提供了一个全局的简便的访问http异步请求的方式。如:

ar myHeaders = new Headers();


var myInit = { method: 'GET',

               headers: myHeaders,

               mode: 'cors',

               cache: 'default' };


var myRequest = new Request('flowers.jpg', myInit);


fetch(myRequest)

.then(function(response) {

  return response.blob();

})

.then(function(myBlob) {

  var objectURL = URL.createObjectURL(myBlob);

  myImage.src = objectURL;

});

  • SuperAgent访问方式

SuperAgent提供了简单的访问服务端方式,主要针对http,https的Ajax访问,简单精炼的方法满足了普通应用访问服务端端各类常见访问方式,包括数据包头,包体的设置,get、put、post和delete的操作,文本与文件的传递等,学习曲线极低,强烈推荐,官网说明:https://visionmedia.github.io/superagent/#test-documentation。如:

request

   .post('/api/pet')

   .send({ name: 'Manny', species: 'cat' })

   .set('X-API-Key', 'foobar')

   .set('Accept', 'application/json')

   .end(function(err, res){

     if (err || !res.ok) {

       alert('Oh no! error');

     } else {

       alert('yay got ' + JSON.stringify(res.body));

     }

   });

  • 其他方式

除了以上介绍的,你还有选择Nodehttp,fetch polypill,node-fetch,isomorphic-fetch,axios,request,reqwest等。每种都有自身的优缺点和使用限制,依据整体开发任务进行合理选择吧,没什么绝对的好坏之分。

作者:loveu2000000 发表于2016/12/20 22:06:54 原文链接
阅读:16 评论:0 查看评论

springMVC源码分析--HandlerMethod

$
0
0

在之前的博客中我们已经接触过HandlerMethod,接下来我们简单介绍一下HandlerMethod,简单来说HandlerMethod包含的信息包括类、方法和参数的一个信息类,通过其两个构造函数我们就可以了解其功能,对应着springMVC的Controller来说就是某个url对应的某个Controller执行的方法。

/**
	 * Create an instance from a bean instance and a method.
	 */
	public HandlerMethod(Object bean, Method method) {
		Assert.notNull(bean, "Bean is required");
		Assert.notNull(method, "Method is required");
		this.bean = bean;
		this.beanFactory = null;
		this.beanType = ClassUtils.getUserClass(bean);
		this.method = method;
		this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
		this.parameters = initMethodParameters();
		this.resolvedFromHandlerMethod = null;
	}


/**
	 * Create an instance from a bean instance, method name, and parameter types.
	 * @throws NoSuchMethodException when the method cannot be found
	 */
	public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
		Assert.notNull(bean, "Bean is required");
		Assert.notNull(methodName, "Method name is required");
		this.bean = bean;
		this.beanFactory = null;
		this.beanType = ClassUtils.getUserClass(bean);
		this.method = bean.getClass().getMethod(methodName, parameterTypes);
		this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
		this.parameters = initMethodParameters();
		this.resolvedFromHandlerMethod = null;
	}


完整源码如下:

public class HandlerMethod {

	/** Logger that is available to subclasses */
	protected final Log logger = LogFactory.getLog(getClass());

	private final Object bean;

	private final BeanFactory beanFactory;

	private final Class<?> beanType;

	private final Method method;

	private final Method bridgedMethod;

	private final MethodParameter[] parameters;

	private final HandlerMethod resolvedFromHandlerMethod;

	//创建一个实例,根据bean实例和method方法
	public HandlerMethod(Object bean, Method method) {
		Assert.notNull(bean, "Bean is required");
		Assert.notNull(method, "Method is required");
		this.bean = bean;
		this.beanFactory = null;
		this.beanType = ClassUtils.getUserClass(bean);
		this.method = method;
		this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
		this.parameters = initMethodParameters();
		this.resolvedFromHandlerMethod = null;
	}
	//根据bean,方法名以及参数类型创建实例
	public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
		Assert.notNull(bean, "Bean is required");
		Assert.notNull(methodName, "Method name is required");
		this.bean = bean;
		this.beanFactory = null;
		this.beanType = ClassUtils.getUserClass(bean);
		this.method = bean.getClass().getMethod(methodName, parameterTypes);
		this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
		this.parameters = initMethodParameters();
		this.resolvedFromHandlerMethod = null;
	}
	//根据bean名称,BeanFactory工厂和method方法创建实例
	public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
		Assert.hasText(beanName, "Bean name is required");
		Assert.notNull(beanFactory, "BeanFactory is required");
		Assert.notNull(method, "Method is required");
		this.bean = beanName;
		this.beanFactory = beanFactory;
		this.beanType = ClassUtils.getUserClass(beanFactory.getType(beanName));
		this.method = method;
		this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
		this.parameters = initMethodParameters();
		this.resolvedFromHandlerMethod = null;
	}

	protected HandlerMethod(HandlerMethod handlerMethod) {
		Assert.notNull(handlerMethod, "HandlerMethod is required");
		this.bean = handlerMethod.bean;
		this.beanFactory = handlerMethod.beanFactory;
		this.beanType = handlerMethod.beanType;
		this.method = handlerMethod.method;
		this.bridgedMethod = handlerMethod.bridgedMethod;
		this.parameters = handlerMethod.parameters;
		this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;
	}
	private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
		Assert.notNull(handlerMethod, "HandlerMethod is required");
		Assert.notNull(handler, "Handler object is required");
		this.bean = handler;
		this.beanFactory = handlerMethod.beanFactory;
		this.beanType = handlerMethod.beanType;
		this.method = handlerMethod.method;
		this.bridgedMethod = handlerMethod.bridgedMethod;
		this.parameters = handlerMethod.parameters;
		this.resolvedFromHandlerMethod = handlerMethod;
	}


	private MethodParameter[] initMethodParameters() {
		int count = this.bridgedMethod.getParameterTypes().length;
		MethodParameter[] result = new MethodParameter[count];
		for (int i = 0; i < count; i++) {
			result[i] = new HandlerMethodParameter(i);
		}
		return result;
	}

	public Object getBean() {
		return this.bean;
	}

	public Method getMethod() {
		return this.method;
	}

	public Class<?> getBeanType() {
		return this.beanType;
	}

	protected Method getBridgedMethod() {
		return this.bridgedMethod;
	}
	
	public MethodParameter[] getMethodParameters() {
		return this.parameters;
	}

	public HandlerMethod getResolvedFromHandlerMethod() {
		return this.resolvedFromHandlerMethod;
	}

	public MethodParameter getReturnType() {
		return new HandlerMethodParameter(-1);
	}

	public MethodParameter getReturnValueType(Object returnValue) {
		return new ReturnValueMethodParameter(returnValue);
	}

	public boolean isVoid() {
		return Void.TYPE.equals(getReturnType().getParameterType());
	}

	//获取方法上的注解,单个注解,如果没有注解则返回方法本身
	public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
		return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
	}

	//创建handlerMethod
	public HandlerMethod createWithResolvedBean() {
		Object handler = this.bean;
		if (this.bean instanceof String) {
			String beanName = (String) this.bean;
			handler = this.beanFactory.getBean(beanName);
		}
		return new HandlerMethod(this, handler);
	}
	@Override
	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof HandlerMethod)) {
			return false;
		}
		HandlerMethod otherMethod = (HandlerMethod) other;
		return (this.bean.equals(otherMethod.bean) && this.method.equals(otherMethod.method));
	}

	@Override
	public int hashCode() {
		return (this.bean.hashCode() * 31 + this.method.hashCode());
	}

	@Override
	public String toString() {
		return this.method.toGenericString();
	}


	/**
	 * A MethodParameter with HandlerMethod-specific behavior.
	 */
	protected class HandlerMethodParameter extends SynthesizingMethodParameter {

		public HandlerMethodParameter(int index) {
			super(HandlerMethod.this.bridgedMethod, index);
		}

		@Override
		public Class<?> getContainingClass() {
			return HandlerMethod.this.getBeanType();
		}

		@Override
		public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) {
			return HandlerMethod.this.getMethodAnnotation(annotationType);
		}
	}


	/**
	 * A MethodParameter for a HandlerMethod return type based on an actual return value.
	 */
	private class ReturnValueMethodParameter extends HandlerMethodParameter {

		private final Object returnValue;

		public ReturnValueMethodParameter(Object returnValue) {
			super(-1);
			this.returnValue = returnValue;
		}

		@Override
		public Class<?> getParameterType() {
			return (this.returnValue != null ? this.returnValue.getClass() : super.getParameterType());
		}
	}

}




作者:qq924862077 发表于2016/12/21 19:09:50 原文链接
阅读:154 评论:0 查看评论

深度强化学习系列(三)Value iteration Network

$
0
0

原创文章,转载请标明出处:http://blog.csdn.net/ikerpeng/article/details/53784021
知乎同步发布:https://zhuanlan.zhihu.com/p/24478944

交流请加群:580043385


今天这个歪楼以下,插播今年NIPS的最佳论文,也是强化学习的一篇论文,叫做 Value iteration Network.

这一篇强化学习的论文是为了解决 强化学习当中泛化能力差的问题,为了解决这个问题,引入了一个 Learn to plan 的模块。

本文的最大创新:在一般性的策略(Policy representation)表示当中加入了一个 规划模块(Planing module)。作者认为加入这个模块的motivation是很自然的,因为决解一个空间的问题的时候都不是单纯的解决这个问题,而是要在这个空间当中去计划。

总结VIN的创新点,我觉得主要是以下的几个点:

1. 将奖励函数和转移函数也参数化,并且能够求导;

2. 引入了一个空间辅助策略的求解,使得policy更具有泛化能力;

3. 在策略的求解当中引入attention机制;

4. 将VI module的设计等价为一个CNN网络,且能够使用BP算法更新网络。

作者定义了一个MDP 空间M,这个空间由一系列的tuple构成,也就是一些列的 状态,动作,转移,奖励数据元组,M决定着我们的最终的策略。那么通过这个 MDP空间的数据M得到的一个策略 policy并不是一个具有很好的泛化能力的策略,因为策略局限在这个数据空间当中。因此,作者假设得到了未知的数据空间M‘,在这个空间当中存在最优的plan包含了M空间当中的最优化策略的重要信息。 其实这样的假设就好像是M仅仅是这个MDP空间当中的一部分的采样轨迹,加上M'像是对于这一个空间当中的轨迹的一个补充。

做了这样一个假设之后,作者用了一个比较巧妙的做法: 并不是去求解这一个空间,而是通过让在 M空间当中的policy能够同样解决M'空间当中的问题,以至于可以将M'空间当中的策略的解元素加入到M的策略当中。

为了简化这个问题,作者认为在数据空间M'当中的 奖励R'和转移概率P' 同样依赖于在M数据空间当中的观测(observations)(我觉得这样的假设也是合理的,因为R 和P是和 s 和a相关的)。在做了这样的假设之后,作者引入了两个函数fR和fP 分别用于的参数化 奖励R'和转移概率P'。函数fR为一个奖励函数映射:当输入的状态图,计算出对应的奖励值;例如,在接近于目标附近的状态得到的奖励值就比较高,而接近于障碍物的状态得到的奖励值就越低;fP 是一个状态转移的函数,是在状态下的确定性的转移动作。

我们假设已经得到了M'空间的数据,那么通过通过VI module都能够得到这个数据空间当中的值函数V'*(s),那么如何来使用这个结果勒?

基于这两点观察,作者巧妙的设计了VI网络第一.,对于MDP空间的当中的所有的状态s,所得到的值函数V'*(s),那么M'空间当中的最优plan 的所有的信息就被编码到值函数当中;因此,当把这个值函数当作额外的信息加入到M空间的policy当中的时候,从policy当中就可以得到要得到M'空间当中的最优计划的完备的信息。 第二,对于值函数V'*(s)的求解实际上只是依赖于一个状态的子集。因为从状态s能够进行状态转移的状态实际上并不多(也就是临近的几个了)。因此,这个VI模块存在两个特点,一个是产生一个将所有的关于最优的plan 信息都编码的值函数V'*(s);另一个则是将产生一个attention机制,集中在可能的转移当中。于是在一般性的强化学习算法当中便可以加入一个plan 的模块。整体的形式如下:

接下来我们再来看看这个model的具体的实现细节,对于这个VI module,作者将它描述为:一种能够进行规划计算的可导的神经网络(a NN that encodes a differentable planing computation ) 。 因此,我们可以看出作者将它看作是一种的新的神经网络解构。那么,作者为什么会这样说叻? 主要是基于这样的观察:VI的每一次迭代都可以看作是将上一次迭代的值函数Vn 和奖励函R 经过卷积层以及 max-poling层(迭代更新实际上就是每一次找到一个最大的V值来更新当前值函数);因此,在每一个特征图当中实际上可以看作是一个具体的action对应的值函数的结果(也就是Q函数啦);有多少个动作就会对应多少张特征图(这是使用action有限的情况来理解,那我认为连续的action是可用通过一个特征向量来表示的)。那么卷积层当中的卷积和的参数正好对应于 状态的转移概率。如下图所示:

基于这样的观察,作者就提出了本文的VI Network,表达式为:Q_{\bar{a} ,i,j} =\sum_{l,i,j}^{}{W_{l,i,j}^{\bar{a} }\bar{R}_{l,i^{'} -i,j^{'}-j}  } 并且在得到的结果当中,对不同通道的Q值进行 max-pooling操作。那我们来理解这个表达式,在表达式当中的l 表示的是各个动作action对应的R层,a其实对应于l; 累加当中的 表示邻近于这个位置的一个区域索引。W 就是网络的参数了,也就是一个卷积核,表示的是可以到周围的几个Q的概率;经过最后的 跨通道的Max-pooling 得到就是一次迭代后的值函数的值。于是这样这个网络具备了值迭代的功能,同时也能够像CNN一样通过BP算法来进行网络的更新。

那么在有了这样的结构之后,如何进行以及Attention模块的设计就是VI设计当中要完成的了。

下面通过一个实验进一步的理解这个网络解构:Grid walking的实验。

如下图所示,是一个28*28 的格子地图,在这个封闭的范围内 随机生成的黑色部分就是障碍物,而其余白色的地方就是能够行走的地方。实验当中,要解决的任务就是给定一个起点位置,需要智能体找到最优的路径到达目的地。(图中的蓝色线是专家样本,橘红为VIN得到的预测结果)

那么在这个实验当中,其实很多经典的算法都能够求解出一个比较好的解但是本文关注的是,通过VI模块之后,网络是否具备有plan的能力。 那么在设计网络的过程当中,这里的M'和真正的MDP空间一样,而函数是为了使得 输入的状态image能够map到一个合理的reward,也就是说,通过这个函数,对于接近于obstacles的位置得到的奖励就应该很小,而在没有障碍物或者是接近于Goal的位置得到的奖励就应该很高。对于函数fR fP 这里直接通过一个3*3 的卷积核进行表示,因为作者认为状态的转移是一种局部的转移。对于迭代的次数的K的选择适合 Grid的大小相关的;最后的Attention机制的设计,作者将其表示为,选出和输出状态具有相同s的Q ,把这个plan的结果作为一般的强化学习算法的输入(例如使用TRPO算法进行训练)。训练好了之后,在一些随机生成的样本上面进行测试(包括起始位置随机,目标位置随机以及障碍物位置随机等等,得到的结果是:VIN预测的准确率高于其余的算法;在越复杂的情况当中表现力就越优于一般的算法,并且具有更强的泛化能力。

在将其同CNN,以及FCN网络的能力进行比较。分别在三种不同大小的Grid上面进行了比较,VIN网络的能力均超过了其余两种,越复杂的问题当中优势越明显。

注文章当中的M‘就是原文当中的\bar{M}

iker Peng 2016年 12月21日

\bar{M}

\bar{M}

作者:u012192662 发表于2016/12/21 19:14:49 原文链接
阅读:171 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live
<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>