PXE模式使用openwrt网络安装debian

    废话不说,上干货。

    首先,禁用arptables。当然,如果你没开这个防火墙,那么没必要。其次,注意你的openwrt必须有udisk,否则空间相差太多,根本没有实现的可能。
    然后,如果你用的是新版的rom,应该在/etc/init.d/dnsmasq里面看到,dnsmasq()这个函数里面有。
        append_parm "$cfg" "tftp_root" "–tftp-root"
        append_parm "$cfg" "dhcp_boot" "–dhcp-boot"
    如果没有,加一下,有的话说明原生支持。下面可以直接修改。
    dnsmasq是一个dhcp/dns双重服务器,而pxe引导的第一步就是支持bootp协议。这个选项在/etc/config/dhcp里面。config dnsmasq一节上,增加。
        option 'dhcp_boot' 'pxelinux.0'
    重启dnsmasq,完成bootp准备。
    然后,安装tftpd-hpa,opkg update,opkg install tftpd-hpa。这是一个tftp服务器,默认不启动。如果你打算让pxe引导模式持久化,那么就改为默认启动,同时永久关闭arp防火墙。在/var/tftpd-hpa里面,可以看到tftpd的根路径。从参考3的的连接里面,你可以找到合适的一个下载路径,下载netboot.tar.gz到这个文件。解压后,可以看到pxelinux.0,这个和上面的pxelinux.0相对应。这是pxelinux的组件,隶属于syslinux项目,可以用来完成启动。
    这样,就完成了安装的所有准备工作。你可以找一个设备实验一下,应当可以完成网络安装的步骤。
    另外,如果需要启动选择amd64或者是i386,或者更进一步定制。那么需要下载其他镜像,自己生成pxelinux.cfg这个目录中的内容。
4. 配置pxe,安装debian和ubuntu http://my.unix-center.net/~whtbie/wordpress/?p=290

