Linux Developer开放文档

Contents:

订阅列表

第Alpha1期

Author:江湖郎中
Date:2013-11-24
Category:Linux
Tags:ArchLinux
QQ群号:20506135

很荣幸的向各位Linux开发QQ群的成员宣布《GNU/Linux Developer》第alpha1期发布了!

我曾怀着虔诚的心朝拜 GNU 神圣殿堂,它的光芒始终照耀着我前行。

自由软件与开源软件是为了更好的尊重我们的劳动成果,消除版权所保护所不能适应的更迅速发展的软件行业的一种机制,通过适当的条款来保护合作与分享,这正在形成一种社会化开发的新趋势。 编程一小时 更促使社会化开发的范围由 github 等code群体扩展为整个社会群体的行为,商业软件行为本身没有错误,只是原有的开发模式已经不适应未来的发展趋势。 自由/开源不等于免费,参与你所使用的软件的开发,为你使用的软件贡献代码、捐赠或付费,尊重授权协议,尊重我们共同的劳动成果。

本期专题:Archlinux安装

http://distrowatch.com/images/yvzhuwbpy/arch.png

作者:猫猫

为了自由的名义

在一个应该考虑晚上吃蹄花还是羊肉汤的时候,郎中在小窗口里说让我做第一期订阅的掌勺,我勒个去,亚历山大啊。不过,这样安排也是有一定道理的,按年龄来的呗……

说起来其实真心的很仓促,一点准备都没有,想话题的时候,嗖的一声脑子都不知道去哪了。上次帮人赢键鼠套的时候,改ppt还看了好几天《人月神话》呢,这回只想了一个晚上,好吧,上述言论的中心思想是:这期不准拍砖,留着砖下期拍郎中去。

没啥好说的,那就说说Archlinux吧... [更多]

ArchLinux安装手记

基本上来说呢,自己手动搞一下ArchLinux,会对Linux有一个更为深入的理解。这货没有Fedora或者Ubuntu那样方便的安装程序用于安装,而是所有的步骤和操作都需要自己动手完成... [更多]

通过SSH远程安装Archlinux

其实在引导起来以后,已经是一个功能比较完备的简装系统了,所以为何不启动完成后就打开SSH,然后远程来安装。至少,在SSH客户端里面,原来要通过敲键盘输入的东西,可以直接ctrl+c、ctrl+v了... [更多]

把Archlinux安装到U盘

最近突然发现手头的笔记本硬盘突然变缺稀了,主要是之前又一次手贱买了个装两块笔记本硬盘的raid盒子,后来又把IDE的移动硬盘弄坏了,于是就悲剧了,扯来扯去就剩一个SSD和一个给小猫做看动画用的移动硬盘了,于是俩笔记本都陷入了要悲剧的边缘。 后来想,1501这朵奇葩,既然电池啥的都已经烈士了,而且这货又有着可以拿去铺地的身材,所以干脆了,直接买了俩ScanDisk的小魔豆,插到USB上也几乎看不出来,然后装Archlinux到魔豆里,然后这货就放那滚着玩了... 更多

给Archlinux安装中文字体

起来xfce4,打开chrome,我勒个去,中文变成口口版了,突然很怀念当初做wm的ROM的时候,把字体删了…… 更多

Archlinux自动连接wifi和自动启动sshd和自动连接无线网络
自动连接wifi,前提是已经生成好了无线配置文件,位置在/etc/netctl,比如wlan0-SSID(这里的SSID需要替换成你的真实的SSID名字)...
更多

资源推荐

基于VBOX的各版本Linux OVA

作者:猫猫

VirtualBox的OVA镜像文件
c/c++资源(源码、开发工具、开发库)

作者:江湖郎中

c/c++开发工具,编译器,调试分析,构建,开发库,源码

群内问答

Q: _aio_在网络上的应用?

[济南]江湖郎中: ___nginx___使用了_aio_,它使用的方式是_epoll+libaio+eventfd_的方式

Q: lamp怎么安装

[湘]Livenux: aptitude install lamp

Q: Openwrt是什么

[绵阳]空如也: openwrt是一个基于Linux的OS,主要用于路由器

一段代码

1
2
3
4
5
6
7
8
9
 #!/usr/bin/env bash
 #获取ip更新并发送邮件
 ip_log=ip.log
 now_ip=$(curl ifconfig.me)
 old_ip=$(cat $ip_log)
 if [[ "$now_ip" != "$old_ip" ]]; then
       echo "$now_ip" > $ip_log
       mutt -s "Ip changed" xxx@gmail.com < ip.log
 fi

成员推荐

http://www.wangxiaomao.net/mdphoto.png
网名:猫猫
群ID:[济南]猫猫
主页:猫猫
技术:杂食的
简介:别人以为我是只企鹅,可是我希望自己做只猫

注解

说明

欢迎群成员自荐自己的blog文章和收集的资源,发 邮件 给我,如果有意见或建议都可以mail我。 如果无法直接在邮件内查看,请访问 github上的页面网站 。 我们在github上开放编辑希望大家能参与到其中。

第Alpha2期

Author:猫猫
Date:2013-11-24
Category:publication
Tags:Python, bigdata
QQ群号:20506135
微信号:linux_developer
专题作者:唯一

《GNU/Linux Developer》第 Aplha2 期在春节前和大家见面了,本期 唯一 将为大家带来专题 使用Python构建简易推荐系统

本期专题:使用Python简易推荐系统的构建

作者: 唯一

很惭愧的,被 猫猫 给坑了,让我一个半桶水的家伙,跟大家分享个挺好玩的东西。尽管不是挺深入,但是绝对够科普。

个性化推荐是根据用户的兴趣特点和购买行为,向用户推荐用户感兴趣的信息和商品。 随着电子商务规模的不断扩大,商品个数和种类快速增长,顾客需要花费大量的时间才能找到自己想买的商品。 这种浏览大量无关的信息和产品过程无疑会使淹没在信息过载问题中的消费者不断流失。为了解决这些问题,个性化推荐系统应运而生。 个性化推荐系统是建立在海量数据挖掘基础上的一种高级商务智能平台,以帮助电子商务网站为其顾客购物提供完全个性化的决策支持和信息服务。 参考

说白了,推荐系统就是你在淘宝或者亚马逊购买东西的时候,应该可以看到页面中,会出现由网站向你推荐的商品,往往那些商品会让你觉得很适合你,据说,推荐系统为亚马逊带来的的利润是30%,也就是意味着有30%的成交量是用户因为网站的推荐而购买的。

接下来会以代码加讲解的形式来讲述这个专题。 OK,首先我们今天是用最简单的方式来构建推荐系统,这个方式被称之为协同过滤,意思就是大家一起协同来过滤出一些有用的信息(我猜的)。 这种方式是基于用户的(还有基于内容之类的方式,由于比较深入就不讲究了)。 大家对电影可能比较熟悉,也有去过豆瓣之类的站点为自己看过的电影打分吧。接下来,我们就自己模拟一堆数据,来做演示。

perfers = {
    'Tom': {'Movie1': 2.5, 'Movie2': 3.5, 'Movie3': 3.0, 'Movie4': 3.5, 'Movie5': 2.5, 'Movie6': 3.0},
    'Jackson': {'Movie1': 3.0, 'Movie2': 3.5, 'Movie3': 1.5, 'Movie4': 5.0, 'Movie6': 3.0, 'Movie5': 3.5},
    'Scotte': {'Movie1': 2.5, 'Movie2': 3.0, 'Movie4': 3.5, 'Movie6': 4.0},
    'Abby': {'Movie2': 3.5, 'Movie3': 3.0, 'Movie6': 4.5, 'Movie4': 4.0, 'Movie5': 2.5},
    'Aimee': {'Movie1': 3.0, 'Movie2': 4.0, 'Movie3': 2.0, 'Movie4': 3.0, 'Movie6': 3.0, 'Movie5': 2.0},
    'Angelia': {'Movie1': 3.0, 'Movie2': 4.0, 'Movie6': 3.0, 'Movie4': 5.0, 'Movie5': 3.5},
    'Jack': {'Movie2': 4.5, 'Movie5': 1.0, 'Movie4': 4.0}
}

在这里,我们用perfers这个字典来保存Tom、Jackson...Jack等用户对不同的电影的评分,如果你们接下来有兴趣去试一下的,可以去调用豆瓣的接口收集一些用户对不同的电影的评分。 这里有一些用户会有其他用户没有评分过的电影的评分,这里假设没有评分就是没有看过。 OK,接下来,我们要引入一个概念,那个概念就是用户的相似度,我们如何判断两个用户之间的相似度呢?

我们在数学上应该学过两条点之间的距离,也就是欧几里得距离欧几里得距离会等于 sqrt(sum(xs-ys,2)) 参考 ,

因此我们定义一个函数

相似度 = 1 /(1 + 欧式距离)

加1 是为了防止距离为0

def sim_distance(prefs, person1, person2):
    si = {}
    for it in prefs[person1]: #找出共同点
        if it in prefs[person2]:
            si[it] = 1
    if len(si) == 0:
        return 0
    pSum = math.sqrt(sum(pow(prefs[person1][it] - prefs[person2][it],2) for it in si))
    return 1.0 / (1 + pSum)

运行下面的结果得到

>>> print sim_distance(perfers,"Tom","Jackson")
>>> 0.294298055086

欧几里得距离评价法是一种比较简单的方法。但是由于存在一些用户总是倾向于评分过高或过低(相对平均值), 这时兴趣相似的用户并不能通过此方法计算出来。Pearson相关系数是根据两组数据与某一直线的拟合程度来衡量的。 OK,Pearson相关系数,又叫做 皮尔逊相关系数 ,(我也看不懂,直接扔代码...)

