Solrex's profileSolrex Shuffling.LifeBlogListsNetwork Tools Help

Blog


    7/30/2007

    National Gallery of China


    黑乎乎地阴沉了一天,空气湿闷湿闷,到晚上总算开始下雨了。幸亏上次下雨带来的雨伞还扔在办公桌下,北京的雨是够少的,雨伞几个月才能用一次。

    昨天难得去逛了逛国家美术馆,和小力姐还有她表姐。看了一个西班牙普拉多国家博物馆藏品展《从提香到戈雅》,基本上全是油画,基本上看不懂。像我这种连素描都觉得深奥无比的人,怎么可能有什么艺术欣赏能力呢?不过还是耐心地把每幅画都看了一遍,艺术欣赏能力嘛,要慢慢培养的。又想起来中国大学教育和美国的差距,公司里 Berkely 的实习生小 Kevin 下学期四门课有两门是非 engineering 的课,好像是一门美国文化,一门东南亚文化史。他说他要在暑假里看完八本书,这样去上这些文化类的课程时候,就不用再读了,只想怎么写文章好了。在我们大学里的这类课程,是向来受到鄙视而且不放在必修课程里面的。也不是说哪个好或者哪个不好,不过看问题的角度和需求确实很不一样。

    mp3 被我摔坏了,虽然外面看一点儿毛病都没有,拿去修人家说坏得太厉害,只好返厂了。看来魅族的随身听质量也没那么好,三十厘米的高度都能摔报废。搞的我很郁闷,也不能拷电影回去看了。上次买了张中关村美嘉的电影兑换券,本来说去看变形金刚呢,唉,一直懒得动,现在看见就烦,扔不是不扔也不是。心血来潮果然不好,还是逮个空去看看吧。

    很久不写记叙性的文字了,都觉得有点儿生疏了。大概是因为生活比较平淡,尤其是在感情方面,现在的女朋友对我很好,再没有以前的那种期望总变失望的苦闷。比以前更能随心地做事,不觉得有什么得失之类的强迫性的精神紧张了。

    这一段时间来来往往的人还真不少,Baosheng 来大唐电信做技术支持两趟,小力姐来动物所提前报到了,表姐来武警总医院实习,表哥在丰台那面工作,周四哲子也会过来一趟。哈哈看来这京城和旧都还是不一样,真热闹。
    7/28/2007

    How to Make a Data Floppy or CD Image on Linux


    当在 Linux 下和虚拟机共享文件时,我发现一个问题,并不是所有的虚拟机都支持(或很好的支持)在主机和虚拟机操作系统之间共享文件,这样在需要文件共享时候就会遇到很多问题。不过因为几乎所有操作系统都支持读写软盘和光盘,就可以使用一种比较迂回的办法解决这个问题:建立软盘或者光盘镜像文件,虚拟机使用读写软/光驱的方式打开它,Linux 主机直接挂载它,这样就可以将这个文件作为共享目录使用。不过当虚拟机的操作系统足够强大的时候,完全可以使用虚拟网络传输。

    这样就涉及到如何建立一个数据软/光盘镜像。我们平常所挂载的光盘镜像,基本是用于只读的目的,而且是别人建立好的。如何使用 Linux 命令来建立一个数据软/光盘镜像呢?

    建立光盘镜像很简单,使用下面命令即可:

    genisoimage -o data.iso  /data/yourdir/*

    这就能直接将 /data/yourdir/ 下的所有文件建立成一个光盘镜像。但是使用光盘镜像唯一一个不足就是,它是只读的,所以文件的共享只能从一个方向进行(如果虚拟机上的系统不支持烧录CD的话 ^_^)。

    建立软盘镜像:

    前面在 Writing x86 PC Bootloader With Free Software 一文中提到了如何制作启动软盘镜像,但是这个软盘镜像仅仅能用来启动电脑,而不能用来存储数据。因为它没有被格式化,所以不能挂载,因此最主要的任务是要将它格式化。

    首先,生成空白软盘镜像:
    dd if=/dev/zero of=data.img bs=512 count=2880

    使用 losetup 命令,将 data.img 作为 loop device 使用:
    sudo losetup /dev/loop0 data.img

    然后,格式化这个 loop device:
    sudo mkfs.msdos /dev/loop0

    检查文件系统:
    sudo fsck.msdos /dev/loop0

    删除 loop device:
    sudo losetup -d /dev/loop0

    这时候,data.img 已经格式化完成,可以作为一个软盘镜像使用,比如用 sudo mount -o loop data.img  mountdir/ 挂载到 mountdir 上。设置一定的权限之后,使用虚拟机打开这个软盘镜像,就可以把这个镜像当作共享目录来使用,虽然很可怜的是这个文件只有 1.44 M 大小,但在某些时候已经能满足需要了。

    LilyBBS discussion: Segmentation Fault on Fedora and Ubuntu


    昨天和别人在小百合 LinuxUnix 版发帖讨论 Segmentation Fault 的问题,整理如下:

    flyDutchMan 根据自己存在段错误的程序在 Fedora 和 Ubuntu 上的运行结果,认为 Fedora 和 Ubuntu 对段错误的处理方式不同,他的观点是(原文链接:[href: http://bbs.nju.edu.cn/vd83468/bbscon?board=LinuxUnix&file=M.1185514732.A&num=6528 ] ):

    "Ubuntu认为段错误是很严重的错误,它的做法是当即中断程序。而Fedora对待段错误是比较宽容的,在Fedora中即使检测到某个进程正在对不属于它的地址空间进行操作,他仍然会完成这次"非法"的操作,并且继续执行后面的操作,只是在终端上打印出"Segment Fault"的错误。所以在这个程序中,虽然发生了段错误,Fedora仍然能运行到connect(),是整个程序顺利跑起来。"

    并给出了一个 demo:
    #include <stdio.h>

    #define IP_ADDR_LENGTH 16
    #define UMP_FUNC_NUM 6

    int main() {

           char addr[IP_ADDR_LENGTH];
           addr[0] = '\0';
           strcat(addr, " 172.16.64.181" );

           char (*taskpath)[IP_ADDR_LENGTH];

           printf("the address is %d\n", &taskpath[0]);

           int a;
           int b;

           sprintf(taskpath[0], "%s", addr);      

           printf("taskpath[0]: %s\n", taskpath[0]);
           printf("finish!\n");
           fflush(stdout);

           return 0;
    }

    "在Ubuntu下运行,系统不会输出" finish! "这句,而是在输出taskpath[0]的地址后直接终止程序。注意,上面的int a; int b;声明不能省略,也不能赋值!因为如果省略或赋值,就不会产生Segment Fault!(赋值的话系统就会把这两个变量分配到Stack中,这就与对Heap操作的taskpath没有冲突了)"

    我的回复是(原文链接:[href: http://bbs.nju.edu.cn/vd83468/bbscon?board=LinuxUnix&file=M.1185532985.A&num=6538 ]):

    首先,我的观点,没有所谓 Fedora 和 Ubuntu 对段错误处理的不同。因为它们都是使用 Linux kernel,而内存管理只要 Kernel 的版本一样,我认为不会有不同的处理方式。

    其次,我想纠正上文中的一个说法(可能有些讨人嫌哈,不过一些东西还是说清楚点儿好,因为 ls 用这个来解释自己的程序):

    > 赋值的话系统就会把这两个变量分配到Stack中,这就与对Heap操作的taskpath没有冲突了

    无论你赋值与否,这两个变量都是存在在 stack 中的; taskpath 也不是对 heap 进行操作,它只是存在于 stack 上的一个指针变量。

    > 因为如果省略或赋值,就不会产生Segment Fault!

    在我的系统中,都会产生段错误。

    最后,我来给出我对这个问题的解释:

    就上文的 demo 程序来说, a, b, addr, taskpath 都是存在于 stack 上的,这个很清楚,调试过 C 语言程序的人应该都知道,我就不解释了。

    1. 为什么会出现段错误?

    因为 taskpath 是一个野指针,在使用之前没有被赋值,所以 taskpath 会指向任何位置,对一个随机的位置进行写操作,显然会出现段错误。

    2. 为什么同一个程序,定义不定义 a, b 会影响段错误出来的时间点?

    虽然上面说 taskpath 会指向任何位置,但是这个说法并不完全正确。因为大家知道,taskpath 是在 stack 上的一个变量,而 stack 呢,是一直在重复使用的一个区域。要明确这一个概念,在操作系统中执行一个可执行文件,程序并不是从 main 开始的,它要先执行一段代码,也就是平常所说的 crt(c runtime)。这个一般是由 lib 提供的,其中要调用一些库函数,所以呢,在 main 执行之前, stack 被 crt 用过(这是最关键的一点)。

    因为 stack 使用完是会被释放的,这也就是在调用函数时 function prologue 和 epilogue 所干的事情,开辟栈空间和恢复栈空间,主要动作就是移动栈指针。那么 taskpath 所占的位置很有可能被 crt 用过(不是一定),那么如果被 crt 写过,比如被 crt 用做保留 ebp 或者什么其他的寄存器,它的值就是确定的(在一定程度上说)。

    如果 crt 在 taskpath 这个位置上保存过寄存器的值,尤其是 ebp 或者 esp,那么很有可能 taskpath 就指向此程序栈空间的某个位置。那么写 taskpath 指向的内存产生的段错误就没那么 critical,或者说操作系统对它的指针在自己栈空间中的操作比较容忍,就不会立即停止程序的运行。但是如果 crt 没有在这个位置上进行操作,那么这个位置就可能是某个垃圾地址,比如说操作系统自己的内存空间,那么写 taskpath 指向的内存就会造成很严重的后果,操作系统会立马检查出来终止它的运行。

    我在 Ubuntu 7.04 下使用 gcc 4.1.2 编译、调试并反汇编的结果显示:两个程序唯一的不同是 taskpath 在堆栈上的位置,当定义 int a, b; 时,taskpath 是 $ebp -40 而这个地址没有被操作过;当不定义 int a, b; 时, taskpath 是 $ebp - 32,这个地址曾经被 crt 使用过。所以按照上面的解释,系统报段错误的时间不一样。

    如果熟悉 GDB 的话,可以很容易的用调试证明这一点。计算出 crt 入口的 $ebp 和 main 中 $ebp 的差,以此计算出 taskpath 保存的位置,在上面设置 watch point,从 _init 执行到 main,看其中有没有对 taskpath 所在位置进行写操作。

    3. 为什么不同的操作系统,结果不一样?
    这个就比较简单了。kernel 不一样,可能内存管理的方式不一样。使用的 lib 或者 gcc 不一样,可能引起 crt 的汇编结果不一样。这两个都能导致同样的程序报错的时间不一样。

    所以,不是 Fedora 或者 Ubuntu 能不能容忍段错误,没有 OS 容忍段错误,不同只是在产生段错误够不够 crucial 需要得到立即处理。

    7/23/2007

    学术点名 From Cai Baiyin


    Cai Baiyin 兄这个是我觉得印象最深刻的点名方式,回答一下吧。

    规则:被点名者可以挑自己感兴趣的问题回答,如果你觉得问题设置的好,可以继续问别人。希望被提问者可以自己在后面继续加上你想要问的话题?可以相互提问。

    1,你的专业是什么,她是你最喜欢的么?如果不是,那么你最喜欢的专业是什么?

    我原来的专业是信息与计算科学(计算数学),现在的专业是信息安全。对于信息安全,我是比信息与计算科学喜欢一点儿,但是不是最喜欢的,我真的没谱。学理工的总想装作有文学修养,我也觉得古典文学对我可能更有吸引力一些 :-)。

    2,在你最喜欢的专业里请你列举出至少五位大牛,其中一位是这个专业奠基者,另外一位是你最最崇拜的。

    看来我还是说我最喜欢的专业是 CS 吧,因为我根本不知道什么信息安全方向大牛都有谁,计算机科学涵盖的广点儿,能说的人也多点儿。

    John Von Nouma:我想应该算是计算机科学的奠基人之一吧,Turing Alan Mathison 也应该算吧。
    Richard Matthew Stallman:Free Software 运动的发起者,我对他保持敬意。
    Linus Benedict Torvalds:Linux 内核作者,我不知道他算不算牛,但是我很感谢他的贡献。
    Claude Elwood Shannon:信息论的创始人,重要性自然不用说了。
    Donald Ervin Knuth:TAOCP 的作者,Tex 软件的作者,我最最崇拜的一个人。

    3,你觉得在这个专业里你能做出让自己满意的贡献么?说说你如此回答的理由?

    我是个半路出家的和尚,虽然我有信心做出一些贡献。到现在为止,我还没找到什么让我满意的贡献方向 :-)。确切的来说,我还没有开始我真正的 CS 专业学习。

    4,你满意的贡献能够具体描述给我看看么?

    如果让我臆想的话,满意的贡献当然是指可以得 Turing Award 的了,可惜,我连臆想这个可能的方向都无从下手。

    5,就你的这个专业,全球那一所学校是最强的?

    MIT? Standford? Berkerly? Carnegie Mellon? 我确实不知道哪个是最强的,但能去其中任意一个我都能高兴地发疯!

    6,你认为从事此学科的研究需要哪些方面的能力?你自己具备几条?

    哈哈,看了 phoenixinter 的回答,我觉得自己什么能力都不具备。
    还是装逼一点儿吧,我觉得做这方面研究,要有:
    数学能力(有一点儿,要说没有老师会骂我的)
    兴趣(还行)
    独立自考能力(在学术方面有点差)
    自学能力(还行)
    狗屎运(到现在为止,觉得还可以)
    细心与耐心(很差)

    7,希望自己的老婆或者丈夫也是从事这方面研究的么?

    千万不要,不然谁做饭?

    8,人类历史长河中哪位智者是你最最高山仰止的?

    智者太多了......
    亚里士多德,哈哈,因为我老听说他,却不知道他的思想内容是什么,真的是"高山仰止",哈哈!

    9,你的人生哲学

    Life is hard, get used to it.

    10.每天你花多长时间在你的学科上,分别是做什么用的?我最最感兴趣的是你花在读论文上的时间

    这个统计起来比较困难,得分阶段吧。我喜欢的时候是一整天,不喜欢的时候不会碰,平均下来,也就那么三四个小时吧~~~

    读论文啊,读得很少很少很少,如果平均到四年,大概每天只有几分钟。

    其实总的来说,虽然看起来我在计算机科学的应用方面还可以,但是真正对理论科学的研究是相当少的,这也是我为什么研究生阶段要转到一个计算机方向的原因(虽然也有很大一方面是因为世俗的欲望)。

    接着点下去:
    Forrest Sheng Bao, Eric You Xu

    如果你们看到了,就接着来,没看到或者没时间就算了。
    7/21/2007

    Writing x86 PC Bootloader With Free Software


    Hacking 《自己动手写操作系统》Chapter 1&2
    ——Writing x86 PC Bootloader With Free Software

    今天在看一本书,《自己动手写操作系统》(于渊,电子工业出版社),虽然很欢迎这样一本详尽介绍怎样写操作系统的书出现,但看完前两章后对作者的某些做法很不以为然。比如使用 Windows 作为开发平台,采用商业虚拟机作为测试平台,不是每个人都买得起这些软件的(我们要在心中牢固树立使用盗版软件就是犯罪的观念 X-D)。

    我这篇文章的目的就是为了展示 Linux/Free Software 的强大,不使用任何商业软件,不用自己写的任何工具,使用免费的工具链,照样可以完成而且更高效地完成《自己动手写操作系统》前两章的 demo。

    当然我也希望这篇文章为推动 Linux 和 Free Software 的发展出一点力,比如让部分读者(尤其是 EE 和 CS 学生)看完这篇文章后舍弃瘟都死,投身到 Linux 和 Free Software 阵营中来,或者《自己动手写操作系统》的作者在下一版(如果有的话)中完全使用 Free Software 来做 demo。

    好了,下面开始,先介绍一下需要使用的工具。
    操作系统:Ubuntu 7.04 Feisty,平台: i386 PC。
    使用工具:gcc, binutils(as, ld, objcopy), dd, make, hexdump, vim, virtualbox。
    上面所说的工具中,除了 virtualbox 虚拟机,剩下的工具在任何能用做开发环境的 Linux 版本上都是默认安装的。VirtualBox 也是遵从 GPL 协议的开源软件,可以从这里 [href: http://www.virtualbox.org ]下载。Ubuntu 只需要 sudo apt-get install virtualbox 安装即可。

    首先,我们看第一个示例代码:
    [wbyang@solrex-PC loader]$ more boot.asm
        org    07c00h            ; 告诉编译器程序加载到7c00处
        mov    ax, cs
        mov    ds, ax
        mov    es, ax
        call    DispStr            ; 调用显示字符串例程
        jmp    $            ; 无限循环
    DispStr:
        mov    ax, BootMessage
        mov    bp, ax            ; ES:BP = 串地址
        mov    cx, 16            ; CX = 串长度
        mov    ax, 01301h        ; AH = 13,  AL = 01h
        mov    bx, 000ch        ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
        mov    dl, 0
        int    10h            ; 10h 号中断
        ret
    BootMessage:        db    "Hello, OS world!"
    times     510-($-$$)    db    0    ; 填充剩下的空间,使生成的二进制代码恰好为512字节
    dw     0xaa55                ; 结束标志
    此段代码使用 Intel 格式的汇编语言写成,本也是用同样开源的 NASM 编译,但是鉴于很少有人在 Linux 下使用此汇编语法,它在 Linux 平台上的扩展性和可调试性都不好(GCC 不兼容),而且不是采用 Linux 平台上编译习惯,所以我把它改成了使用 GNU tool chain 去编译连接。这样的话,对以后使用 GNU Toolchain 编写其它体系结构的 bootloader 也有帮助,毕竟 NASM 没有 GAS 用户多。

    上面的汇编文件可以用 AT&T 风格改写为:
    [wbyang@solrex-PC loader]$ more boot.S
    .code16            ;使用16位模式汇编(GAS 默认认为 .S 文件是 pure 32-bits i386 code)
    .text            ;代码段开始(为 link script 做定位)
            mov        %cs,%ax
            mov        %ax,%ds
            mov        %ax,%es
            call       DispStr            ;调用显示字符串例程
    INF:    jmp        INF                ;无限循环(GAS 没有 $ 作为当前行标号的约定)
    DispStr:
            mov    $BootMessage, %ax
            mov    %ax,%bp            ; ES:BP = 串地址
            mov    $16,%cx            ; CX = 串长度
            mov    $0x1301,%ax        ; AH = 13,  AL = 01h
            mov    $0x00c,%bx        ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
            mov    $0,%dl
            int    $0x10            ; 10h 号中断
            ret
    BootMessage:.ascii "Hello, OS world!"
    .org 510            ; 填充到 510 字节,使生成的二进制代码恰好为512字节
    .word 0xaa55        ; 结束标志

    但有一个问题, NASM 可以直接使用 nasm boot.asm -o boot.bin 将 boot.asm 编译成 bin 文件,GAS 不能。但是 GAS 的不能恰好给开发者一个机会去分步地实现这个过程,使编译更为灵活。下面请看 link script 和 Makefile:
    [wbyang@solrex-PC loader]$ more solrex_x86.ld
    SECTIONS
    {
      . = 0x7c00; 
      .text :
      {
        _ftext = .;   //告诉链接器程序加载到内存的7c00处
      } = 0
    }

    这个连接脚本的功能就是,在 link 的时候,将程序加载到内存 0x7c00 的位置(BOIS 将 PC 控制权转交给这个位置运行的程序),相当于 boot.asm 中的 org 07c00h 一句。有人可能觉得麻烦,还需要用一个脚本控制加载地址,但是 《自己动手写操作系统》就给了一个很好的反例:Chapter 1.5 代码 1-2,作者切换调试和运行模式时候需要对代码进行注释,而使用脚本控制,只需要编译时候调用不同脚本进行连接,就能解决这个问题。

    这在嵌入式编程中是非常常见的处理方式,使用不同的连接脚本一次 make 生成某个程序分别运行在 board 上和 simulator 上的两个二进制文件 。

    相信只要能耐心看到这里的人对下面 Makefile 中的内容都不会陌生。
    [wbyang@solrex-PC loader]$ more Makefile
    CC=gcc
    LD=ld
    LDFILE=solrex_x86.ld            #使用上面提供的连接脚本 solrex_x86.ld
    OBJCOPY=objcopy

    all: boot.img

    boot.img: boot.bin
            @dd if=/dev/zero of=emptydisk.img bs=512 count=2880        #生成空白软盘镜像文件
            @dd if=boot.bin of=boot.img bs=512 count=1                 #用 bin file 生成对应的镜像文件
            @dd if=emptydisk.img of=boot.img skip=1 seek=1 bs=512 count=2879        #在 bin 生成的镜像文件后补上空白,最后成为合适大小的软盘镜像

    boot.bin : boot.elf
            @$(OBJCOPY) -R .pdr -R .comment -R.note -S -O binary boot.elf boot.bin

    boot.elf: boot.o
            $(LD) boot.o -o boot.elf -e c -Tsolrex_x86.ld

    boot.o: boot.S
            $(CC) -c boot.S

    clean:
            @rm -rf boot.o boot.elf boot.bin boot.img

    使用 Makefile,一个是方便,直接就可以生成可引导的软盘镜像文件,二是为了清楚,其间对源文件的任何处理都一清二楚。下面解释一下 Makefile 都做了什么:
    第一步, gcc 调用 as 将 boot.S 编译成目标文件 boot.o;
    第二步, ld 调用连接脚本 solrex_x86.ld 将 boot.o 连接成可执行文件 boot.elf。
    第三步, objcopy 移除 boot.elf 中没有用的 section(.pdf,.comment,.note),strip 掉所有符号信息,输出为二进制文件 boot.bin。
    第四步, dd 使用 boot.bin 生成可引导的软盘镜像 boot.img。

    到此,我们使用开源工具链编译生成 bootloader 的过程已经结束,没有使用到任何商业软件,也没有自己写任何转换工具。《自己动手写操作系统》文中提到的 HD-COPY 和 Floopy Writer 都没有使用到。 为了验证也可以先用 hexdump -x -n 512 boot.img 将 boot.img 前 512 个字节打印出来,可以看到 boot.img dump 的内容和附送光盘中的 TINIX.IMG dump 的内容完全相同。这里我们也显然用不到 EditPlus 或者 UltraEdit,即使需要修改二进制码,也可以使用 vim 的 %!xxd 命令进行十六进制编辑。

    写得真够累的,那个 virtualbox 就不说了,用法跟 virtualPC 没有什么大差别。安装上以后,新建一个虚拟机,加载 boot.img 光盘镜像到软驱,然后选择虚拟机重新启动,就可以看到红色的:
    Hello, OS world!
    当然,你如果喜欢的话,可以改成 "F-U_C-K Microsoft!" 不过要注意的一点是,做这件事是需要权限的,要把当前用户加到 vboxusers 组中,否则这个行为无法成功 :-)。

    综上,很显然 VirtualPC 也不需要。《自己动手写操作系统》可怜的作者费了半天劲在瘟都死的 VirtualPC 里装 Redhat Linux,解决瘟都死和 Linux 的文件共享问题,解释了一番自己"工欲善其事,必先利其器"的动机,但我实在没看出有一点儿需要瘟都死的原因。瘟都死什么都不能给你,但 Linux 能给你整个世界!

    7/19/2007

    Tor - Anonymity on Line


    其实以前就见过 Baosheng 在博客里推荐 Tor 这个工具,据说可以访问 Wikipedia,只是当时潜意识里觉得太麻烦,就懒得搞。昨天晚上 Baosheng bg,请 ufx222, xum84, daoming, proline 我们一起吃饭,又提到了这个洋葱路由,今天就尝试了一下,果然好用。

    简单来说,Tor 的功能就是,采用不同的"洋葱路由器(onion router 意思和代理服务器差不多)"来重定向网络请求,并且随时间更换路由,这样别人就无法监视你的网络访问情况,主要目的是为了保护隐私。而由此带来的副产品就是,onion routers 遍布全世界各地,所以就可以使用这个工具通过 onion routers 访问被"墙"封掉的站点(比如现在的 blogspot.com )。更多介绍请登录 Tor 官方网站 [href: http://tor.eff.org/ ] 。

    从我的使用来看,刚开始使用访问网站速度可能慢点儿,用了一段时间之后速度就快很多了,大概是 Tor 自动在寻找洋葱路由服务器。而且最牛的是,我们公司的 DNS 坏了一小段时间,其间什么网站都没办法访问,而通过 Tor 居然访问正常,大概是 Tor 记录的是 IP 而不是 domain 吧。有意思的是访问 google.com 往往被重定向到某个欧洲的 Google 服务器,比如: google.de, google.es 之类的。

    在 Linux 下 Tor 的配置很简单(我估计在 Windows 下会更简单,官方网站上有各种系统安装介绍):

    首先,安装 Tor 软件,在 Ubuntu 下面就是:
    sudo apt-get install tor
    使用默认配置即可,即在 9050 端口打开一个 SOCKS 服务器。Tor 程序会以后台方式一直运行在系统里。

    其次,为 Firefox 下载 torbutton 插件[href: https://addons.mozilla.org/en-US/firefox/addon/2275 ],安装。安装完成后,到"Tools->Add-ons->Extensions->Torbutton Preferences",在 "Proxy Settings" 中选择 "Use custom proxy settings",然后将前四个都留空,最后 "SOCKS Host:" 中填: localhost, Port: 9050,这样配置就完成了。

    可以留意 Firefox 状态栏的最右端(窗口右下角),这时候会出来一个 "Tor Disabled",用鼠标点击该区域,就可以在 "Tor Disabled/Tor Enabled" 状态切换。这样在访问某些敏感站点时候就可以 Enable 它,在不需要时 Disable 它。也可以在 Torbutton Preferences中把这个文字格式的提醒改成一个洋葱头的图标提醒。

    其实我想,不安装插件,只在网络设置中使用 SOCKS 代理也可以实现这种功能,如果这样的话,这里插件的作用只是启用和不启用代理的区别。那么,如果在校园网内,这个插件能否起到在 Firefox 的代理和插件这两个代理之间切换的目的呢?如果可以的话,就算不使用或者不能使用 Tor,这个插件也可以用作切换校园网代理使用了,倒也蛮方便的(只是我不需要用到了,所以就留给别人验证吧 X-D)。

    7/17/2007

    [Share] The Shortest Distance...


    从 baosheng 的博客上看到一篇颇具灵性的文章《世上最短的距离... 》,特转载之.

    Original post: [href: http://bbs.nju.edu.cn/vd45799/blogcon?userid=baosheng&file=1184249302 ]

    Baosheng 者,鲍盛也,更多请看其个人主页:[href: http://forrest.bao.googlepages.com/]

    PNN充分贯彻了Simple is beauty的原则:第一层求距离,第二层找最近的这也就是聚类识别的基本思路。这就带来一个问题,你如何定义距离? dot product? Euclidean distance?

    所以,这世界上最短的距离不是我站在你面前而你不知道我爱你,而是我站在你面前,你却不知道如何定义距离。

    近期准备写一篇文章,Why PNN is awesome? (为什么PNN帅呆了? )偶很喜欢把awesome翻译成帅呆了而不是令人敬畏的....

    PNN: Probabilistic Neural Network(概率神经网络), 一种基于Radial Basis Network(径向基网络)修改过的网络,号称有下列优点:
    1. 1000 times faster than back-propagation network
    2. robust to noise

    附H. Zhu研究small world时作的一篇文章:
    偶大一时候还不懂什么叫greedy algorithm,那时居然想做研究,寒...

    更多的信息请参考:
    [1] J. M. Kleinberg, Nature 406, 845 (2000).
    [2] M. Granovetter, Science 301, 773 (2003).
    [3] Han Zhu and Zhuangxiong Huang, cond-mat:0404377 (available at arxiv.org)

    [4] 成龙,舒淇,《玻璃樽》。

    女孩子为了求得冥冥中的如意郎君,会作出种种傻事,据说其中第四十八傻的一种,是把求爱信放在一个瓶子里,投入大海,盼望在这种超越人和人的穿梭中,爱情能找到归宿。


    之所以说这只是第四十八傻,因为这其实还并不算特别傻(相比于其他)。爱情是一种近邻双体相互作用,所以这种漫无目的的穿梭,由于其超越了人的因素,反而可能会快很多。

    那么怎样才是最有效的传递方式呢?现在大家可能都听说过小世界的概念。人类社会是一个小世界,是因为在近邻联系之外,还存在着很小一部分长程联系。因此,表面上看起来千山万水的距离,也许就隐藏着一个很巧妙的快捷路径。

    但是人类社会何其复杂,我们渺小的个人,怎能通晓所有的结构。世上人来人往,单纯的女孩,又何处寻找藏匿的他?很遗憾,即便是真的有很短的路径,我们也很可能茫然不知。

    泰戈尔听说这一点以后,欣然修改了他的诗句:
      世界上最遥远的距离,不是天涯海角,
        而是有快捷路径,我却不知道。

    先来考察一下,我们是怎样传递信息的?这是一个很基本的问题,每个人都有过体会。譬如说,我们要把一个信息传递给一个不认识的住在北京的医生。我们总是先把信息传给一个北京的朋友,他考虑了一下,再把信息传递给一个在医疗系统里工作的朋友,而由于这个人仍然不认识那个医生,只能把信息传给在那个医院里工作的熟人,最后才终于交给目标。每一次的传递,都是试图交给和目标最接近的人,曲线救国永远是不被考虑的。实际上,也许就存在着短得多的路径,比如说那个目标也许就是某个人的小舅子,但是由于是曲线救国,而没有被考虑到。

    千万年来,人类都是采用这样一种方式(有个名字,叫greedy algorithm)。也许你已经猜到了,这种方式,只有在某一些网络里面才是有效的。条件很简单,在这些网络中,长程的联系出现的概率一定要随距离衰减(衰减不能太快,也不能太慢)。只有这样,北京人和北京人,医生和医生之间相互认识的概率才会比一般情况大。这样才能发挥greedy algorithm的优势。在真正随机建立起来的小世界网络中,它的效率是很低的。因此,在随机的小世界网络中,虽然真正的平均距离很小,但这毫无用处,因为我们根本找不到路径。

    也许人类社会就是这样一种情况,也许还不够optimal。这是一个根本问题,要搞清楚它很不容易。

    说到这里,我给仍然待字闺中,准备送出玻璃樽的女孩子们一个建议。我相信你们心目中肯定都对理想郎君有了很明确的标准。比如说,如果你们想要找帅哥,你们不妨可以采用greedy algorithm,因为南大帅哥是比较多的,你们可以先把求爱信交给南大的同学,然后南大的同学一看,帅哥物理系最多阿,再把这封信交给物理系,在物理系内部,帅哥之间的联系是很密切的,大家交流一下,很容易就能推选出符合你要求的人选。

    泰戈尔了解到这一点,欣然改了他的诗句:
      世界上最遥远的距离,不是有快捷路径你却不知道,
        而是有物理系同学,你却不懂他的好。
    7/16/2007

    Class Member Function as pthread_create Argument


    花了三个工作日把原来写的一段通信守护进程代码从过程方法改到了 template class,对于 template 的使用和类的派生明白了不少道理。还有个很受启发的一点,就是 C++ 中如何使用类的成员函数作为创建线程的开始函数。
    pthread_create 是 POSIX 标准下创建线程的函数,函数原型是:
    int pthread_create(pthread_t *thread, pthread_attr_t *attr, void*(*start_routine)(void *), void *arg);

    在 C 中,这个函数使用很简单,只要定义一个参数和返回值均为 void * 类型的函数,使用函数名字作为参数即可。就算不完全符合,可以使用 (void *(*)(void *)) 将其强制转换为符合类型检查规格的函数指针。但是,类的非静态成员函数隐含 this 指针作为第一个参数,所以参数完全不可能转化为 void * 类型,而 C++ 的类型检查要比 C 严格许多。由于我原来写的代码是 C 风格的,自然不会出现类型不符的问题,现在将线程开始函数封装到一个模板类中,再创建线程的时候就不能满足需要了。

    在试了几种转换无效之后,从网上搜到一种方法:定义线程开始函数为类的静态成员函数(static member function),这样就不隐含 this 指针了,然后将 this 指针从 pthread_create 最后一个参数传给开始函数,在函数中将 void * 类型的 this 指针强制转换为类指针。看来静态成员函数还是有些妙用的。

    ===================我叫分割线===================

    带着我妈和我妹在北京城里转悠了几天,累得不行。主要原因在我,没有考虑到身体因素,连着玩消耗太大,再加上自己也没车没房,倒公交车和住宾馆也要走很远,费时间又费劲。我都快受不了了,别说我妈了。以后再出去玩,坚决不会再连着转三天以上,要么紧紧张张地玩两天,要么就花时间长点儿,走走歇歇。唉,谁让咱是穷人呢,又有钱又有闲的日子还没过上呢!

    今天看了下积压很久的博客订阅,同学里开始写和继续写的人越来越多了。觉得有些文章比较阴沉低迷,因为自己从大三开始心情就老是跌宕起伏,反而在面对这许多次的分别聚首时坦然一些。要不是周熹在毕业聚餐时候专门招我,也不会哭得那么厉害。散了散了散了吧,没有离别,怎么会有重逢呢?

    还是在 Yourui 的博客上看到小恪去新疆的消息,要是当面看到他,肯定会玩笑说发配三千里伊犁充军去了。这在边关待了两年之后,再回来学积分拓扑之类的数学还能看得下去吗?都说是命运无常,旅途坎坷却能看更美风景,那关外不知还是不是大漠孤烟长河落日的大西北。

    刚才去吃饭,走在晚间暖暖的懒洋洋的空气中,忽然有点儿秋天的感觉。想起 7 年前爸爸送我到商丘一高上学的情景,日子可真快啊!老了,老了!
    7/10/2007

    A Sunny Day


    一会儿晴一会儿阴,怪怪的天气持续好几天了,不像秋冬时候的北京,几乎滴水不沾。据说南京也下了好大雨,校园里的水都要沒过膝盖了。今天跟 baosheng 聊天时候还说:在南京待了四年没发过水,我一走,发了;在南大上了四年没死过人,我一走,死了。嗨,不说这个了,晦气。反正今天天气相当的好,当然,也相当的热。

    前几天在"带三个表"博客上看到推荐《流血的仕途-李斯与秦帝国》,历史小说,觉得挺有意思的。周日到第三极书局,坐在台阶上看完了,真不错,语言杂古杂今,颇为诙谐。而且对那段历史有自己的解读,有很多事情觉得像是编的又像是确有其事,让人摸不准。反正自己也不是历史研究者,不必咬文嚼字,编不编就随他去吧,我只是喜欢故事。

    后天我妈和我妹来北京玩,可能要请两天假了,陪我妈逛逛北京城。她在送我去南京上学的时候才第一次出过河南,而且当时家里比较困难,我也没有主见,在报到之后就让她回去了,没有在南京好好玩玩。我妈也只有寒暑假有时间,这个时候我一般又都在家,所以很可惜没机会带她再玩。现在就不一样了,我在北京已经基本稳定下来,而且自己实习也攒了点儿钱,可以告诉我妈说,你就坐车过来吧,不用带钱了,吃住玩儿子包了 :-)。我妈辛苦了一辈子,光在电视上见过首都,现在就能凭自己的能力让她在京城转转,真的很自豪,而且让老妈看看自己工作和学习的地方,对自己的担心也会少一点儿,以后能在家的时间真的很少了。
    7/7/2007

    Log - on 20070707


    今天比较闷热,刚刚外面在下雨,貌似又停了。在床上躺了将近一天,晚上跑北航吃的晚饭,因为 Weekly Report 还没有发给 PM,所以只好到公司一趟。昨天在北航食堂办了张租借卡,50 块押金,每月 5 块租金,刷卡加收 15% 餐费,真黑。不过没办法,在外面的小馆子吃饭有诸多不便,而且少有实惠又合口味的饭馆,只能忍了。从去年开始体验到在外面吃饭的诸多不爽,我就再也没抱怨过学校食堂,还是食堂比较合适各种口味的人吃饭。当然,那些从小娇生惯养的除外。现在幻想,Google 中国有自己的食堂和名厨,那他的员工真是相当的滋润,不过饭菜能打包回家吃不?

    说到北航,就提一下最近挺有印象的两个特点。一,食堂的饭卡管理人员都是"一指禅"。而且还是相当慢的"一指禅",那个打字的速度啊,输我的名字大概花费了二十秒,真不敢想象北航居然请这些人用电脑。如果说是照顾下岗职工或者是职工家属,你起码得找点能打字的吧,这样不是浪费同学的时间吗?二,搞笑的南门交通问题。北航的南门(锦秋国际对门)每天晚 7 点关门,非常不方便同学进出,但是它又有非常人性化的一面,南门的栏杆缝隙足够像我这样的体型进出。经常看见这种景象,保安关上门以后,看着一个个同学仍然义无反顾地朝关上的大门走去,然后非常精确地侧身从栏杆缝隙中穿过,简直可以算是北航一景了。我大概都穿越过二十次以上了,哪天一定要拍张照片发到相册中去。

    昨天晚上和公司同事一起喝酒,一直到十一点多,回到住处已经是凌晨了,这也是导致今天没精神的重要原因。不过倒是听了不少有趣的谈话,硬件部的老板 Simon 说:"一个男人要想成熟应该学会四条:一,喝不加佐料的纯咖啡;二,喝啤酒,而且要是黑啤酒(guiness);三,吃苦瓜;四,品尝碧螺春。"然后他自己又加了一条:抽古巴雪茄,不过他说自己还没达到这一条。公司里还流传着一条 Slog: Be the best chip company in China. 据说是 Simon 酒后的豪言。还有一个 Berkeley EECS 的实习生 Kevin,今年大二,才 19 岁,不到美国允许喝酒的年龄,但是到中国就开怀畅饮啦!然后我问他在 UCB party 很多吧,有没有喝过酒?他说,我们 EECS 的学生课业很重的,party 很少的,他大学两年只参加过一次 party。他说 Berkeley 校区北部 party 比较少一些,南部比较多些。名校还是不一样,而且 EECS 读起来也应该不容易,啥会儿我能进这样的学校啊?
    7/3/2007

    Beijing Again


    好些天没有更新博客了(针对我的更新频率而言),原因很简单,有更重要的事情去做 :-)。

    1 号到的北京,把寄放在同学那里的被子拖到租住的公寓,请邓飞、丽君吃了顿饭。2 号到公司报到,换了个办公桌,换了个电话。寄来的包裹和录取通知书同时到达,纳闷不已,为什么北京往南京挂号需要七天而南京挂号到北京只需要三天?害得我为了一张纸折腾(中科院的录取通知书着实简陋,信封是牛皮小信封,通知书就是一张请柬大小)。我原以为是通知书的那玩意儿是入学须知,但搞不明白的是,为什么入学须知要寄给我两次?

    一毕业,这同学们好久不更新的博客都重新拾起来了,反而显得我有点儿懒。这下到公司工作,晚上的时间就多了些,可能又要恢复我正常的更新速度了。

    这两天工作也没干什么事,FPGA 调试还不太熟练,模拟器又改了不少,而且更新中工作不太正常,所以就随便看看代码、看看邮件列表和一些 patch。GDB 的 mailing list 里这两天挺有意思的,有个人发了一个希望把 GDB 代码用 C++ 重写的邮件,然后一群大佬说这个问题别讨论了,各持己见讨论起来会没个头的。但是某个邮件里有巨牛的一句话:"The more C++ code I see, the more convinced I get that the language should die. "让我叹服不已,哈哈。

    重装了一个 Ubuntu,当然也装上了 beryl,比原来用着更方便了。Google desktop for linux 推出了,试用了一下,挺好的,特别喜欢它的两下 ctrl 就可以弹出搜索框,这样就免得我还得用鼠标把光标定位在 Google toolbar 里去。Google desktop 的 sidebar 没有在 Linux 版本上体现出来比较遗憾,那些小工具很有意思,但其实 Linux 本身就带有很多有一些的小玩意儿,喜欢玩的能把桌面配置得很 cool 或者 cute。为 Firefox 装了一个 IE7 的主题,看起来还是蛮好的,看来 Microsoft 的 UI 工程师也不是吃干饭的。但是 wine 现在还不支持 IE7,用 ies4linux 测试版装上之后,IE7 的 UI 效果一点儿也没有,真没劲。

    毕业了,大家都在干不同的事,还有人(XHO)感叹没假期了,哈哈,准备成家立业的时候已经开始了,慢慢就该习惯了。