tcp连接的建立和释放

    大家新年好,新年第一博,我们来写一点干货。

    建立tcp为什么是三次握手?

    从两军问题说起太远了,三次握手的假定是一条双工线路的每个方向,要么持续通,要么持续不通。就好比一个电话,你和对方可以同时说话,所以是双工线路。你说了对方能听到,这叫单方向。单方向上,要么通,要么不通。
    如果从一个不保证稳定的电话线上(例如移动电话,这是典型例子),你怎么确定你们通话是正常的?
    假如你首先说“喂”,这时候你什么都不知道,对方能听到,他就知道你到他这里的电话是好的。他会说“喂,我听到了”。你听到了,会知道他到你这里的电话是好的。
    事情结束了么?没有呢,他还不知道你能听到他讲的东西,所以你还要回“我听到了”,然后开始说正事。
    回想一下自己打电话的经历,是不是往往漏掉了最后一个“我听到了”呢?这样会使得对方无法确认你能听到他说的东西。不过一般来说,当你开始滔滔不绝的时候,他会假定你听到了那句“喂,我听到了”。因为通常没有人会没听到对方的回应就开始说话说个不停。这个模式在tcp中也是可以做到的,在最后一个ack上附加数据。
    为什么由发起方开始?因为我们必须要假定有一个方向开始,任意开始就需要处理碰撞问题(就是同时开始)。接通socket总是由发起方开始传输第一个包,你不觉得直接在这个包上面开始测试连通会比较合理一些么?
    电话为什么由被叫方开始说话?因为主叫方打电话后,被叫方决定了电话什么时候接通。电话接通的时候,被叫直接就可以说话了(假如电话稳定的话),而主叫要等到下一个“嘟”不出现才能有所反应。所以通常都是被叫先开口。当然,也有被叫方接起电话来等着主叫说话的情况。
    另外提一句,如果你使用手机拨打的话,当听到对方“喂,这里是XX,您好”之类的信息的时候,应当先说“喂,我是XX,您好”。等对方确认能听到了,再开口说正事。因为手机有不算太小的几率,双方都听不到,或者单方向听不到。如果不巧是后者,很容易引起不必要的误会和麻烦。例如你滔滔不绝的说,对方作为反应,说了几句。然后你什么都听不到,继续说。对方当然会生气,对不对?
    OK,现在我们来说说挂电话。
    tcp的fin机制,其实是要解决这么一个问题。当你说“再见”后,能够马上把电话放下么?
    不行的,因为对方可能还有一些重要的事情还没说。你一说再见就挂断,这个会造成问题。从简单的思考上,我们会得出一个结论。当你说了“再见”后,对方可能还需要说一些事情。当对方也说了“再见”后,你就可以挂电话了。
    可是且慢,对电话而言这个模型成立,我们得稍作修改才符合网络——当你挂下电话机后,对方不会出现忙音。于是,当你说再见,对方说再见,你必须再说一次再见,对方才能确定你听见了再见。而且这次,事情非常符合两军问题——你们永远也无法就什么时候挂机达成一致。这个问题再折衷回来,也是一个三次模型,对方说再见,你说完你要说的话,然后说再见,对方再见,挂机。
    被动关闭上,这个模型基本是正确的。当你收到“再见”后,把你要说的事情说完,然后再见。这时候不能挂电话,因为你不确认对方听到你的“再见”了。如果你的“再见“对方没收到,那么对方会死等到天荒地老。至于为什么对方可以肯定你收到了他的再见,是因为刚刚你说的那堆废话里,应该已经包含了“我知道你要挂电话了,我会尽快说完”的意思。所以,你需要等对方的“再见”回来。
    当然,在tcp的实现上说,所有对对方的回应,都在ack里面。所以是FIN FIN-ACK ACK,关闭。最后一个ACK前,叫做LAST ACK状态。如果ACK丢失,会造成被动方挂断有问题,因此这里需要一个超时机制。用电话术语来说,就是最后一个再见没听见,你就要等到天荒地老,因此当对方首次再见完成的时候,你说再见,如果一定的时间等对方的最后一个再见等不到,就别等了,直接挂机。这个时间比等不到对方任何消息而挂机,要来的短。tcp标准设定为两倍最大生存周期,即2MSL。当然,如果等到了最后一个ACK,就直接删除连接数据结构。
    主动关闭的时候,情况会更加复杂一点。为什么?因为刚刚的超时机制。我们从你说再见之前开始说起,这次你是主动告别一方。
    你首先说了一个再见,然后进入FIN_WAIT1状态,换成电话术语,就是等对方说再见。tcp机制上,对方的ACK先到,就是FIN_WAIT2。对方的FIN先到,就是CLOSING——这种情况不多见,只在双方同时想挂断的时候发生。如果对方的FIN-ACK一起发送,那就直接保送上TIMED_WAIT。无论是哪种先,最后会收到一个ACK和一个FIN,并且发送一个ACK。换成电话术语,就是你说了再见,对方一定会说知道了和再见,并且你会说知道了。差别在于tcp需要用多个状态来表示哪个事情先,哪个事情后,打电话就不要这么麻烦了。
    最复杂的事情,在于说了最后一个再见之后。当你说完最后一个再见,就可以直接挂电话么?电话可以,但是作为tcp,却不可以。因为某些情况下,对方的FIN包没有到就会进入TIMED_WAIT状态。另外一些情况下,对方的LAST_ACK等不到你的ACK,会把他的FIN重发一遍。如果直接销毁连接结构,那么最后一个FIN包可能对新的连接造成干扰,而且会阻碍对方关闭连接。所以,作为主动挂断一方,你有一点很不利的是,无论如何,你必须等这个2MSL的时间。这个值在linux中一般是60s,更进一步可以查看rfc1337
    刚刚解说的最后一个情况,就是很多机器TIME_WAIT很高的原因——因为你的服务器主动关闭了连接。作为本质解决方案,你需要理解为什么会发生这件事情,服务器端关闭连接是否正常。如果正常,那么加一些内存,并且启用tcp_tw_recycle来减缓这个问题。注意,这个参数不应当在NAT后的机器上被启用。具体可以查看rfc1323

python的字符串相加效率

    今天文章被人纠了错,就跑去人家主页上逛。结果看到有篇文章说字符串相加速度的,看看结论很奇怪。就做了一下实验。原文可以看这里。我们只讨论python部分的行为。首先是论证我观点的测试,无关部分就跳过了,大家应当可以自行补上。