def sim_pearson(prefer, person1, person2):
    sim = {}

    #查找双方都评价过的项
    for item in prefer[person1]:
        if item in prefer[person2]:
            sim[item] = 1           #将相同项添加到字典sim中

    #元素个数
    n = len(sim)
    if len(sim) == 0:
        return 0

    # 所有偏好之和
    sum1 = sum([prefer[person1][item] for item in sim])  #1.sum([1,4,5,,,])  2.list的灵活生成方式!
    sum2 = sum([prefer[person2][item] for item in sim])

    #求平方和
    sum1Sq = sum( [pow(prefer[person1][item], 2) for item in sim] )
    sum2Sq = sum( [pow(prefer[person2][item], 2) for item in sim] )

    #求乘积之和 ∑XiYi
    sumMulti = sum([prefer[person1][item] * prefer[person2][item] for item in sim])
    num1 = sumMulti - (sum1*sum2/n)
    num2 = math.sqrt((sum1Sq-pow(sum1,2) / n) * (sum2Sq - pow(sum2, 2) / n))
    if num2 == 0:
        return 0
    return num1 / num2

测试下

>>> print sim_pearson(perfers, "Tom", "Jackson")
>>> 0.396059017191

看到了吧,通过上述的方式我们可以计算出一个两个用户之间的相似度(也就是对同一种东西的看法的相似度,那所谓的推荐系统是不是呼之欲出了呢)。没错,刚刚开始最简单的推荐系统就是通过计算每一个用户跟其他用户的相似度,然后按照相似度排序完之后,将相似度高的A向B推荐B没有接触过而A已经接触过的东西。

小技巧

这种方式也就是基于用户的协同过滤,此时用于物品基本上跟用户之间的比例差不大的情况下才适合。如果用户多了呢,此时怎么办,留给大家的思考。

OK,老规矩,继续贴代码。此时定义一个函数名字叫做 topMatches 用来得到某个人的排序过的用户匹配度,代码相当简单就不解释了。

def topMatches(prefs, person, n = 5, similarity = sim_pearson):
    scores=[(similarity(prefs, person, other),other)
            for other in prefs if other != person]
    scores.sort()
    scores.reverse()
    return scores[0:n]

测试下

>>> print topMatches(perfers, "Tom")
>>> print topMatches(perfers, "Jack")

哈哈,你们看到Jack跟Tom不愧是一对好基友吧...

>>> [(0.9912407071619299, 'Jack'), (0.7470178808339965, 'Angelia'), (0.5940885257860044, 'Aimee'), (0.5669467095138396, 'Abby'), (0.40451991747794525, 'Scotte')]
>>> [(0.9912407071619299, 'Tom'), (0.9244734516419049, 'Aimee'), (0.8934051474415647, 'Abby'), (0.66284898035987, 'Angelia'), (0.38124642583151164, 'Jackson')]

那接下来,进入最后一步了,请问,我想得到推荐给Tom的东西要怎么做...

def getRecommendations(prefs,person,similarity = sim_pearson):
    totals = {}
    simSums = {}
    for other in prefs:
        if other == person: continue

        sim = similarity(prefs, person, other)

        if sim <= 0: continue

        for item in prefs[other]:
            if item not in prefs[person] or prefs[person][item] == 0:
                totals.setdefault(item, 0)
                totals[item] += prefs[other][item] * sim
                simSums.setdefault(item, 0)
                simSums[item] += sim

    rankings = [(total / simSums[item], item) for item, total in totals.items()]

    rankings.sort()
    rankings.reverse()
    return rankings

测试下

>>> print getRecommendations(perfers,"Tom")
>>> print getRecommendations(perfers,"Jack")
>>> []
>>> [(3.3477895267131013, 'Movie6'), (2.832549918264162, 'Movie1'), (2.530980703765565, 'Movie3')]

这个时候因为Tom已经看过所有的电影了,所以没得推荐了...

行吧,本期的献丑也到此为止了,由于本人也是因为工作需要刚刚接触,所以有兴趣的一起交流哈。 另外鄙视下坑我的 猫猫 。。。大家一起鄙视下,同时期待 猫猫 带来的 Cubieboard 开发板专题。

资源推荐

《集体智慧编程》:该书完全使用简单易用的python语言描述,为入门者简直是揭开了一层朦胧的面纱。本人也是其中的受益者,所以有兴趣的可以先阅读本书。 另外专题中用到的代码和讲解内容也是来自于此书。

pythonxy :一个集成了很多科学计算工具的python版本。本专题的代码虽然都是自己实现,但是也可以通过scipy库中的一些封装好的函数库去实现。其实现更加合理科学。

pycharm :个人用过的觉得是最好的python IDE,或许,用多了会上瘾的感觉,(收费的商业版,当然也有社区版。。。怎么使用就看你们的方式了)

mahout:一款由java编写的机器学习的库,能够跟hadoop完美的融合,对于大数据的机器学习非常的好,在企业的具体应用中也开始在用了,至于为什么给大家推荐呢,

不是因为作为一个代码库可以偷懒,我一直的原则都是,能够做得出的才去偷懒,不然就勤快点,主要是因为本期演示的数据非常的少,所以没有什么影响,但是真正应用中的话数据量是非常大的,试想下,如果以淘宝或者亚马逊的交易商品来做推荐,那么多数据,如果自己写代码一个个去跑,该跑到什么时候。。。

一段代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 #!/usr/env python
 import socket
 from smtplib import *
 from email import *
 """
    上一期,通过bash脚本借助curl获取ifconfig.me返回的地址并发送邮件,
    这一期我们用python实现借助dnspod来获取外网ip地址并发送邮件
 """
 def get_ip():
     sock = socket.create_connection(('ns1.dnspod.net', 6666))
     ip = sock.recv(16)
     sock.close()
     return ip

 def send_mail():
    s = SMTP()
    s.connect("smtp.xxx.com")
    s.login("xx@xx.com", "xx")
    msg = mime.Multipart.MIMEMultipart()
    msg['Subject'] = u"RaspberryPi IP"
    msg['From'] = "xx@xx.com"
    msg['To'] = 'xx@xx.com'
    text = "Your home IP: " + get_ip()
    msg.attach(mime.Text.MIMEText(text, "plain", "utf-8"))
    se = s.sendmail("xx@xx.com", ['xx@xx.com'], msg.as_string())
    s.quit()

开源吉祥物

http://ssh.cnsworder.com/img/daemon-tux-hexley.png
FreeBSD: Beastie
Linux: Tux
darwin: Hexley

Tip

开发

read、write默认是不带缓冲的 fread、fwrite默认是带缓冲的

int fileno(FILE *stream) 可以将文件指针转换成文件描述符 FILE *fdopen(int fd, const char *mode) 将文件描述符转换成文件指针

运维
tmux和screen可以在远程断开后继续运行
使用
fedup --network 20 将fedora升级到最新的20

作者简介

http://ssh.cnsworder.com/img/weiyi.jpg
网名:唯一<br/>
群ID:[广州]唯一
微博:<http://www.weibo.com/sadlin>
技术:java、搜索引擎
简介:广州小小程序员。喜欢折腾代码。。

注解

欢迎群成员自荐自己的blog文章和收集的资源,发 邮件 给我,如果有意见或建议都可以mail我。 如果无法直接在邮件内查看,请访问 github上的页面网站 。 我们在github上开放编辑希望大家能参与到其中。

第Alpha3期

Author:猫猫
Date:2013-11-24
Category:publication
Tags:Python,C/C++
QQ群号:20506135
微信号:linux_developer
专题作者:onwone

《GNU/Linux Developer》第 Aplha3 期在春节后和大家见面了,本期 onwone《C/C++编译系统》《web.py分析(一)》 两个专题和大家分享。

前言

工作了有N多年了,在GIS圈(其实关注于3D)转了又转5年了,但是有点忙忙碌碌,但是又不知道忙了些什么,至今无房无车。于是甚为消极。2013年于是决定好好的工作,挣钱。现在也为了提高自己,将自己知道的一些东西分享给大家。

《C/C++编译系统》 来源于,曾经的一个开源项目。原本是Mac项目,在移植的时候,没有使用Makefile这种方式,为了能在Linux上运行,特地的写了一个Makefile,来在linux上编译这个软件。两周的时间,每天从7点到9点,编写和调试Makefile。那个时候大概把《我一起写Makefile》翻了一遍,写了一个简单的Makefile。之后想用automake来编译,但是我失败了,从网上看到的教程实在是让我沮丧,看不懂。(rpmbuild也是给我这种感觉)。后来接触了CMake,这是一个非常简明的构建系统,非常直观了当的指令集合,完美的跨平台表现,让CMake别越来越多的软件只用它作为构建系统。

《web.py分析(一)》 这个专题是喜欢Python并且学习了它之后,用了web.py练了一次手,目前这个公司使用了python在很多项目上边,在工作之余分析了web.py。选择web.py比较简单,因为web.py非常简单(追踪代码时候发现了它不简单),代码来那个很少。相对于其他的python webserver。它是一个代码量和功能比例很大的webserver。这也满足了我想看apache,但是被它庞大代码量吓退的小心思。当然我希望以后,我还会写出它的后续 《web.py分析(二)》《web.py分析(三)》 ...

专题一 C/C++编译系统

想好了写这个专题《C/C++编译系统》,但是心里还是有点忐忑,怕其中有认识不足的地方,或者错误误导大家。 在这里,我也讲不出来很牛本的东西,我这里讲述关于编译C/C++的问题和现在使用的自动化工具。

警告

我们这里不牵涉C/C++的语法、逻辑造成的编译问题。

什么是Makefile

Makefile是一个或者多个C/C++工程的编译过程的描述。描述了从源文件到中间文件再到目标文件的过程。这些描述根据特定的规则编写,提供给make程序使用。make执行Makefile(默认名字是Makefile,如果是其他名字softname.mak,则执行命令 -f softname.mak ),就执行了C/C++的编译过程。 如果你在Linux上做过从源码安装软件,总会使用命令make & make install。不管之前的操作时./configure还是cmake。因为Makefile的简单明确,已经让它被广大程序员接受,作为了C/C++工具链必备的一环。新的编译系统的产生也只是为了辅助产生Makefile,而更好的服务程序员们。

IDE和Makefile

对于使用IDE的伙计们,编程是一个简单的事情。编写代码,点击编译按钮。在规定的目录下,就会生成二进制文件。So easy。是的!为什么还需要使用Makefile这个东西。虽然不算很难写,但是比起点击一个按钮那也是负担啊!对于理由,我也只能说,可能你用不到,了解一下我们的工具总不是一件坏事。 但是对于另一些人,他们必须要跟Makefile打交道了,比如持续集成的工程师们,为了定时发布而是用持续集成工具的工程师们,他们工具的限制要求了必须要写下编译脚本。以方便发布软件产品。 再比如Linux kernel的开发工程师。 对不起,这个时候没有IDE可以让他们使用。 木办法,写Makefile或者使用automake类似的工具生成Makefile吧。

C/C++的编译过程和Makefile

对于C/C++的编译的过程可以分成很多细节。可以看图

http://docs.cnsworder.com/img/compile_process.jpg

真实的情况只是很简单的场景,我们不是在汇编课上,需要使用gcc生成汇编语言来完成我们的作业。

  1. 编译 这个步骤是把*.c和*.h编译成*.o
  2. 打包或者链接 把头一个步骤的产生的*.o打包成libxx.a(或者lib*.so)

如果是链接的话,产生可执行二进制文件

这就是工程C/C++编译的两大步骤。也是我们实际可以看到的过程。在VS或者其他IDE比如Dev C++,编译过后,可以找到中间文件*.o(*.obj)和库文件(可执行文件)。

Makefile就是对这个过程的描述。Makefile如何编写,我现在用一个例子说明。工程checknow,包含check和now两个项目。

check项目,包含check1.c,check1.h和check2.h,check2.c四个文件,目标是生成libcheck.a

now项目,包含now1.c,now1.h和now2.h,now2.c四个文件,目标是生成libnow.a

我们会编写如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 #compile configuration
 CC=gcc
 DEBUG=-g3
 WARN=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs
 ifeq ($(shell uname), SunOS)
     PLATOPTS+=-lsocket -lnsl
 endif
 CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS)
 LIBS=libcheck.a
 LIBS+=libnow.a
 CHECK_OBJS=check1.o check2.o
 NOW_OBJS=now1.o now2.o

 all: $(LIBS)

 libcheck.a: $(CHECK_OBJS)
     ar rcs libcheck.a $(CHECK_OBJS)

 libnow.a: $(NOW_OBJS)
     ar rcs libnow.a $(NOW_OBJS)

 check1.o:check1.c check1.h
     $(CC) -c check1.c check1.h -o check1.o $(CFLAGS) $(PLATOPTS)
 check2.o:check2.h check2.c
     $(CC) -c check2.h check2.c -o check2.o $(CFLAGS) $(PLATOPTS)
 now1.o: now1.c now1.h
     $(CC) -c now1.c now1.h -o now1.o $(CFLAGS) $(PLATOPTS)
 now2.o: now2.h now2.c
     $(CC) -c now2.h now2.c -o now2.o $(CFLAGS) $(PLATOPTS)

 clean:
         rm -rf $(LIBS) $(CHECK_OBJS) $(NOW_OBJS)

这就是我写的第一个Makefile,看到上边最多的就是依赖关系,而根据依赖关系进行编译。这就是Makefile最原本的意义,非常的清楚明白。远比已发布软件的Makefile更加的清楚明白。

这个脚本完成了对编译的所有的全部,甚至包括扩平台的一些设置,可以使用简单的Shell命令。是一个完备的Makefile。

但是懒惰的程序员通过定义了各种符号的含义,简化了Makefile编写的内容,上述脚本可以写成如下

#compile configuration
CC=gcc
DEBUG=-g3
WARN=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs
ifeq ($(shell uname), SunOS)
    PLATOPTS+=-lsocket -lnsl
endif
CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS)
LIBS=libcheck.a
LIBS+=libnow.a
CHECK_OBJS=check1.o check2.o
NOW_OBJS=now1.o now2.o

all: $(LIBS)

libcheck.a: $(CHECK_OBJS)
    ar rcs libcheck.a $(CHECK_OBJS)

libnow.a: $(NOW_OBJS)
    ar rcs libnow.a $(NOW_OBJS)

.c.o:
    $(CC) -o $@ -c $<

clean:
        rm -rf $(LIBS) $(CHECK_OBJS) $(NOW_OBJS)

最主要的简化,就是.c.o,同名替换,把.c后缀改成了.o,作为输出文件。

>>> “$@”表示目标的集合,就像一个数组,“$@”依次取出目标,并执于命令。
>>> “$<”表示所有的依赖目标集

具体的内容,可以查看陈皓的 《跟我一些Makefile》

Makefile和CMake

我们已经了解Makefile,怎么去写Makefile。而Makefile有一个重大的缺陷,Makefile也要维护,而程序员是懒惰的。为了更好的维护Makefile,程序员们用不同的方法简化Makefile的维护,降低编译的难度。

automake是*nix上原生的生成makefile的工具。但是可惜automake怪异的使用方法,阻止了我使用它,当时我宁愿写Makefile,所以我不会使用automake,你有兴趣的话可以自己研究一下。(在一个开源工程中,我的确是些了Makefile,而没有使用automake) CMake的作用是生成Makefile或者特定的IDE工程,它极大解决编译源码的跨平台问题。原来越多的软件使用CMake作为构建系统。Qt,OSG,OGRE, opencv。强大的CMake可以使他们非常轻易的在Mac,*nix,windows上进行编译。以前我不知道,但是在windows上,我编译过完整的Qt,OSG,OGRE,非常简单,点点按钮的事情(一般编译教程,重点在于解决你的库依赖)。

上边Makefile的例子,使用CMake简直太简单了。定义输入,输出,设置一些环境变量就可以了,甚至不用设置环境变量。