def f():
    s = ''
    for i in xrange(3):
        s += '123'
        print id(s)
    return s
f()
f()
输出:
138190216
138276992
138276992
138190216
138276992
138276992
    至少在几十的规模,这个结论还是成立的。说明对象确实被缓存了,这导致了字符串相加的多次测试中,后续次数都没有实际的执行字符串分配动作。召dis来问之。
 11           0 LOAD_CONST               1 ('')
              3 STORE_FAST               0 (s)
 12           6 SETUP_LOOP              41 (to 50)
              9 LOAD_GLOBAL              0 (xrange)
             12 LOAD_CONST               2 (3)
             15 CALL_FUNCTION            1
             18 GET_ITER            
        >>   19 FOR_ITER                27 (to 49)
             22 STORE_FAST               1 (i)
 13          25 LOAD_FAST                0 (s)
             28 LOAD_CONST               3 ('123')
             31 INPLACE_ADD         
             32 STORE_FAST               0 (s)
 14          35 LOAD_GLOBAL              1 (id)
             38 LOAD_FAST                0 (s)
             41 CALL_FUNCTION            1
             44 PRINT_ITEM          
             45 PRINT_NEWLINE       
             46 JUMP_ABSOLUTE           19
        >>   49 POP_BLOCK           

 15     >>   50 LOAD_FAST                0 (s)

             53 RETURN_VALUE             
    我们看到s是local变量,这个符合我们的预期。但是后续确实发生了add,而string的+算法,我们可以参考Objects/stringobject.c:1015这里,string_concat函数的内容。这里没有加速过程,即使有,也只有发生在len(a) == 0 or len(b) == 0的情况下。对于123的求和无法说明原因。
    这里我只能做一个假定,我们发现的id相等,其实可能是由于内存重分配的结果。一个对象被回收后,是存放在对象池中的,再分配的时候,可能按照规则被重新分配。当然这只能是一个推测,实际证明必须在python源码中修改并且重编译,我就不找这个麻烦了。
    另一个问题,实验的时候,只是把固定字符串更换为随机字符串而已,长度也没有发生变化。预期的结果应当是+=的速度变慢,结果+=速度不变。问题是join的速度加快算是怎么回事?关于join,我们可以参考Objects/stringobject.c:1574,这里说明了join的工作流程,也没有任何加速!
    唯一的解释,就是append的工作速度慢到超乎正常人类的想像,实验证明了这点。
def g():
    a = []
    for i in xrange(1000):
        a.append('1234567890')
    # s = ''.join(a)

print Timer('g()', 'from __main__ import g').timeit(10000)
    结果是0.91,append动作比join慢10倍。

计算机自动化的方向

    我认为,人类操纵各种设备的权利不言自明,这是软件/电气设备进化的必然结果。

    OK,我在吐槽什么?
    昨天,老婆用了一次家里的新自动洗衣机。很好用——晚上把衣服全丢进去,然后设定模式,倒进去洗衣粉,今早六点他会自动启动。早上就拿着半干的衣服去阳台晾晒,整个过程没有一点麻烦。外婆家里的那台老洗衣机,每次使用都需要搬进搬出,连接一堆管线,然后发出巨大的响声,再由人工把半湿的衣服拿去晾。
    ——如果要那样的话我们还得看着洗衣机,或者任由刚刚洗好的湿衣服在洗衣机里面闷六个小时。
    我觉得,这才是享受人生的方式。当然,老婆和我也是一样的观点——我们在父母家里可是受够了老式洗衣机的刁难。她在发现这玩意的好处后,脑筋动的可比我快多了。早上还没有睡醒,我就被她吵起来,然后问了一个问题。
    怎么远程遥控家里的微波炉和空调?
    OK,很得意的说,这是家居设计时我早就发现的一个问题,然后很遗憾,我告诉她——暂时不行。这个是我调查了很久后得出的结论。我不大不小好歹是个程序员,怎么说在控制电器上也是有点经验的,不过这个问题确实超出了我的能力范围。目前我所知道的,控制电器的方式基本有三种。