project(checknow)
cmake_minimum_required(VERSION 2.6)
# None
set(CMAKE_C_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs")
# Debug
set(CMAKE_C_FLAGS_DEBUG "-g")
# Release
set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
ADD_LIBRARY(chech check1.c check2.c )
ADD_LIBRARY(now now1.c now2.c )

好了这就是CMake需要的脚本 CMakeLists.txt ,放在程序的源文件同级目录。是不是非常简单。

cmake命令行

两种使用方式

>>>  cmake [option] <path-to-source> 指向含有顶级CMakeLists.txt的那个目录
>>>  cmake [option] <path-to-existing-build> 指向含有CMakeCache.txt的那个目录

第一种方式用于第一次生成cmake makefile,此后可以在build dir里直接 ``cmake . `` 。注意 `.`表示当前目录,因为当前目录中已经有CMakeCache.txt,所以适用第二种方式。实际上cmake总是先检查指定的build dir中有没有CMakeCache.txt,如果有就按第二种方式处理;如果没有才寻找CMakeLists.txt使用第一种方式处理。

参数

>>> -G <generator-name> 指定makefile生成器的名字
>>> -U globbing_expr 删除CMakeCache.txt中的变量
>>> -D var:type=value 添加变量及值到CMakeCache.txt中。注意-D后面不能有空格

当然CMake为了简单的处理编译,定义了全部的指令。这里只用了非常简单的几种,如果你要深入的理解CMake编译系统,请查看CMake的官方文档和OSG,Qt里边CMakeLists.txt的内容。当然他们非常的易懂。

好吧本篇专题就这样结束了,我在这里好像讲了很多,又好像什么都没有讲。只是为大家介绍了C/C++现在比较好的编译系统make,CMake。如果你有这样的需要,请根据你的需要来选择。

专题二 web.py分析(一)

在切入正题之前,我先表扬一下Python,我认为Python是一项伟大的语言(不要挑我毛病,我就是只用CPython),因为和C/C++语言的关系,它可以实现各个层面工作。而在混合编程的趋势下,和C/C++的紧密联系,又让它成为了互联网应用实现、大型软件的二次开发的神兵利器。 对我来说它的伟大之处在简洁,简单。非常简短的语句可以实现强大的功能。大量的C/C++代码才能够完成的软件,在Python中减少一多半量完成,这对我们学习是一个如此的有利条件。我真的爱死它了。(这个时候请不要给我提GIL)

我讲述的内容是webpy的解析。为什么是一呢?因为webpy运行作为http server的基本功能(接收连接请求,生成页面,输出),不仅仅是这一点的粗略功能,还有更加细节的内容,render系统,session管理的内容。而我在这里仅仅是把它作为http server的运行情况给提炼了出来。之后我会把render,session也仔细分析一下。

(题外话:曾经觉得写出来一个http server是一个牛叉至极的事情,Apache的httpd多大啊。编译出来2M的二进制文件,C代码得有多少啊。之前有点小恐惧)

webpy使用到得基本技术

如果你也要拆解一下webpy,你需要重点注意一下Python的几个技术

  1. closure(闭包)
    1
    2
    3
    4
    5
    6
    7
    8
     def maker(N):
         def action(x):
             return x * N
         print(action.func_closure) # 打印出action函数的func_closure属性值
         return action
    
     N = 10
     print('int N: id = %#0x, val = %d' % (id(N), N)) # N的值为10(整数10的地址是0x8e82044)
    
    >>> int N: id = 0x8e82044, val = 10
    
        mul10 = maker(N) # action.func_closure中含有整数10(即自由变量N)(<cell at 0x90e96bc: int object at 0x8e82044>,)
    
    闭包的这种 能够记住环境状态 的特性非常有用,Python中有一些其他特性就是借助闭包来实现的,比如 装饰器。
    
  2. Python的内置方法的意义

    web.py里边有太多使用python内置方法,重载方法的例子。通过猜,Google(bing)也能比较清楚的明白这些方法的作用。比如getattr方法,可以通过这个方法实现调用

    import sys
    
    path = getattr(sys, "path")
    print( path)
    

    实现了sys.path()的调用,在这里sys.path等于getattr(sys, “path”)

    hasattr方法,可以类是否有某个对象

    hasattr(sys, 'path')
    
    >>> True
    
  3. 面向对象

    python本身就是面向对象的语言,web.py使用面向对象的本来就是水到渠成的,在追踪代码时候,如果方法并没有在这个类里边,请考虑它的父类实现有这样的方法。

    web.py解析(httpserver部分)

    web.py例子

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
     import web
    
     urls = ("/.*", "hello")
     app = web.application(urls, globals())
    
     class hello:
         def GET(self):
             return 'Hello, world!'
    
     if __name__ == "__main__":
         print('app run!!!!')
         app.run()
    

    从这个例子入手。这里构建了url映射表,并用映射表在构造了application,之后pplication只执行了一个run方法。

    1. application对象 __init__ 时候,将映射表,环境传入application,创建运行环境,创建了processors。 application.run 调用 wsgi.runwsgi(self.wsgifunc(*middleware)) 将application的方法wsgifunc最为闭包传递给后边的方法,之后的方法,但是在这里我要告诉大家这个方法就是server进行response的地方。

    2. wsgi.runwsgi经过条件判断,把wsgifunc交给了httpserver.runsimple(func, validip(listget(sys.argv, 1, ‘’))),在这里listget把命令行的参数ip和port。

    3. httpserver.runsimple(func,(ip, port)) 方法。
      1. StaticMiddleware里边对func进行了分拣,如果属于static文件(通过文件夹名称划分),就是归于StaticMiddleware把文件输出。
      2. 此时原来的func替换成了StaticMiddleware的 __call__ 。之后的LogMiddleware,在func包裹了一层日志输出。
      3. 终于到了 WSGIServerWSGIServer 也很简单,只有一点方法 wsgiserver.CherryPyWSGIServer(server_address, wsgi_app, server_name) .
    4. wsgiserver.CherryPyWSGIServer ,创建了线程池ThreadPool, WSGIGateway_10`和`httpserver 的各项参数,如端口,接收请求的根数,超时时间等。

    5. 这里结束了 wsgiserver.CherryPyWSGIServer ,回到WSGIServer方法,再回到 httpserver.runsimple ,到了server.start()

    6. server.start() 正式开始创建了socket,并开始监听。启动了线程池 (requests.start()) ,把线程池装满线程。开始接受连接,对连接的socket进行封装成connection。把connection放入连接池。与此同时线程池中的线程也在工作着,从连接池拿到连接,然后调用 conn.communication

    7. communication方法的作用,创建HTTPRequest,分析 requestreq.response
      1. 分析request,读取了http header,获取了http所需的一切内容。
      2. req.response,最重要的部分 self.server.gateway(self).respond() ,在这里gateway进行了构造,其中最重要的是整个http环境进行了记录。由gateway进行response。
    8. 而在WSGIGateway,respond里边可以看到这个 self.req.server.wsgi_app(self.env, self.start_response) 这样一句,这个 wsgi_app 就是第4步, wsgi_app 就是在这一步返回的闭包。那个报过了日志输出的func。而核心还是application的wsgifunc。终于绕回来了。

    9. 在application的wsgi里边,load(env) 将环境进行载入,将一开始add processor的几个processors,执行完了之后,执行handle()方法。在handle里边,_match确定了需要调用那个类, _delegate 真正执行了对应path的类。

    诶, 一层一层的追溯代码的调用关系,中间经历了几次连接断掉的情况。好几次都绕在了,request的respond方法如何到了 application.wsgifunc 。http状态是如何到了application里边的,而urls mapping只在application里边。这个像是断掉的绳子,连接不起了。

    httpserver的实质是一个socket监听端口,分析http head,根据http head的method,path,paramters,然后输出文本。就是这么简单,但是web.py为了实现这个非常简单的内容。绕了多少圈啊!!!我认为web.py将application作为网站内容的container不太合适,也许这就是web.py代码绕来绕去的原因。

web.py结构发展预感

web.py的httpserver有一个比较凌乱的调用过程,是在太多凌乱了。太多的使用了闭包,有些闭包的实际的调用时机,实际上比你看到的时机要晚非常多,wsgifunc是一个非常重要而且讨厌的例子。 在wsgiserver模块里的`__init__.py`可以看到WSGIPathInfoDispatcher,内容非常简单。实现了application类中_match的作用,而且也使得减少使用了闭包。对于代码难度也有所降低。 当然只是我发现的一小点内容,web.py也在尽量简化它的代码逻辑。这也是为了web.py以后发展。不用这么多闭包和奇葩的回调。分析起来很艰难啊。

分析web.py的感受

我在分析web.py只是做为httpserver来分析的,当然也只是分析了它如何实现httpserver。但是我也看到了它在使用ssl,chunkTransfer等等一些http服务器应用的代码。web.py一个优秀的httpserver,在这里我只是分析它的实现逻辑,但是对它更加细节部分缺少理解,也对他如何将这些细节组合在一起也缺少理解。 我想以后我还会更加深入的分析web.py这款简单的httpserver。

NOTE:
开始时候想到了一个问题。web.py怎么能把全局变量和线程池搅合在一起,而没有出现错误。纠结了一天,第二天醒了的时候,想起来一个事情, web.py使用了线程池,application内部使用了web.ctx作为全局变量。但事实上,web.ctx是ThreadedDict,最终来自于threadlocal,如果你想了解threadlocal是怎么实现的,查看python23.py。

资源推荐

《essential C++》:这是一本绝对值得推荐的C++入门书。不厚200多页。但是在这200多页,里边 Stanley B.lippman,C++的创始人。就会交给你学习C++注意的关键细节。中文版的作者–侯捷,也是一位大牛,强强联手,品质保证。

nginx lua :nginx配置文件执行lua脚本,以往nginx做反向代理都是在配置文件中配置,现在直接放到数据里里边,通过lua脚本来做。省了不少事情,数据迁移问题也少了很多。

网易公开课 :好东西,尤其MIT,哈佛的课程。可以推荐的好多啊。

一段代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 def anna(fn):
     def new_func(*args):
         print 'by anna args=%s' % args
         return fn(*args)
     return new_func

 def annie(ar):
     print 'by annie1 ar=%s' % ar
     def _A(fn):
         def new_func(*args):
             print 'by annie2 args=%s' % args
             return fn(*args)
         return new_func
     return _A

 class ccc():
     @anna
     def __init__(self):
         print 'ccc'
     @anna
     def ff(self, a):
         print a

 @anna
 def test1(a):
     print a

 @annie('hi')
 def test2(a):
     print a

 test1((1,2))
 test2((3,4))

这段代码实现了decorator 模式

Tip

开发

开发服务端程序,客户端连接不顺畅,netstat查看网络连接状态,出现大量CLOSE_WAIT时候,请查看服务端代码,是否有对于无效连接close是否及时。

运维

客户端连接不顺畅,netstat查看网络连接状态,出现大量TIME_WAIT时候,就需要对系统参数进行调整TIME_WAIT重复使用参数。执行命令

echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse
echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle

这样对TIME_WAIT的套接字进行回收利用,减少TIME_WAIT浪费的套接字。

使用

快速制作启动U盘

>>> dd if=[镜像文件] of=[u盘设备] bs=4M

作者简介

http://docs.cnsworder.com/img/ownone.jpg
网名:ownone
群ID:[北京]Num1*
微博:http://t.qq.com/ownone_vip
技术:C、python、linux、web、网络编程
简介:北京程序员一枚,带一点开源的浪漫主义情怀,带一点悲观主义(开源在中国的商业化)。努力工作。

注解

欢迎群成员自荐自己的blog文章和收集的资源,发[邮件](mailto:cnsworder@gmail.com)给我,如果有意见或建议都可以mail我。 我们在github上开放编辑希望大家能参与到其中。

第Alpha4期

Author:猫猫
Date:2013-11-24
Category:publication
Tags:Python, Linux
QQ群号:20506135
微信号:linux_developer
专题作者:九州 猫猫

《GNU/Linux Developer》第Alpha4期在春风中来了,本期 九州大数据android系统编译和定制 两个专题和大家分享,另外由于*ownone*工作太忙了 web.py 的专题将会在4月份继续和大家见面,这期 猫猫 会给大家带来HD2 不死鸟传说 的专题分享。 因为群成员发展迅速,大家商量了一下决定,分设四个专题群来分别讨论问题:

  • Linux开发1群[内核] 287465634
  • Linux开发2群[服务] 20506196
  • Linux开发3群[应用] 19443596
  • Linux开发4群[基础] 48619264

另外为了更好的和大家进行答疑互动,群新开设了 答疑网站 ,大家如果有问题无法及时解决可以发到网站上进行解决。如果大家感觉自己问题比较有代表性也可以发送到上面以方便其他人。

往期订阅的内容可以在 readthedocs 上看到,几乎是和github上是同步的。(用Markdown排完然后还得再用reStructuredText再排一次版真的好累哦~~)

下期专题预告一下,郎中会给大家带来 Linux init系统介绍 ,ownone应该会给大家继续 web.py 的内容,敬请大家期待吧~~~

哦,忘了还有另外的惊喜哦,暂时保密吧 :p

专题分享

说来惭愧,郎中让我做此次专题并非我的水平有过人之处————菜鸟一枚,只是机缘巧合。说好的 《大数据》 内容因为才疏学浅加上公司事务占据太多时间,在此次专题中只做介绍性描述,以免贻笑大方.作为补充,此次专题会详细介绍 《安卓系统编译和定制》 内容。废话不多说,直入正题。

大数据

作者: 九州

要理解大数据这一概念,首先要从”大”入手,”大”是指数据规模,大数据一般指在10TB(1TB=1024GB)规模以上的数据量。大数据同过去的海量数据有所区别,其基本特征为 体量大、多样性、价值密度低、速度快

大数据特点
  • 数据体量巨大。从TB级别,跃升到PB级别。
  • 数据类型繁多,如网络日志、视频、图片、地理位置信息,等等。
  • 价值密度低。以视频为例,连续不间断监控过程中,可能有用的数据仅仅有一两秒。
  • 处理速度快。1秒定律。最后这一点也是和传统的数据挖掘技术有着本质的不同。物联网、云计算、移动互联网、车联网、手机、平板电脑、PC以及遍布地球各个角落的各种各样的传感器,无一不是数据来源或者承载的方式。
大数据处理

大数据技术是指从各种各样类型的巨量数据中,快速获得有价值信息的技术。解决大数据问题的核心是大数据技术。目前所说的”大数据”不仅指数据本身的规模,也包括采集数据的工具、平台和数据分析系统。大数据研发目的是发展大数据技术并将其应用到相关领域,通过解决巨量数据处理问题促进其突破性发展。因此,大数据时代带来的挑战不仅体现在如何处理巨量数据从中获取有价值的信息,也体现在如何加强大数据技术研发,抢占时代发展的前沿。

下面来介绍一下通用的大数据处理流程。

1. 采集

大数据的采集是指利用多个数据库来接收发自客户端(Web、App或者传感器形式等)的数据,并且用户可以通过这些数据库来进行简单的查询和处理工作。比如,电商会使用传统的关系型数据库`MySQL`和`Oracle`等来存储每一笔事务数据,除此之外,`Redis`和`MongoDB`这样的`NoSQL`数据库也常用于数据的采集

在大数据的采集过程中,其主要特点和挑战是并发数高,因为同时有可能会有成千上万的用户来进行访问和操作,比如火车票售票网站和淘宝,它们并发的访问量在峰值时达到上百万,所以需要在采集端部署大量数据库才能支撑。并且如何在这些数据库之间进行负载均衡和分片的确是需要深入的思考和设计。

2. 导入/预处理

虽然采集端本身会有很多数据库,但是如果要对这些海量数据进行有效的分析,还是应该将这些来自前端的数据导入到一个集中的大型分布式数据库,或者分布式存储集群,并且可以在导入基础上做一些简单的清洗和预处理工作。也有一些用户会在导入时使用来自Twitter的Storm来对数据进行流式计算,来满足部分业务的实时计算需求。

导入与预处理过程的特点和挑战主要是导入的数据量大,每秒钟的导入量经常会达到百兆,甚至千兆级别。

3. 统计/分析

统计与分析主要利用分布式数据库,或者分布式计算集群来对存储于其内的海量数据进行普通的分析和分类汇总等,以满足大多数常见的分析需求,在这方面,一些实时性需求会用到EMC的GreenPlum、Oracle的Exadata,以及基于MySQL的列式存储Infobright等,而一些批处理,或者基于半结构化数据的需求可以使用Hadoop。

统计与分析这部分的主要特点和挑战是分析涉及的数据量大,其对系统资源,特别是I/O会有极大的占用。

4. 挖掘

与前面统计和分析过程不同的是,数据挖掘一般没有什么预先设定好的主题,主要是在现有数据上面进行基于各种算法的计算,从而起到预测(Predict)的效果,从而实现一些高级别数据分析的需求。比较典型算法有用于聚类的Kmeans、用于统计学习的SVM和用于分类的NaiveBayes,主要使用的工具有Hadoop的Mahout等。该过程的特点和挑战主要是用于挖掘的算法很复杂,并且计算涉及的数据量和计算量都很大,常用数据挖掘算法都以单线程为主。

整个大数据处理的普遍流程至少应该满足这四个方面的步骤,才能算得上是一个比较完整的大数据处理。

大数据作用

1. 营销 营销的本质是找出潜在顾客,向其发布信息,最终达成交易。 收集海量的消费者信息,然后利用大数据建模技术,按消费者属性(如所在地区、性别)和兴趣、购买行为等维度,挖掘目标消费者,然后进行分类,再根据这些,对个体消费者进行营销信息推送。目前概念火热的精准营销就是如此 2. 内部运营 相比营销,大数据在内部运营中的应用更深入,对于企业内部的信息化水平,以及数据采集和分析能力的要求更高。本质上,是将企业外部海量消费者数据与企业内部海量运营数据联系起来,在分析中得到新的洞察,提升运营效率。 3. 大数据用于决策 在大数据时代,企业面对众多新的数据源和海量数据,能否基于对这些数据的洞察,进行决策,进而将其变成一项企业竞争优势的来源?同大数据营销和大数据内部运营相比,运用大数据决策难度最高,因为它需要一种依赖数据的思维习惯。

安卓编译定制初步

作者: 九州

Android 开源代码的特性使我们能够非常方便的定制,满足各种不同的需要。下面介绍怎么编译、定制android 代码满足个人需要。

确定需求

恶意应用在后台悄悄发送、屏蔽短信订购SP业务已成为安卓一大危害, 而需求在此产生——我希望手机系统能够详细记录: 手机内哪个应用在什么时候向谁发送了什么内容的短信,简称`4W`信息

初步设计

恶意应用一般使用 sendTextMessage 函数后台发送短信,那么解决方案看起来很直接——在函数实现内插桩,桩代码将函数调用信息输出到 Log 。那么,查看 Log 文件自然就知道短信的`4W`信息。

实践操作
下载源代码

直接使用Google提供的源代码有个问题就是编译出来的系统只适用于特定的几款手机。所以这里使用 CyanogenMod 项目代码。可以简单认为 CyanogenMod 是在Goole原生代码基础上适配了更多的手机机型。项目地址

下载源代码的过程

  1. 下载并添加 repo 文件到用户环境变量。

    https://code.google.com/p/git-repo/downloads/list?can=1&q=

  2. 建立代码存放目录
    >>> cd ~
    >>> mkdir androisource
    
  3. 在代码存放目录内执行

    >>> cd androidsource
    >>> repo init -u git://github.com/CyanogenMod/android.git -b [版本]
    

    以“gingerbread-release”(对应android2.3.7 ) 版本为例完整命令格式为:

    >>> repo init -u git://github.com/CyanogenMod/android.git -b gingerbread-release
    
  4. 初始化完成后执行下载源代码
    >>> repo sync
    
    >>> repo sync -j [n]
    

区别在于前者使用单进程,后者使用了 n 进程下载。

初始化编译环境
整个android的编译依赖关系比较简单,安装好指定的包就即可,这里不做详细介绍 ,具体参见: http://source.android.com/source/initializing.html 。但有一点需要指出的是编译 2.3以上 androd 版本必须使用sun java 1.6
添加系统服务

虽然在 “初步设计”中我们描述的方案是桩代码直接记录信息到 log 文件,但此设计不便于扩展,在实践中我们采用系统服务代理模式。

Android本身提供了isms,search,network_management等系统服务实现不同的功能。sendTextMessage函数实际上就是使用isms服务发送短信。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 //frameworks/base/telephony/java/android/telephony/SmsManager.java

 public void sendTextMessage(
         String destinationAddress, String scAddress, String text,
         PendingIntent sentIntent, PendingIntent deliveryIntent) {
     if (TextUtils.isEmpty(destinationAddress)) {
         throw new IllegalArgumentException("Invalid destinationAddress");
     }
     if (TextUtils.isEmpty(text)) {
         throw new IllegalArgumentException("Invalid message body");
     }
     try {
         ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
         if (iccISms != null) {
             iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);
         }
     }
     catch (RemoteException ex) {
         // ignore it
     }
 }

借鉴于此,我们可以自定义一个 ilog 系统服务 ,并在 sendTextMessag 函数内插桩 ,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 public void sendTextMessage(
          String destinationAddress, String scAddress, String text,
          PendingIntent sentIntent, PendingIntent deliveryIntent) {
     if (TextUtils.isEmpty(destinationAddress)) {
         throw new IllegalArgumentException("Invalid destinationAddress");
     }
     if (TextUtils.isEmpty(text)) {
         throw new IllegalArgumentException("Invalid message body");
     }
     try {
         ILog ilog = ILog.Stub.asInterface(ServiceManager.getService("ilog"));
         if (ilog != null) {
             String[] logInfo=new String[3];
             logInfo[0]=destinationAddress;
             logInfo[1]=scAddress;
             logInfo[2]=text;
             ilog.log("sendTextMessage", logInfo);
         }
      }
     catch (RemoteException ex) {
          // ignore it
     }
     try {
         ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
         if (iccISms != null) {
             iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);
         }
     } catch (RemoteException ex) {
          // ignore it
     }
 }

log(String, String[]) 函数中,可以定制自己想要的效果,比如记录到文件,弹出通知栏提示等。

添加安卓系统服务需要一个接口文件 aidl 和一个实现文件 java ,关系类似于 c++ 类的头文件与定义文件。参见: http://processors.wiki.ti.com/index.php/Android-Adding_SystemService

具体的添加或修改代码如下:

frameworks/base/core/java/android/os/ILog.aidl

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 /*
 * aidl file : frameworks/base/core/java/android/os/ILog.aidl
 * This file contains definitions of functions which are exposed by service
 */
 package android.os;
 interface ILog {
     /**
     * {@hide}
     */
     void log(String function ,in String[] logInfo);
 }