1.电器本身支持某种协议,例如wifi,或者蓝牙。我的电视机就支持eth网络,我可以通过手机遥控电视,或者直接在电视上观看某些节目,而不用打开电脑。
2.通过电源接口做。例如我看到房屋装修中卖的最多的,号称智能屋的系统。大部分都只能支持电灯的开关,或者电灯开关支持的最好。因为电灯的开关是一个只和电源有关的问题,我们只需要做一个很小的单片机系统,装置在开关面板上。当这个机器收到无线信号的时候,就打开或者关闭电灯开关。
3.通过红外线仿真做。这个适用于IrDA兼容的无线红外遥控设备。通过购买一个红外线装置,接收遥控发出的红外信号,再对着设备重发。
    而以上三种方案,都是有缺陷,而且是严重缺陷的。
    方案一,需要设备支持。通常来说,这样的设备都是相当昂贵的,而且不是每类别的设备都能买满意了。如果有一个很小的厂子生产一种空调,支持wifi。但是这个厂的空调机以不稳定而出名,你是否愿意为了遥控而冒常常要去修空调的麻烦呢?
    方案二,不是每个设备都能灵活控制。空调和微波炉接入电源后处于待机阶段,而不是启动——这是最有遥控价值的两台机器。即使能启动好了,我再如何通过电源告诉他,把里面的东西给我加热10分钟?而且单片机接收信号必须有相当复杂的加密,至少能对抗差分攻击。否则就会陷入汽车解锁遥控器同样的问题——被破解。
    方案三,更加糟糕。红外是一种指向性相当强的方案,所以当年的红外数据传输方案很快就被蓝牙替代了。也就是说,我要遥控三台空调,需要买三个红外设备,做固定指向。或者买两个电机来摇动红外设备。即使给我做出来了,不支持遥控的微波炉,自然也无法使用这个方案。
    然而你很容易的想到,如果一个完全不明白技术关键的外行,在接触程控的第一天,就把我摇起来问这个问题。那么这个问题,肯定是我们将来的目标。
    未来的设备,不但需要一套硬件界面(这个是必须的),而且还需要一套协议界面。为什么?你可以在家里的电脑里,通过符合协议的软件,一次性控制家里的所有设备,这就是所谓的“完全中控”。如果你觉得我是瞎说,鬼才会想要这种东西。请自己问问手里有一台ipad的同学,他们是否想在ipad上装个软件,直接遥控家里所有的电器?
    他们想死了。
    晚上的时候,把面包放进烤炉,执行一个good morning app。早上到时间了,闹钟会自动叫你起床,同时餐厅空调开始工作。当你确定起床后,面包就会自动开始烤,刷牙完毕正好出炉。出门的时候,所有设备都会自动关闭——整个房间里面没有任何一台中控设备了。晚上回家前,你的移动中控设备会通过3G自动唤醒灯光和空调。出门购物的时候,家里的冰箱会把缺什么东西传到你的手机上。

    这才是人生阿。

    睡觉前总是习惯要听点音乐,睡着后需要自动关闭么?装个app吧,亲。那个app不能连带关闭空调么?换这个app吧,亲。想要起床前空调就开始工作么?我们的app带定制功能,而且有默认配置模板提供修改哦,亲。Bill Gates在《未来之路》里面所幻想的美好未来,其实和我们只有一步之遥。
    这一步问题在哪里?协议。
    其实我们是可以做到的,这样美好的生活。问题是,我们缺少一个协议。
    有专业公司,提供装修服务。他们可以对你的家里进行改造,部分安装他们的外接设备,部分改为专用电器,并且在iphone上安装专用软件,实际上可以部分做到我刚刚说的。
    问题是,贵,而且不开放。
    开放的好处在于,如果这个系统不支持晚上睡觉前关闭空调,我可以自己写一个替换掉。而且如果某个电器坏了,我不需要高价问他们买一个新的专用电器,而是直接可以在商场里面买一个。而专用电器支持的问题则是,我必须持续使用他们的设备和服务,他们也不能关门。
    所以我才说,我们需要一个协议。