frameworks/base/services/java/com/android/server/LogService.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 package com.android.server;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.*;
 import android.os.ILog;
 import java.io.*;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;

 public class LogService extends ILog.Stub {

     public LogService(Context context) {
         super();
         mContext = context;
     }

     //获取调用该服务的应用包名
     private String getPackageName(int pid, int uid) {
         PackageManager mPkgMgr = mContext.getPackageManager();
         String[] pkgs = new String[0];
         if (mPkgMgr != null) {
             pkgs = mPkgMgr.getPackagesForUid(uid);
         }
         if (pkgs != null && pkgs.length == 1) {
             return pkgs[0];
         }
         ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RunningAppProcessInfo> apps = am.getRunningAppProcesses();
         if (apps != null) {
             for (ActivityManager.RunningAppProcessInfo info : apps) {
                if (info.pid == pid) {
                     return info.processName;
                 }
             }
         }
         return "unknown";
     }

     //将信息写入文件
     private int writeToFile(String funciton ,String[] logInfo ,String packageName) {
         File ilogWorkDir = mContext.getDir("/data/data/ilog", 0);
         if (!ilogWorkDir.exists()) {
            ilogWorkDir.mkdir();
         }
         File ilogOutFile = new File("/data/data/ilog", "smsLog.txt");
         FileOutputStream fos = null;
         try {
             fos = new FileOutputStream(ilogOutFile, true);
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         }
         DataOutputStream dos=new DataOutputStream(fos);
         StringBuffer stringBuffer=new StringBuffer();
         stringBuffer.append("Time:")
                     .append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
                     .format(new Date()))
                     .append("\r\n");
         stringBuffer.append(String.format("FunName:%s", logInfo[0])).append("\r\n");
         stringBuffer.append("Info:").append("\r\n");
         for (int i = 1; i < logInfo.length; ++i) {
            stringBuffer.append("    ").append(logInfo[i]).append("\r\n");
         }
         stringBuffer.append("\r\n\r\n");
         try {
            dos.write(stringBuffer.toString().getBytes());
         } catch (IOException e) {
             e.printStackTrace();
         }
         return 0;
     }

     public void log(String function, String info[]) {
         String packageName = null;
             packageName = getPackageName(Binder.getCallingPid(), Binder.getCallingUid());
             writeToFile(function ,info,packageName);
         }

     final private Context mContext;
 }

frameworks/base/services/java/com/android/server/SystemServer.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 /*
  * go to function "@Override public void run()"
 * ........
 * Add following block after line "if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) "
 */
 try {
     Slog.i(TAG, "ilog");
     ServiceManager.addService("ilog", new LogService(context));
 } catch (Throwable e) {
     Slog.e(TAG, "Failure starting LogService Service", e);
 }

frameworks/base/Android.mk

1
2
3
4
5
6
7
8
 /*
  * open frameworks/base/Android.mk and add following line
  */
 ...
 core/java/android/os/IPowerManager.aidl \
 core/java/android/os/ILog.aidl \
 core/java/android/os/IRemoteCallback.aidl \
 ...
编译

CyanogenMod gingerbread-release 版本适配了60多款手机 [1] [2]

为官方支持的手机编译出ROM比较简单,命令格式如下:

cd device/[厂商]/[手机别名]
./extract-files.sh
./setup-makefiles.sh
cd ../../..

cd vendor/cyanogen
./get-rommanager
cd ../..

source ./build/envsetup.sh
lunch cyanogen_[手机别名]-eng
make clean
brunch [手机别名]

以我手上的测试机`htc G9`(别名 liberty)为例:

cd device/htc/liberty
./extract-files.sh
./setup-makefiles.sh
cd ../../..

cd vendor/cyanogen
./get-rommanager
cd ../..

source ./build/envsetup.sh
lunch cyanogen_liberty-eng
make clean
brunch liberty

编译期间出现的问题大多为依赖包未安装,根据提示安装好即可

编译完成后会在 /out/target/product/[手机别名]目录生成cm-7-[日期]-UNOFFICIAL-[手机别名].zip ,可以使用刷机精灵之类的软件刷机入对应的手机当有应用调 sendTextMessage函数时,就会记录到 /data/data/ilog/smsLog.txt 。需求满足

[1]http://wiki.cyanogenmod.org/w/Devices#type=“phone”;cmversions=”7”
[2]http://wiki.cyanogenmod.org/w/Devices#type=%22phone%22;cmversions=%227%22
不死鸟传说

作者: 猫猫

其实原本这是郎中的地盘,后来我看过了九州关于定制android的内容后,灵机一动,就给自己挖了个坑。我是真心的没想到今天会回家这么晚滴……

这一段的本意隆重的推介一下HTC的HD2,也就是Loe,手机界的第一神机。HD2现在还是我调试android程序的不二选择,目前这货里面共存了六个系统,包括一个FFOS和一个WP7.8,外加四个不同版本的android……

不死鸟传说
就在HD2价格落到最底点的时候,就在更多人把眼光高高的仰望到硬件越来越眼花缭乱的安卓机的时候,XDA的大神们默默的发布了可以用在HD2上的安卓ROM。其实吧,说实话,能在HD2彻底死亡之前及时的出来安卓ROM,私以为与HTC后续的几款手机,比如G5、G7,用的都是和HD2一样的处理器不无关系。 更多
Wp7加无限制android(NativeSD)刷机方法
个人认为,NativeSD是不死鸟最炫丽的羽毛 NativeSD也是xda的妖物们弄出来的一套HD2刷机方法,原理上基本就是在tf卡中划分出一个ext4的分区,然后把android的系统解包到这个ext4分区的目录中,再挂载这个目录从而实现启动android的目的。虽然听上去和卡模版的android区别不大,不过NativeSD是直接解包到卡上运行的,理论上说只要卡的速度够快,android的运行速度会超过直刷到ROM中的速度的。 更多

下面数篇是我自己做的或者改的HD2的NativeSD ROM

crane–sense–androi2.3.5
Sense在所有的安卓UI中一直是我的最爱。说不清楚为啥,也许是从WM时代带过来的习惯,也许是因为Sense真的很好用。不过,似乎Sense在伴随着HTC一起沉沦吗? 更多
peacock–MIUI–android2.3.7
MIUI这个系统一出场就给1.x年代的安卓世界眼前一亮的感觉。那时候安卓的UI着实的丑,被IOS死死地压制,但是走对IOS大规模山寨之路的MIUI算是当年安卓界的异类了——至少用起来简单,不那么难用,响应速度也快。不过正如IOS的UI一样,MIUI这种风格的UI,由于可随意定制性性对差一些,用时间久了会些许有些腻味了。 更多
swan–CM10.1–androi4.2.2
CM的出现很多大程度上改变了安卓界的格局。原本各手机厂商为了多卖新机型,对老机型系统的支持和更新翻脸就不认账,但是自从有了CM,情况就变成了用户可以不卖手机厂商的帐了——反正不管啥版本的系统,几乎没有CM找不到的。 更多
sparrow–deepin–androi4.1.2
深度曾经也算是盗版windows很有地位的一员,自从番茄入狱以后,深度也干起了洗白的大潮。后起的DeepinLinux和SenduOS也算是中规中矩吧,不过似乎用户群双双都不大,另外感觉效果上似乎离MIUI还是有不小的距离。简单的用了下,还算是流畅吧,不过没装什么软件(CM10在不装软件的时候也算得上比较流畅了,装了软件就卡卡卡卡卡……)。 更多
ostrich–FireFoxOS
FireFoxOS也算是Linux系手机操作系统的异类了,不过它毕竟是Linux。由于有了各种安卓的前车之鉴,只要是Linux系统的手机操作系统,在HD2这里都可以做成NativeSD的,SO,XDA的大神们果然就做了。 更多

外三篇——掘完HD2的坟回来掘G6

Legend:制作金卡
为什么需要金卡、金卡的作用、是不是可以不用金卡……这些问题我都不想讨论了,说实话,我还真不知道。但是我对金卡的认识是,这东西在某些情况下确实有用,所以就找一张体质好的容量小的卡做一个放那吧,反正小容量的卡一般来说也没多大用处了。OK,我不会告诉你这一章是可以跳过的。 更多
Legend:刷RUU
RUU,是ROM Upgrade Utility英文缩写,意思是ROM升级工具包(即ROM更新实用程序),它一般由HTC官方发布,在电脑端简单快速地升级手机固件(ROM)的套件。即所谓的官方ROM,官方到不能再官方的ROM。 更多
Legend:从RUU中提取ROM

番外之番外

其实在提取完G6 ROM以后,原本是要写怎么裁剪系统的,后来因为种种原因一直都没写。偶一直都以为偶食言了,今天看了看,原来那时候根本就没有预告要写这个呀,万幸万幸,偶还是个讲信用滴人……

其实裁剪手机系统是灰常简单的事情,把zip解压缩,把里面的/system/app下面或者/data/app里面的各种不需要的让人恶心的apk删掉,然后这个世界就清净了。

如果从网上找教程的话,会有很多教程都说最后一步要签名,签名不对无法刷入云云,其实,据我观察,似乎现在的很多手机由于用的recovery并不是有那么严格的限制,所以rom包其实根本就不需要在意签名了,只要rom里面的内容正确,刷机脚本没问题就一切OK……这到底是进步还是倒退?需要签名好像也就是HTC刚开始的机型这么干过吧,后来刷G12的时候,根本就没有G6那样的签名障碍呢。

android已经让这个世界疯了。一切似乎都变得廉价和触手可得了。

code block

上期**ownone**给出了函数方法定义修饰器的方法,偶尔看到了皓哥写的通过类方式定义的方法感觉眼前一亮,现分享给大家

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 class Dec(object):

     def __init__(self, tag):
         self._tag = tag

     def __call__(self, fun):

         def wrapped(*args, **args):
             fun()
             return "called"

         return wrapped

 @Dec(tag="b")
 def function():
     return "functed"

Tip

开发

shared_ptr的内存所有权使用计数器是非独占的,weak_ptr弱引用只引用不计数。

运维

使用virtualenv可以更好的隔离python的版本依赖以便于部署与生产环境

使用

emacs启动慢,通过hosts文件设置本机的机器名对应的ip即可

作者简介

http://ssh.cnsworder.com/img/jz.jpg
网名:九州
群ID:[广州]九州
微博:http://t.qq.com/adu_na
技术:偏好c/c++ , 快忘干净的python ,以及工作偶尔用到的 java
简介:广州低阶IT人士,做过安卓安全研究,目前从事网络协议分析 ,希望以后能专职开发

注解

欢迎群成员自荐自己的blog文章和收集的资源,发[邮件](mailto:cnsworder@gmail.com)给我,如果有意见或建议都可以mail我。 我们在github上开放编辑希望大家能参与到其中。

第Alpha5期

Author:cnsworder
Date:2013-11-24
Category:publication
Tags:Python, Linux
QQ群号:20506135
微信号:linux_developer
专题作者:onwone 江湖郎中

《GNU/Linux Developer》第 Aplha5 期和大家见面了,本期 郎中 将为大家带来专题 Linux init系统介绍flask–kiss之美, ownone 继续 web.py 之旅 。

本期专题

Linux init系统介绍

作者:江湖郎中

我手上的版本有archlinux、fedora20、debian7、centos6我主要以以上这些版本为例来描述,BSD init以上版本默认都没有了,所以无法验证,描述很可能有漏洞。其中archlinux、fedora20使用systemd,debian7使用system V init,centOS6使用upstart。

在谈init之前先说一下linux kernel的启动过程,在PC上和arm嵌入式开发板上会有所不同。

系统启动
  • PC

    设备在上电以后会在指定的位置来运行某段代码,这个位置`0xFFFF0`就是固化在主板上的BIOS(现在是UEFI了),BOIS自检后会从磁盘的某个位置加载程序,如果mbr分区会运行位于磁盘0道0柱1扇区上512字节的mbr程序,mbr程序会通过446+1字节的位置读取64字节的分区表,并在boot标志的分区上加载bootload,一般会使grub、lilo。UEFI引导的情况下,UEFI会直接到GPT分区的fat文件系统下找到efi的引导文件并加载,这个文件会加载grub或者其他引导(lilo是否支持有待验证)。grub本身是一个缩减版的内核,grub本身会包含stage1,stage1.5,stage2 三步。它通过kernel指令加载kernel(grub2是linux指令) vmlinuz文件并传递给内核启动参数,通过initrd指令加载ram disk文件,然后内核就被加载进内存中运行了。

    efi启动模式下的boot目录如下图:

http://docs.cnsworder.com/publication/image/boot_4.png
  • 开发板

    开发板上电后会从norflash或者nandflash上的某个位置来读取bootload,然后由bootload加载内核到内存,内核直接开始运行。在3.0以后的arm linux上kernel会从flash的某个位置读取LDS来加载板载资源的配置信息。

    在内核初始化完成后,需要和根文件系统建立关联,pc版的kernel会借助initrd来做桥梁加载根文件系统,而armlinux则直接根据配置加载跟文件系统。

早期init 系统简介

在内核所有的操作完成以后就会从根文件系统中加载地一个要执行的程序,他是所有程序的父进程,也是我们今天的主角 init 。恩,前面的废话太多了,现在才进入正题.

init的历史很久远,早期Linux使用的init有两个版本: sysVBSD 。现在他们仍旧没有完全被废弃,现在还有不少发行版本采用这两个系统比如dibian还采用system V init,archlinux在20jenk12年前后才放弃BSD init切换到systemd。废话不多说,分别描述一下。

  • BSD
    • 使用/etc目录下以rc.x作为文件名的文件来描述init的操作
    • rc.sysinit
    • rc.single单用户执行
    • rc.multi2~5执行
    • rc.local是杂项
    • init系统会按照以上顺序加载运行
    • rc.conf包含了相关的配置
  • system V
    • 脚本文件目录在 /etc/init.d/
    • /etc/rc{runlevel}.d 目录标识相应运行级别的目录
    • 目录下的文件以S开头的是启动的服务,以K开头的是不启动的服务
    • 启动标识后紧跟的数字表示启动优先级,数值越小运行越早
    • 通过service命令来起停服务
    • 通过chkconf来管理服务
    • 通过 /etc/inittab 文件来配置相应的运行级别

以上两种init系统加载的文件本身都是一些脚本文件,通过这些脚本可以加载相应的模块或者启动需要的程序。 BSD init 具体服务的内容:

#!/bin/sh
. /etc/rc.subr
name="dummy"
start_cmd="${name}_start"
stop_cmd=":"

dummy_start()
{
    echo "Nothing started."
}

load_rc_config $name
run_rc_command "$1"

SystemV init具体服务的配置内容:

#! /bin/sh

### BEGIN INIT INFO
# Provides:          sudo
# Required-Start:    $local_fs $remote_fs
# Required-Stop:
# X-Start-Before:    rmnologin
# Default-Start:     2 3 4 5
# Default-Stop:
# Short-Description: Provide limited super user privileges to specific users
# Description: Provide limited super user privileges to specific users.
### END INIT INFO

N=/etc/init.d/sudo

set -e

case "$1" in
  start)
        # make sure privileges don't persist across reboots
        if [ -d /var/lib/sudo ]
        then
                find /var/lib/sudo -exec touch -t 198501010000 '{}' \;
        fi
        ;;
  stop|reload|restart|force-reload|status)
        ;;
  *)
        echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
        exit 1
        ;;
esac

exit 0

从语法角度来看两者没有什么区别。

早期的init系统存在若干问题,比如,无法并行任务,任务之间缺乏有效的通信机制,对进程的监控只能通过PID来进行...

现代init系统简介

systemd和upstart在这种情况下产生了,他们都是事件驱动的,不得不说的是由于systemd开始时间晚于upstart所以很多特性也借鉴了upstart,同时systemd还借鉴了Mac OS X的Launcher系统。

  • systemd

注解

systemd 是 Linux 下的一款系统和服务管理器,兼容 SysV 和 LSB 的启动脚本。systemd 的特性有:支持并行化任务;同时采用 socket 式与 D-Bus 总线式激活服务;按需启动守护进程(daemon);利用 Linux 的 cgroups 监视进程;支持快照和系统恢复;维护挂载点和自动挂载点;各服务间基于依赖关系进行精密控制。

–维基百科

systemctl来管理systemd,同时也兼容service命令 所有的systemd配置在 /usr/lib/systemd 目录下,当启动用后会被链接或者拷贝到/etc/systemd目录下

  • upstart - 使用initctl来管理upstart - 配置项在 /etc/init/ 目录下 - ubuntu中在 /etc/rc.conf 的最后一行通过 exec /etc/init.d/rc $RUNLEVEL 来启动相应级别系统,debina中是在 /etc/inittab``中添加 ``id:2:initdefault:

    我印象中ubuntu的upstart的配置和centos的配置方法是有区别的,这里无法进一步验证。

systemd和upstart的使用

先分别上一段代码,sytemd:

[Unit]
Description=OpenSSH Daemon
Wants=sshdgenkeys.service
After=sshdgenkeys.service
After=network.target

[Service]
ExecStart=/usr/bin/sshd -D
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=always

[Install]
WantedBy=multi-user.target

upstart:

start on fedora.serial-console-available DEV=* and stopped rc RUNLEVEL=[2345]
stop on runlevel [S016]

instance $DEV
respawn
pre-start exec /sbin/securetty $DEV
exec /sbin/agetty /dev/$DEV $SPEED vt100-nav
post-stop exec /sbin/initctl emit --no-wait fedora.serial-console-available DEV=$DEV SPEED=$SPEED
usage 'DEV=ttySX SPEED=Y  - where X is console id and Y is baud rate'

看出什么区别来了吗?

upstart和systemd是全新的方式,upstart是命令的方式,systemd则是conf形式。

systemd
  • Unit 用来描述服务的相关信息和依赖关系
  • Service 对服务本身进行描述
  • Install 说明他的运行环境
  • 运行级别也通过systemd来进行管理
upstart
  • 通过 start on runlevel [012345]stop on runlevel [!RUNLEVEL] 来制定具体运行级别
  • 通过 exec 来运行相应的程序
  • 通过 script ... end script` 指令可以直接嵌入脚本

一些更加细节的配置请查阅相关手册吧。

我们可以通过 --init=xxx 内核参数来指定所使用的init系统。当然指定的这个init可以是任意的程序,你完全可以直接指定成为你想要的任何程序。

目前大部分Linux发行版本都已经采用systemd作为默认的init系统,ubuntu现在使用的是upstart系统,而Debain也在投票的结果是选择了systemd,ubuntu也宣布会接受debian的上游选择决定。

貌似现在systemd有统一Linux世界init系统的趋势。

专题 web.py学习(二)

作者: ownone

web.py和通用概念

关于web.py解析上一次,和大家一块分析了web.py主体(httpserver)的调用流程。要仔细分析他们的调用流程,这是一件比较困难的事情。 因为web.py为了方便大家的扩展,使用了很多近似的方法名称,如果你要用眼睛上去查看他们的调用,你非常可能被带入迷糊的境地。会有许多让你疑惑的内容我自己使用的方法是在web.py中添加了大量的调试信息。

看了郎中撰写的flask的东东,我觉得我有点太钻牛角尖,非常想把web.py弄明白,但是并没有把web.py用好,这一次我的希望这次的web.py可以作为web.py三部曲(核心逻辑,如何使用,写一个凑合的web程序)的承上启下的内容。

web.py里边包含着几个通用的概念HTTPServer,HTTPRequest,HTTPConnection,GateWay.这些概念在所有的server都会出现。

  • HTTPServer是web.py的大管家,创建套接字,建立线程池,处理http header,返回http状态和页面。
  • HTTPConnection在服务器上,意味着client,他就是client的代表。web.py非常形象的使用了一个方法communicate,体现了两者之间的关系。
  • HTTPRequest是client和server交互的实际的内容,非常直接的request,response。
  • GateWay 服务器和开发人员的面板。通过gateway,开发人员实现的逻辑,才能与客户端进行交流。

好了,在这里对web.py的httpserver部分做了一个总结。

hello world

下边我将要更多的介绍web.py了。让大家怎么开始使用web.py,好了从臭名昭著的helloworld开始吧。

#-*- coding:utf-8 -*-
import web

#定义url,将地址映射到对应的类
urls = (
    "/", "index",
)
app = web.application(urls, globals())
#定义index类
class index:
    #get请求
    def GET(self):
        return "Hello World"

if __name__ == "__main__":
    app.run()

请将这段代码保存到app.py里边,运行 python app.py (你必须已经安装了web.py),用浏览器访问 http://localhost:8080 ,如果看到Hello World,那么恭喜你你已经成功运行了网站。你的代码已经提供了http服务。

这个程序是我们的开端,所有的内容都在这个基础上延伸。让我们好好认识这个开端。

路由表和服务器容器

urls –路由表,定义了客户端请求的url,可以使用正则表达式,web.py会为我们只能得匹配到合适的类。这里都是逗号,两两配对。

注意:url匹配只匹配url路径不包括参数,例如:
/news/create?title=(.+)

其中起作用的url是/news/create

web.application是我们web服务器的容器,我们把想要的url和对应的逻辑实现以后,它就忠实的为我们工作(因为web.application可见,让我觉得web.py像lib多个framework) 这些自定义的类,有固定的GET,POST方法,以应对get和post请求。实现逻辑,返回给客户端。 web.py使用了类来写视图,这是一个非常赞的设计,这样我们可以通过定义基类来实现很多功能,例如在视图开始前自动检查用户权限,将一些常用的方法写成基类方法,就能很方便的进行调用,甚至在一些特殊需求下,可以通过一个类视图,来衍生出很多页面,既提高了开发速度,也提高了可维护性。

这很好,但是还有个疑问,我写一个helloword还行,让我写一个正常的页面,让我用一个字符串全return出来,这也太为难了,别着急。下边就是我们的模板。

web.py模板

这个太重要了,让我想起的就是当初开始学习j2ee的时候,编写jsp,在webpage中编写<%Java代码%>。话说这个是一个伟大的历史的进步不是吗?不用什么都是print(“”)

web.py在这个地方,有太多的选择,mako,genshi,jinja2.还有它自身的Templetor 。 Templetor是web.py的模板语言,它能负责将 python 的强大功能传递给模板系统。 在模板中没有重新设计语法,它是类 python 的。 在app.py同级目录建立文件夹templ,上创建hello.html 内容为

$def with (name)
Hello $name!

将app.py中index类更新为

再次运行python app.py,hello word!又出现了。

Templator非常强大,支持简易的语法可以实现

  • 定义变量,赋值
$ bug = get_bug(id)
<h1>$bug.title</h1>
<div>
    $bug.description
<div>
  • 过滤
$:form.render()
  • 转义符
5$$       $#我显示的是5dollar
  • 注释
$# this is a comment
hello $name.title()! $# display the name in title case
  • 控制结构
$while a:
    hello $a.pop()
$if times > max:
    Stop! In the name of love.
$else:
    Keep on, you can do it.
  • 内置 和 全局

    像 python 的任何函数一样,模板系统同样可以使用内置以及局部参数。很多内置的公共方法像 range,min,max等,以及布尔值 True 和 False,在模板中都是可用的。部分内置和全局对象也可以使用在模板中。

全局对象可以使用参数方式传给模板,使用 web.template.render:

import web
import markdown

globals = {'markdown': markdown.markdown}
render = web.template.render('templates', globals=globals)

内置方法是否可以在模板中也是可以被控制的,为了安全性需要去掉内置的方法:

# 禁用所有内置方法
render = web.template.render('templates', builtins={})

通过模板的这些定义,web.py具有了非常强大的页面表现能力。 最后说一下,豆瓣后台部分就是使用web.py,不过模板系统使用的是mako。可见web.py是非常具有实用性的。

flask——KISS之美

作者: 江湖郎中

ownone与大家分享 web.py 的内容了,我在想找一个相当量级的内容与大家分享, Django 太笨重了, tornado 重点在IO,还是 flaskbottle 合适,个人对 flask 稍有些了解,属于严重 入门级别 ,打肿脸充胖子来和大家分享一下。

flask是什么?当然他不是flash,官网给出的说明:

Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions. And before you ask: It’s BSD licensed!

github上的说明是:

Flask is a microframework for Python based on Werkzeug and Jinja2. It’s intended for getting started very quickly and was developed with best intentions in mind.

所以flsak

  • 使用Python写的
  • 一个微型框架
  • 建立在Werkzeug和Jinja2基础上
  • 采用BSD协议
  • 能够非常快速高效的开发

flask目前发布的最新版本是0.10。flash是开源项目托管在github上的,如果有兴趣可以直接git代码,地址是: https://github.com/mitsuhiko/flask

flask的对外部的依赖很少,只需要Werkzeug,Jinja2,itsdangerours三个库,在 setup.py 文件中有定义:

install_requires=[
    'Werkzeug>=0.7',
    'Jinja2>=2.4',
    'itsdangerous>=0.21'
    ]

好吧,不说太多的废话了先跑起第一个应用吧。

第一个应用
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/env python
# file: hello.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

解释一下哈, @app.route("/") 是Werkzeug的路由系统,它是通过python的修饰器来实现的,什么是修饰器吗?上期ownone已经在专题中讲过了,我就不废话了。 运行一下,

python hello.py

哈哈,就这么简单。通过 app.debug=True 或者 app.run(debug=True) 可以轻松的进入调试模式

路由

这就是路由

@app.route("/")

根据路由,flask将http请求交给对应的处理函数

路由系统的可以通过<var_name>的形式轻松与函数的参数结合起来,同时可以限制类型 intfloatpath ,像这样 <int:port_id>

@app.route("/user/<name>")
def name(name):
    return name

路由是使用修饰器来实现的,比起django和web.py这些使用全局的定义要更灵活,但是萝卜青菜各有所爱,不如他们集中配置方便。

flsak支持完整的Restful接口,路由通过 methods=[GET, PUT] 形式来指定处理的类型,全局对象 requestmethod 可以获得请求类型

反向路由
什么是反向路由?
路由是根据地址进行路由,反向路由应该是根据路由得出地址。

它通过 url_for 系列函数可以自动构建出相应的URL来

url_for("user", name="CROSS")

就会返回

>>> /user?name=CROSS

通过 redirect(url(`log`)) 可以轻松完成请求的转发

模板

flask使用的模板系统是作者自己的 Jinja2

模板的语法和django的模板系统差不多

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 <!doctype html>
 <!-- base.htm -->
 <html>
 <body>
 <div>名称:</div>
 {% block name%}
 基础模板的内容
 {% endblock%}
 </body>
 </html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 <!-- name.html -->
 {% extends base.html%}
 {% block name -%}
 {# 注释:减号是移除空白的 #}
 {% if user %}
 <div>{{user.name}}</div>
 {% else %}
 <div>他没有名字</div>
 {% endif %}
 {% endblock%}

是不是和django的模板一样呢。

模板的使用也很简单直接使用渲染器就可以

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 from flask import  Flask, render_template

 app = Flask(__name__)

 class User(object):
     def __init__(self):
         self.name = ""

 @app.route("/name")
 def name():
    user = User()
    user.name = "my_name"
    return render_template("name.html", user)

 if __name__ == "__main__":
    app.run()

当然Jinja2是一套完整的模板系统,功能足够强大,过滤器、上下文、加载器等高级特性。

生产环境部署

这里我直接使用uwsgi来部署,当然你也应该使用nginx或者tornado来做前端。

uwsgi的配置文件支持xml、ini、yaml,个人感觉xml太繁琐了,ini和yaml不错,yaml通过缩进标识关系很有`python范`,所以这里就用yaml来展示一下配置

1
2
3
4
5
6
7
 #flask.yaml
 uwsgi:
   pythonpath: /opt/flask_test
   module: run.py
   callable: app
   processes: 5
   socket: /tmp/flask.socket

启动测试

>>> uwsgi --yaml flask.yaml

成功后可以将启动添加到系统服务中。

简单即是美

flask太简单了,以至于我们不得不去自己去做很多事情来使他完成我们的任务。某种程度上说他不应该是 框架 而是一个

flask虽小但是他通过 requestsession 等对象漂亮的完成了对web相关的工作

flask的最大的亮点就是松耦合,flask只和web层面耦合,除了内置的路由系统和模板系统就没有内置其他功能了,真的很轻量级,但是flask可以快速的接入第三方库来完善自己的功能。

最后给出三个官方推荐的示例

https://github.com/mitsuhiko/flask/tree/master/examples/flaskr/

https://github.com/mitsuhiko/flask/tree/master/examples/minitwit/

https://github.com/mitsuhiko/flask/tree/website

资源推荐

酷壳 陈皓哥为大家推荐的技术文档,内容很丰富。

iOS安全攻防 : 美女程序员吴茜的大作,分析iOS数据窃取与防范的好文章。

Android安全攻防 : 美女的另一大作,介绍android安全机制SEAndroid。

code block

1
2
3
4
5
Ti = ['1', '2', '3', '4']
b = ['5', '6', '7', '8']
s = '1234'
print ''.join(dict(zip(a, b)).get(c) for c in s)
#处理批量代换大代码

Tip

开发

python的编码问题是一个老大难的问题,所以提议

  • 使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明。

  • 抛弃str,全部使用unicode

    python和我们的os交互的时候,使用unicode会自动使用locale的方言,我们就不用为了系统使用什么方言而恼火。

运维
使用logrotate管理日志,通过logrotate来将日志截断,打包,方便以后查看。
使用
vim :!%xxd 查看二进制

作者简介

http://www.gravatar.com/avatar/c1991331b3e8139f3168fdaf71cb65c4.png
网名:cnsworder/crossword<br/>
群ID:[济南]江湖郎中
网站:<http://www.cnsworder.com>
blog:<http://blog.csdn.net/cnsword>
微博:<http://www.weibo.com/cnsworder>
技术:Linux C/C++ Python Golang
简介:专注于Linux智能设备与云的开发

注解

欢迎群成员自荐自己的blog文章和收集的资源,发[邮件](mailto:cnsworder@gmail.com)给我,如果有意见或建议都可以mail我。 我们在github上开放编辑希望大家能参与到其中。

文档

文档

笔记

笔记

问答

Indices and tables