64位Ubuntu上使用Network Connect

Network Connect 是 Juniper 公司出品的配合其安全硬件 VPN 解决方案的软件包,很多公司使用这个 VPN 解决方案,一般需要使用 RSA Token 动态密码登录。Network Connect 支持 Windows 和 Linux 操作系统,但很遗憾的是,它只支持 32 位 Linux。下面以 Ubuntu 为例,介绍如何

在 64 位 Linux 上安装并使用 Juniper Network Connect

1. 安装浏览器 Java 插件(64位);

$ sudo apt-get install icedtea-plugin

虽然看起来只安装了一个软件包,但实际上可能会下载依赖的 OpenJDK 的一系列软件包。这是为了在 Firefox 下能够正确启动 Network Connect 的安装过程。

2. 修改 root 密码;

$ sudo passwd

由于 Ubuntu 默认不使用 root 用户,下面自动安装 Network Connect 软件时候又必须提供 root 密码,所以这里必须先初始化 root 的密码。

3. 打开 Firefox,访问 VPN 网站。

像在 Windows 下那样,先登录进入 VPN 页面,再点击 start,启动 Network Connect 的自动安装过程。过程中会弹出一个很丑的终端,安装时需要输入 root 密码,但是最终必定是无法弹出 Network Connect 小图标,也连接不上。

4. 下载脚本 junipernc[1],并且安装到执行目录 /usr/bin 中;

$ wget http://mad-scientist.net/junipernc -O junipernc 
$ chmod 755 junipernc
$ sudo mv junipernc /usr/bin

5. 安装 Network Connect 二进制程序依赖的 32 位动态链接库;

NC 具体的可执行程序是 ~/.juniper_networks/network_connect/ncsv ,是 32 位的可执行程序。如果不安装它依赖的 32 位动态链接库[2],该程序是执行不了的。

$ sudo apt-get install libc6-i386 lib32z1 lib32nss-mdns

6. 执行 junipernc 脚本,会跳出各种对话框,对应填入各种参数;

$ junipernc --nojava

URL 就填入 VPN 网站的域名,USER 就是自己的用户名,REALM 比较麻烦,需要自己查看 VPN 网站登录页面的源代码,看对应 REALM 域实际表单提交的 value 是什么,填进去即可。

--nojava 的意思是,只执行 VPN 连接,不启动 Network Connect 小锁图标的 Java 程序。因为该 Java 程序要求 32 位 Java 环境。

连接失败会有提示;连接成功后,junipernc 会一直停在那里,终止连接可以使用 Ctrl-C 命令行,或者 sudo killall -9 ncsv。

6-1. 修改 junipernc 配置;

junipernc 有两个配置文件,一个是 ~/.vpn.default.cfg,保存着用户手工输入的配置;一个是 ~/.vpn.default.crt,这个是从网站上下载下来的证书。

这样,一般的 VPN 连接功能就实现了。如果希望启动 Network Connect 小锁图标并监控 VPN 的流量信息,就需要

在 64 位 Ubuntu 上安装 32 位 Java 环境[3]

如果不是特别需要,不建议折腾下面这套东西。

a. 到 Oracle 网站上下载 32位 Java 的 tar 包;

到这个地址:http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html#javasejdk下载例如 jre-7u3-linux-i586.tar.gz 的 Linux JRE 包。重要的特征是那个 i586。

b. 解压并安装到 jvm 目录,调整默认 java 的链接到 32位 JRE。

$ tar xzvf jre-7u3-linux-i586.tar.gz
$ sudo mv jre1.7.0_03 /usr/lib/jvm
$ sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jre1.7.0_03/bin/
java 73
$ sudo update-alternatives --config java

最后一个命令会给出一个 Java 的列表,如下所示,选择 jre1.7.0_03 对应的编号即可。

There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                      Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-6-openjdk/jre/bin/java   1061      auto mode
  1            /usr/lib/jvm/java-6-openjdk/jre/bin/java   1061      manual mode
* 2            /usr/lib/jvm/jre1.7.0_03/bin/java          73        manual mode

Press enter to keep the current choice[*], or type selection number: 2

c. 验证 java 可以执行且版本正确(其实依赖上面的第 5 步);

$ java -version
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) Server VM (build 22.1-b02, mixed mode)

d. 安装 32位 JRE 可能依赖的 32位动态链接库。

$ sudo apt-get install ia32-libs

这个包会依赖非常多的 32位链接库,安装过程会比较漫长。

参考文章:

[1] Using Juniper Network Connect on Ubuntu
[2] Debian6(64位)搞掂Juniper VPN
[3] Installing 32 bit java now that ia32-sun-java6-bin is not available

MIUI的贴心功能

预先声明:这不是一篇软文,我真的是出于对 MIUI 系统的喜爱才写的。

我的手机型号是华为 U8800,联通定制机,自带的 ROM 里太多乱七八糟的软件,后来就刷了华为官版的海外 ROM。这个 ROM 是比较干净的版本,但不知道为何老是黑屏重启,基本上每天会重启了一两次。毕竟追求的是性价比,这点儿缺陷我就忍了。

不过基于安卓用户的刷机习惯,后来我还是忍不住刷了修改的 MIUI ROM——因为我的手机型号不在 MIUI 的支持列表里。第一次刷的是 2011 光棍节版,前两天又更新到 2.3.2 版。MIUI 很多贴心改进让我爱不释手,下面我会列举一下。

  1. 菜单键+音量- 执行屏幕截图,下面的图片有些是用这个功能截的。

  2. 拨号键盘使用 T9 拼音直接搜索联系人,支持模糊查询。

    拨号键盘

  3. 通知栏内置很多有用的功能快捷开关。

    通知栏

  4. 系统自带防打扰过滤器功能,可以按照规则过滤垃圾短信和电话。

    防打扰

  5. 可在联系人列表中直接查看到手机号码的归属地,这样当某些朋友有多个手机号码时,容易判断该打哪一个。

    联系人
  6. 陌生人的未接电话可以显示号码归属地和响铃次数,而且第一声响铃静音。这对判断来电是否是垃圾电话非常有帮助。

    陌生人来电
  7. 内置流量监控和防火墙功能,可以为每个应用程序设置网络访问权限。

    流量监控和防火墙
  8. 内置音乐播放器与百度合作,提供在线音乐功能。

    音乐播放器
  9. 内置手电筒功能,且在锁屏时可以长按 Home 键打开手电筒。这个功能实在是太有用了!

    手电筒
  10. 电话功能设置很多贴心小功能:自动录音、接通挂断时振动、来电挂断时提供短信回复、通话记录点击显示联系人信息等等。

    电话设置
  11. 最后值得一提的是,虽然不算个功能,但刷了 MIUI 之后,每天重启的现象居然没了!我完全没想到第三方修改的第三方 ROM 居然比官版 ROM 还稳定,这个出乎了我的意料。

代码行统计工具-CLOC

在工作中有时会有需要统计代码的行数,一般会用 wc 给出一个大致的结果。只不过在源代码文件分布比较分散,且存在多种不同类型语言的源代码时,wc 就不是特别适合了。

在公司内部也见过一些同事实现类似功能的脚本,但我想这应该是一个通用的需求,于是就找到了这个工具 - CLOC。其实就是一个 perl 脚本,很好用,统计报告也很清晰。在这里推荐一下。下面是一个统计 leveldb 源代码行数的例子。

$ cloc .
     128 text files.
     123 unique files.                                          
     353 files ignored.

http://cloc.sourceforge.net v 1.55  T=0.5 s (238.0 files/s, 46718.0 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C++                             60           2012           1258          13124
C/C++ Header                    52            968           1458           2690
HTML                             3             84              0           1094
C                                1             33              7            255
make                             1             43             17            153
CSS                              1             10              1             78
Bourne Shell                     1              9             19             46
-------------------------------------------------------------------------------
SUM:                           119           3159           2760          17440
-------------------------------------------------------------------------------

SHELL TIPS: rsync 和 crontab 变量

本周我遭遇了一个惨痛事件,远程开发机有两块硬盘同时损坏,整个分区数据完全丢失。这直接导致我在开发机上 home 目录中所有文件人间蒸发了,真是一觉回到解放前!

值得庆幸的是这件事发生在端午假期中间,放假前我把大部分源代码都提交到了库里,辛苦劳动的损失倒不大。但是之前种种努力搭建的开发环境全丢失了,这一点让人很郁闷。为了不再遭受这样的损失,我痛下决心学习了一下 rsync,用来同步和备份数据。

不得不说 rsync 也是一个神器啊,man rsync 发现有各种灵活用法,最有用的我觉得还是通过 ssh 来备份的方法。发现了这个秘密后,我觉得用来备份自己的网站数据也不错。下面是我使用的参数:

rsync -avzuptS --delete --max-delete=100 -e "ssh" username@solrex.org:~/ ~/backup

如果懒得输入 ssh 密码,可以使用 ssh 公钥认证

一旦配置了公钥认证,这个备份命令就可以定制为 cron 任务定时执行了。这时候我发现一个有趣的问题:如果镜像了整个 home 目录的话,无法记录命令执行日志。 因为无论日志写入到 home 目录下哪个地方,都会因为远端没有这个文件被 rsync 删除掉。无奈之下只好使用笨方法,让 cron 把同步日志发邮件给自己。

$ crontab -l
SHELL=/bin/bash
HOME=/home/work
MAILTO="someone@somesite.com"
PATH=/home/work/local/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin
00 21 * * * mirror_site

把 SHELL 配成 /bin/bash 的原因是 /bin/sh 可能会导致一些不常见的诡异问题,例如这个。同样,在 crontab 中声明 PATH 环境变量可以避免某些命令找不到的问题,特别是自己写的放在 home 目录的脚本。

僵尸对象或 RAII

我最近在想这个问题,到底要不要在程序中使用异常?

以前写的 C 代码比较多,即使写 C++,基本上也是把它当成 C with object 来用。对异常的了解偏少,使用更是极少。最近评审别人代码的时候遇到一个问题:如果构造函数中 new 失败了,会发生什么事情?

工程的代码一般提倡哪里出错在哪里处理,不能恢复的要返回错误码给调用者。在一般情况下,使用 new(std::no_throw) 保证 new 不抛出异常(否则结果是灾难性的),并且检查分配是否成功是可以实现这一点的。

遗憾的是构造函数没有返回值,我们不能返回构造失败。那么只有用迂回的办法,为类定义一个成员变量 bool inited。初始化为 false,只有在构造的工作都完成之后,才将它置为 true。如果一个对象的 inited 成员为 false,就意味着它构造过程中出了问题,不能被使用。这就是一个僵尸对象,“活死人”。

看,我们成功地规避了使用异常。但是慢着,不是只有 bad_alloc 这一个异常啊!还有 bad_cast、runtime_error、logic_error,还有:

$ grep class /usr/include/c++/4.5/stdexcept 
// Standard exception classes  -*- C++ -*-
// ISO C++ 19.1  Exception classes
   *  program runs (e.g., violations of class invariants).
   *  @brief One of two subclasses of exception.
  class logic_error : public exception 
  class domain_error : public logic_error 
  class invalid_argument : public logic_error 
  class length_error : public logic_error 
  class out_of_range : public logic_error 
   *  @brief One of two subclasses of exception.
  class runtime_error : public exception 
  class range_error : public runtime_error 
  class overflow_error : public runtime_error 
  class underflow_error : public runtime_error 

天那,我未曾注意过标准库有那么多异常!那么如果在使用标准库时,不小心触发了什么异常,OMG!

这样看来,使用异常是很有必要的。但是,麻烦的问题又来了,一旦使用异常,函数的退出过程就变了。使用错误码有一个好处,就是你可以在函数返回前擦干净自己的屁股;但是使用异常呢?你既要保证对象能够自己擦屁股(RAII),还要保证函数能自己擦屁股(在正确的位置使用异常处理),这样才能在 stack unwinding 时不会导致内存泄露。哦,auto_ptr 可以帮上一些忙,但如果是分配的资源是数组呢?

还有一个麻烦是,你要遵从约定——特别是对于一个程序库作者来说。如果约定出错时抛出异常,那么可以抛;如果约定出错时返回错误码,或者这个库可能被 C 调用,那么抛出异常就可能是灾难。

现在看来,如果想实现更健壮的 C++ 程序,那么异常处理是不可或缺的。但在使用异常处理之前,必须得了解在哪里、怎样抛出和捕获异常,如果是团队合作,可能还需要有简单的操作指导手册,否则使用不当或者过量的异常也可能带来麻烦。

我还在路上!

有关 SVN、Cygwin 和 Notepad++

1. svn 的访问控制

很久以前我就自己配置过 svn 服务器,但总是不能访问成功。到最后还是使用文件系统(即用 file:/// 而不是 svn:// 或其它)访问 svn 仓库,因为自己建立的文件系统不需要认证。

今天我又尝试琢磨了一下我 svn 仓库的设置,才发现之前没配置成功的原因:svn 对用户的权限默认是关闭的。因此当我设置了用户名密码,svn ls 时得到的提示信息仍然是:

svn: Authorization failed

时,我就糊涂了,我的用户名密码没错呀,为啥还是Authorization failed?我还以为是密码设置有问题,没想到除了用户名以外,还得给用户配置访问列表(ACL),否则就什么都访问不了。说简单点儿就是 svn 用户访问控制是一个白名单机制,而我当成了黑名单机制。

知道了错误原因,就很简单了。到与 svnserve.conf 同目录下的 authz 为对应用户添加可以访问的项目就可以了。

2. cygwin 的启动速度

最近发现 cygwin 的启动速度大大变慢,一个终端起来至少要 30 秒。而且不仅仅是启动,所有程序的运行速度都变慢了,比如文件名补全竟然需要好几秒!我忍了很久,就差卸了重装它了,只是想到好不容易配好的各种环境,给忍耐了下来。

今天琢磨了一下 cygwin 的启动过程,发现可以在 bash 命令后加 -x 参数打印所有执行的命令。于是把启动 log 打印出来,查找到引起运行变慢的罪魁祸首:bash_completion。我之前装了一个名叫 bash_completion 的包所谓命令补全的增强包,好家伙,在 /etc/bash_completion.d/ 下面添加了 144 个文件。在启动的时候要一个个 source 这些脚本,怪不得慢呢!

卸载掉这个 bash_completion 包后,cygwin 的运行速度回到了原来的水平,敲命令的时候总算不用憋屈地等补全了。

3. Notepad++ 的中文搜索

使用 2.6.8 版本时,又发现无法搜索中文的 bug。我非常搞不懂 Notepad++ 的作者怎么维护软件质量的,这 bug 在我的印象里就反覆出现两次了。这样的bug都不写一个回归测试用例来检查,实在是有点儿不可思议。无奈之下只好退回到 2.6.7 版本了。

播客和其它

每隔一段时间,我都会到 Google Analytics 里面检查我博客的引入链接,主要关注那些个人网站,经常会发现一些有趣的人和事。今天逛到的博客提到了 Linux 下的 podcast 客户端,我忽然感了兴趣,然后就开始找一些有趣的 podcast 资源。

就客户端来讲,尝试了几个,发现 Windows 下的 podcast 客户端中,iTunes 还是最好的一个。当然,我的标准中有一条“支持代理服务器”,就刷掉了很多软件。而中文的稳定更新的 podcast 更没有多少,现在听的几个主要来自我爱 Podcast阅微堂的两篇文章。

让我比较不习惯的一个,是锵锵三人行的 podcast。这个 podcast 是由毛豆工作室 制作的,他们为 podcast 设置了下载密码。只有捐款了的会员,才能有固定的下载密码;未捐款用户则只能使用10分钟左右变更一次的guest密码下载。更绝的是,guest 密码的获取方式非常奇特,你必须准确点击到在一个 Google 图片广告上迅速移动的链接,才能看到图片形式的密码;稍有不慎,就只是点开了 Google 的广告,而得不到密码。

虽然我认为费力制作并租用服务器发布 podcast,收费提供也无可厚非,但是使用如此之戏弄用户的把戏提供 guest 密码让我无法认同。破解这种把戏其实也很简单,找出图片的链接,然后请求图片时在 header 中加上到原页面的 referer,就可以直接 GET 到图片了。当然,为了方便,可以将提取图片的 php 脚本扔到自己的服务器上,用浏览器刷新就可以直接得到密码了。

关于 podcast,我还有一个想法:有没有人将安装系统或者使用软件的教程做成 podcast?我想这样做应该很有趣,比如我们要安装 Ubuntu,只需要挂着个 mp3,按照里面声音一步一步走:“哦,现在把光驱打开,把光盘放进去,按 F12 进入启动选择界面,……”。

除了捣鼓 podcast 之外,我前几天还把 WordPress 升级到了 2.9.2。之前 2.7.1 用习惯了,尝试升级了几次都出问题,于是就一直停在了 2.7 版本。这次升级主要是考虑到安全问题,毕竟软件的时间越久越容易被人发现漏洞。升级仍然出现了一些小问题,主要的原因是 WP 运行时占用的内存超过了默认的 32M,在 wp-config.php 中加大内存就没事了。

在博客侧栏增加了来自阿里妈妈的广告,原因无它,只是为了尝试一下阿里妈妈的用户体验,钱估计是赚不到的。

上周五睡觉时,小腿脚踝上方不知不觉地被暖手宝烫出了一个滴溜溜圆的蚕豆状水泡。不能穿高帮的鞋子,只好两只脚穿不同的鞋。目前已经到医院上了三次药,在好转中。

宿舍原来空调风机功率太小,一直不暖和,2月下旬回来给敲掉了。期间下了两三场雪,供暖都快结束了,今天才装上新风机。只要开机就一股暖气片漆的味道,于是干脆放那不开它了,冷点儿也比吸化学毒气强。

我的 Facebook 帐号十几天前被关闭了,我发了封信申诉,一直没消息。昨天早上照常地清空了一下垃圾箱,在删除那一瞬间看见了 Facebook 的回信,真郁闷。不过虽然没看到回复,Facebook 是可以登录了,这是好事儿。

又薅移动的羊毛了,充 300 送 140 的公交卡。正好有张非学生卡,毕业了总是要用的,干脆充上得了。上个月是 50M 的流量,结果只用了不到 30M,这个月关了 5块 30M 的套餐,结果发现 20M 貌似又有点儿不够用了。

在 Twitter 上无意中发现一对可爱的恋人,经常连载一些类似博客的有趣的事,于是 fo 了,刚才发现那男孩儿把我 block 了,大概是不想被人关注吧。天晓得我怎么找到的这种 follower 和 following 都是 1 的用户。另外,看别人在 Twitter 上谈情说爱和吵架都是顶好玩的事情!

An IPv6 Enabled NTP Client for Windows in Python

Python NTP library (ntplib) offers a simple interface to query NTP servers from Python. But it does not support IPv6 NTP servers. I wrote a patch for ntplib to support IPv6 connections. You can download the patch file here and the patched library here.

The code bellow is a simple IPv6 enabled NTP client (ntpdate.py) in Python for Windows, using the patched ntplib. It doesn't (and won't) support Linux because the official NTP release offers IPv6 support on that platform.

#!/usr/bin/env python
# ntpdate.py - set the date and time via NTP
# An IPv6 enabled ntp client, for Windows ONLY.

import ntplib, time
from os import system
from sys import argv

def usage():
  print '''Usage: ntpdate.py  [-qh] server
Example:
  ntpdate.py 210.72.145.44      # IPv4
  ntpdate.py ntp6.remco.org     # IPv6
Options:

  -q     Query only - don't set the clock.
  -h     Print this message.

IPv6 NTP Server List:
  ntp6.remco.org               [2001:888:1031::2]
  ntp6.space.net               [2001:608:0:dff::2]
  time.buptnet.edu.cn          [2001:da8:202:10::60]
  time.join.uni-muenster.de    [2001:638:500:717:2e0:4bff:fe04:bc5f]
  ntp.sixxs.net                [2001:1291:2::b]
  ntp.eu.sixxs.net             [2001:808::66]
  ntp.us.sixxs.net             [2001:1291:2::b]
  ntp.rhrk.uni-kl.de           [2001:638:208:9::116]
  ntp.ipv6.uni-leipzig.de      [2001:638:902:1::10]
  ntp.hexago.com               [2001:5c0:0:2::25]
  ntp1.bit.nl                  [2001:7b8:3:2c::123]

Report bugs to http://solrex.org.'''
  sys.exit()

def main():
  ntp_svr = ''
  query = False

  for a in argv[1:]:
    if a == '-q':
      query = True
    elif a == '-h':
      usage()
    else:
      ntp_svr = a
  if ntp_svr == '':
    usage()

  c = ntplib.NTPClient()
  res = c.request(ntp_svr, version=3)
  t_epoch = res.offset + res.delay + time.time()
  t = time.localtime(t_epoch)
  centi_sec = t_epoch%1 * 100
  time_str = time.strftime('%H:%M:%S', t)
  if not query:
    system('time %s.%2.0f' % (time_str, centi_sec))
    date_str = time.strftime('%Y-%m-%d', t)
    system('date %s' % date_str)
  if query:
    print 'server %s, stratum %d, offset %f, delay %f' % (
           ntp_svr, res.stratum, res.offset, res.delay)
  print '%s %s ntpdate.py: time server %s offset %f sec' % (
         time.strftime('%d %b', t), time_str, ntp_svr, res.offset)

if __name__ == '__main__':
  main()

一个 Windows 对时小工具

由于在 CERNET 内,我经常需要用代理上网,没办法直连到 NTP 服务器,因此不能使用 Windows 时间服务对时。偶尔维修电脑或者不小心调整错时间,再加上电脑时钟本身就有一定的漂移,对时就变成了件麻烦的事情。

手动调时也没个参照,误差往往比较大。IPv6 网络上存在一些 NTP 服务器,Linux 下有 ntpdate 是支持 IPv6 NTP 服务器的,但是我搜索了半天,才在一篇文章上看到有人评论说 Windows 下只有一款 NTP 客户端支持 IPv6,还是收费软件——可他也没给出名字。

无奈之下想到 Python 的 httplib 是支持 IPv6 连接的,于是我就仿照 htpdate 写了一个利用 Google 的 IPv6 Web 服务器进行对时的 Python 小工具 htpdate.py。虽然误差比 NTP 大不少,但是还是在可接受范围内(不到 1 秒),而且比较方便,连日期也一块更新了。下面是代码,比较粗糙。

#!/usr/bin/env python
import httplib, time
from os import system

def main():
  conn = httplib.HTTPConnection('google.com')
  time.clock()
  conn.request('HEAD', '')
  t_rtt = time.clock()
  res_time = conn.getresponse().getheader('date')
  t = time.localtime(time.mktime(time.strptime(res_time,
                                 '%a, %d %b %Y %H:%M:%S %Z')) - time.timezone)
  time_str = time.strftime('%H:%M:%S', t)
  local_time = time.asctime()
  t_exe = time.clock()
  centi_sec = (t_exe - t_rtt/2)*100
  if centi_sec > 99:
    centi_sec = 99
  system('time %s.%2.0f' % (time_str, centi_sec))
  date_str = time.strftime('%Y-%m-%d', t)
  system('date %s' % date_str)
  print 'LOCAL  TIME: ' + local_time
  print 'SERVER TIME: ' + time.asctime(t)
  print 'LOCAL  TIME: ' + time.asctime()
  if (t_exe - t_rtt/2) >= 1:
    print 'Round trip time is too long. Time error might be larger than 1 sec.'

if __name__ == '__main__':
  main()

使用 Sikuli 实现同时登录两个 Dropbox 帐户

来自 MIT 的用图片编程的 Sikuli 语言最近着实火了一把,看着对岸的程序员 Vgod 开发出如此酷的软件着实令人羡慕。但除了 Demo 之外,能不能拿 Sikuli 来 engineer a better life 呢?显然是可以的,就如 Vgod 这篇文章所说,Sikuli 有无穷的潜力,那我们就来玩儿一把,展示一下 Sikuli 的一个现实应用。

1. Dropbox

Dropbox 是一个在线文件存储系统,可以用来存储和在不同电脑间共享文件,但是一个 Dropbox 用户只有 2G 的存储空间,当我们文件多的时候,就受到限制了。而一般情况下 Dropbox 只能运行一个例程,使用多个用户貌似不可行。但是到底可能吗?

当然可能,只是我们需要多个 Windows 帐户。也就是说,每个 Windows 帐户可以运行一个 Dropbox,如果你系统里有多个帐户,就可以运行多个 Dropbox。注意,受到安全策略的限制,这些帐户必须设置密码。比如我们新建一个"dropbox"帐户,密码也是"dropbox"。

2. 笨的方法

一般情况下使用其它帐户运行程序的方式为:在程序或者快捷方式上点右键,选择“运行方式”,然后选择“下列用户”,输入你期望的用户和密码(dropbox:dropbox)来执行该程序。

3. 聪明的方法

但是这样做太麻烦了,我们可以用批处理脚本做这件事情:

start D:\Program\Dropbox\Dropbox.exe
runas /user:dropbox D:\Program\Dropbox\Dropbox.exe

但这样还要手工输入密码,有很多种方法可以避免手工输入 runas 密码,但很遗憾它们大多在 Windows XP Home Edition 上不可用。

用 Home Edition 的同志还是得交互式的输入密码。能不能不手工输呢?可以,比如 expect 就是专门处理交互的语言。不过,学起来太麻烦了吧,要不来看看 Sikuli 怎么做?

4. 使用 Sikuli

下面这个图就是完成启动两个 Dropbox 的 Sikuli 程序:

使用 Sikuli 同时启动两个 Dropbox

首先switchApp("cmd")启动 Windows 的命令行,然后wait等待那个提示符出现,然后 type() 键入一行 runas 命令,wait 等待提示输入密码,type 输入密码 dropbox 加回车 \n,bingo,出来一个 dropbox 了,最后再 type 一行启动非 runas 的 dropbox,又出来一个 dropbox。

上述程序运行结果如下图所示:

两个 Dropbox 在运行

好玩吧!Sikuli 程序就是那么简单,我从下载 Sikuli 到完成这个程序大约花了四十分钟的时间,这可比去学 expect 快多了。这下 expact 之类的交互语言在简单的场景下可以无视了。

你可以将 Sikuli 程序导出成一个 .skl 文件,据说可以双击运行,不过我尝试未成功,这是一个遗憾,希望后续版本可以解决这个问题。

5. 注册 Dropbox

您如果对 Dropbox 感兴趣的话,可以点击下面我的两个邀请链接注册,这样咱们的空间都可以增加 250M。本人将非常感谢您的支持。(如果您打算再注册一个的话,最好不要用自己的邀请链接,因为同一台电脑上激活的用户不会奖励空间。)

https://www.dropbox.com/referrals/NTE2NjMyMTU5

升级黑莓 8700 系统到 4.5.0.182

好多事情都是不做时觉得很难,做了才知道,哦,原来这么简单!给黑莓刷系统也是如此。

本来我的 8700 系统是 4.2.x 版本的,有很多主题和软件不能用,我当时怕升级麻烦,也就忍了。但是当我前两天才憧憬过的 UCWEB 黑莓版今天发布时,而我的 4.2 系统无法支持它,只好下狠心升级一把。

之前我曾经看过无数帖子,评论 4.5 的系统如何如何,也看过不少教程,该如何如何升级系统,总之一个感觉,就是非常麻烦。众说纷纭以至于连该用什么固件都不知道。但是经过几次尝试之后,我才发现了升级黑莓系统是怎么回事,根本没有我想象的那么复杂。下面给出我对整个过程的理解。

1. 到哪里下载固件?

要想刷系统,首先得有固件,到哪里下载就成了一个问题。网上乱七八糟的,众说纷纭,但是我认为本应该只有一个答案:黑莓官网。不过到官网下载固件需要国外代理,因为它禁掉了中国 IP,所以不懂翻墙的人就在其它网站找吧。

2. 下载什么样的固件?

在黑莓官网上,黑莓也不像一般的手机网站一样把一堆系统软件列出来。黑莓官网的固件是按照运营商管理的,很遗憾我们找不到中国移动和中国联通。要找支持中文固件,一般来说我们可以找香港的运营商。但是不同运营商提供的固件版本并不一样,香港的运营商固件可能并不新,这时候美国的 AT&T 反而是一个好的选择。如果需要中文支持的话,一般应该选择括号中注释为 EastAsia 和 Chinese 的固件(据我理解 MultiLanguage 并不包含中文支持)。选择版本的原则我觉得应该版本越高越好,但是不排除偏好某个稳定的版本。

3. 中文支持是不是必须的?

我之前以为必须下载的固件支持中文,装上之后才能使用中文。后来发现也不是那么回事,其实你完全可以下载一个高版本的不支持中文的固件装上,然后找一个相近版本的支持中文的固件,把里面中文支持部分的 .cod 文件找出来,然后用 JavaLoader 装到手机里,这个系统就可以支持中文了。简而言之,中文支持仅仅相当于应用软件而已,可以单独装的,只是需要用特别的方法装。

4. 如何安装固件?

这个就不用我说了,网上一堆一堆的教程。简单的流程就是先将固件安装到 Desktop Manager 里(其实是放到某个目录下),DM 识别了,然后装到手机里。我注意到的一点是:安装固件时最好不要联网,不然黑莓的 Desktop Manager 会老在那找软件更新,增加本来就很长的安装时间。

5. 安装固件时需要不需要备份?会不会对数据有影响?

不需要备份,安装时会自动备份和恢复。对黑莓自身应用,比如短信、通讯录等不会有影响,但是对第三方应用的数据会有影响,比如 Gmail、Mobipocket Reader 等。这也是没办法的事,第三方的应用数据本身也备份不出来。但很奇怪的是手动添加的 Service Book 和 TCP 的 APN 也会消失,只能重新修改。

6. 高版本的系统会不会很慢?

我曾经在网上看过一个耸人听闻的说法是 8700 4.5 的系统需要半个多小时才能启动,让我非常吃惊和迟疑,不敢升级系统。实践证明他大概说的是固件安装过程中的第一次启动需要那么长时间,之后的启动时间和 4.2 系统也没什么明显区别。至于内存占用啦、程序运行速度啦、网速啦,在使用中没有明显感觉。

我觉得将系统从 4.2 升级到 4.5 的优势是:可用的应用和主题更多了、系统和字体更漂亮了;劣势可能是占用的存储空间多了点儿、少了个拼音输入法。除此之外没有其它明显区别,我自己认为值得升级。

我喜欢的黑莓应用

上次手机丢了之后,为图便宜,我换了一个黑莓 8700,黑莓大概是我能负担起的最便宜的智能手机系列。虽然和原来的手机相比,8700 不带照相和扩展卡功能,但各种应用让我觉得比传统手机好玩多了。自从开始玩黑莓的这些有趣应用后,我渐渐觉得以后什么手机应用多,才能占到市场先机。以 Google Android 的开放平台以后肯定有不错的表现。

折腾了一段时间后,下面是一些我喜欢的黑莓应用:

1. Opera Mini 浏览器

如果没有网络,智能手机至少会少了一半的乐趣,现在很多网站都支持手机浏览了,包括我的这个博客,所以一个好用的网络浏览器非常重要。其实 Opera Mini 算不上很好用,但至少比黑莓自带浏览器好用多了,主要是在网页格式化方面。我比较看好的浏览器是 UCWEB,因为它支持标签功能,在 GPRS/EDGE 的低速网络下可以后台打开标签以节省时间。UCWEB 黑莓版已经在内测,希望能尽快推出。

2. Google Maps

通过黑莓上的 Google Maps 我才第一次知道原来没有 GPS 也可以定位。Google Maps 使用基站定位的标称误差大约在 600 米左右,实际误差我觉得大约在三四百米内。虽然误差比较大,但是在北京城里晃悠时,这个范围的误差足够能判断行进方向是否正确了,可以少问很多路。另外还有路线查询功能,有点儿烂,但好歹能用。

3. Google Sync

同步联系人和日历的工具,可以将手机联系人与 Gmail 联系人同步,将手机日程表与 Google 日历同步。这个应用实在是太酷了,在同步完联系人到 Gmail 中之后,我再也不用担心手机丢了会失掉很多人的联系方式。编辑自己的日程表也可以在电脑上进行,不用在手机上慢慢地敲字了。而且只要登出 Google 帐号,就可以删除所有联系人,换手机时候很方便。

4. Key Master

我平时不喜欢用鼠标在一堆图标中找应用程序,所以在电脑上我都是用 Launchy 来启动应用程序。Key Master 是在黑莓上自定义快捷键启动应用程序的工具,非常好用,一般情况下我都不需要再进黑莓的 Applications 目录用滚轮来找程序。

5. Mobipocket Reader

这是一个电子书管理和阅读工具,有手机版和电脑版。电脑版和 iTunes 类似,先把电子书导入到电脑版里,然后通过数据线发送到手机上的 Reader。这不是它最酷的地方,它最酷的是可以直接导入 .pdf, .html, .chm, .epub 格式的电子书。如果有某本书的 pdf 版,就不用再费尽心机寻找 txt 版了,直接导入就可以在手机上阅读。Mobipocket Reader 对 pdf 的重新格式化在我看来已经到了值得称赞的地步,太牛了!

6. 凌波微步 SmartDail

这是一款智能拨号软件,由于黑莓的电话簿不支持首字母查询功能,在电话簿中寻找联系人比较麻烦。这款软件可以支持名字首字母查询,定位联系人非常方便。

7. MidpSSH

黑莓上的 ssh 客户端,不支持中文,但是紧急情况下用来进行简单的服务器维护足够了。

8. Gmail 手机客户端

这个不用解释了。

9. 点讯输入法

用这个输入速度比黑莓原生输入法快多了,主要体现在两个方面:选字快和匹配率高。缺点就是切换麻烦,或者在一些应用中只能拷贝粘贴。

10. BerryFetion

这个软件也相当酷,可以在短信上直接选择“使用飞信回复”,可以省不少短信费!

11. Btalk

黑莓上的 Gtalk 客户端。由于官方的 Gtalk 黑莓版不支持个人用户,开源的 Btalk 让这变成了现实。但是实话说,谁用外出时还用手机挂 Gtalk 呀(又没经验值),也就是偶尔用一下而已。

12. AutoLock 和 TinyLock

自动锁屏软件,用处不大。

剩下还有一些应用,BBWeather, CallAssistant, MobCal, Anyview, BBNotePad 之类的,装上几乎没有用过,也就不评论了。

还有一方面的应用我觉得非常遗憾,我一直没有找到很棒的记事本软件。我希望这个记事本软件能支持(以优先级排序):1. 自动保存,比如15秒保存一次;2. 导出到电脑;3. 支持点讯输入法。不知道这样的应用存在不存在?

PS:在应用之外,还有一款软件不得不提,就是 BlackBerry Master Control Program,简直是安装黑莓软件的神器呀,比黑莓原版的 Desktop Manager 要好太多了!

Fix Black Screen After Boot Problem of Ubuntu 9.10 on D630

Platform: Dell Latitude D630, Nvidia NVS 135M, Intel CPU, Ubuntu 9.10

Problem:

1. Boot from livecd, select install. After a glowing ubuntu Symbol, screen shows nothing, even no CLI.

2. After installation with "text mode", boot from HD. After a glowing ubuntu Symbol, screen shows nothing, even no CLI.

Solution:

I am not very sure whether this problem is caused by the NV 185 driver(nvidia-glx-185). Installing or removing this package gave no help. I googled a lot, found many people encountered the same problem. However, no answer could work on my laptop. Then I tried to install NV driver manually...it works! So, here is the fix:

1. When you get the GRUB boot menu screen, press 'e' to edit the fist entry. Add a word 'single' after 'linux /boot/vmlinuz..... quiet splash', then press 'Ctrl+x' to boot. (I cannot enable networking in recovery mode, so I tried with the single mode.)

2. Select the 'netroot' entry. You will get a root command line with network support.

3. Download the latest NV driver for linux (2010-11-3):

# wget http://us.download.nvidia.com/XFree86/Linux-x86/190.42/NVIDIA-Linux-x86-190.42-pkg1.run

[You can visit http://www.nvidia.com/object/unix.html for the latest NV driver.]

4. Install development tools to build NV driver on you os.

# apt-get update
# apt-get install build-essential

5. Install the NV driver:

# chmod u+x NVIDIA-Linux-x86-190.42-pkg1.run
# ./NVIDIA-Linux-x86-190.42-pkg1.run

6. Reboot.

If you are using a livecd, please use the "text mode" to install Ubuntu 9.10. After installation, try the solution above.

Ubuntu 9.10 启动后黑屏的解决方法

平台: Dell Latitude D630, Nvidia NVS 135M, Intel CPU, Ubuntu 9.10

问题描述:

1. 从 livecd 启动后,选择安装,在白色 Ubuntu 图标闪烁结束之后,无任何屏显,连命令行都没有。

2. 用文本模式安装完成后,从硬盘启动,在白色 Ubuntu 图标闪烁结束之后,无任何屏显,连命令行都没有。

解决方法:

我不太清楚是不是 NV 的 185 驱动有问题(nvidia-glx-185),安装或者删除它对状况没有任何帮助。我搜索了一下,发现很多人遇到和我类似的问题,不过没有任何解决方法可以在我的电脑上工作。无奈下我尝试手动安装了一下 NV 的最新驱动——居然解决了!下面是我的解决方法:

1. 当你进入 grub 启动菜单选择屏幕时,在第一条上按 e 进入编辑状态,在 'linux /boot/vmlinuz..... quiet splash' 这一行最后添加一个单词 single,然后按 Ctrl+x 启动。其实 recovery mode 能做类似的事,但是 9.10 的 recovery mode 好像不能启动网络,所以只好自己进入 single 模式了。

2. 启动后选择 'netroot' 选项,进入带网络的 root 命令行。

3. 下载最新的 NV 驱动(2010-11-3):

# wget http://us.download.nvidia.com/XFree86/Linux-x86/190.42/NVIDIA-Linux-x86-190.42-pkg1.run

[你可以先访问 http://www.nvidia.com/object/unix.html 查看 NV 最新驱动的地址。]

4. 安装编译 NV 驱动需要的编译工具:

# apt-get update
# apt-get install build-essential

5. 安装 NV 驱动:

# chmod u+x NVIDIA-Linux-x86-190.42-pkg1.run
# ./NVIDIA-Linux-x86-190.42-pkg1.run

6. 重启

如果您使用 livecd 安装 Ubuntu 9.10 的话,您应该选择 "text mode" 进行安装。成功安装完成后,仍然遇到黑屏问题,请尝试上述方法。

Windows Tips: 修改热键和文件访问权限

我平时习惯使用 Win+E 打开 Windows 的资源管理器,但对资源管理器的左侧栏一直不感冒。用热键打开我的电脑本身就是为了键盘操作方便,但是多了个左侧栏使方向键选择文件夹相当不方便。昨天我总算找到了覆盖 Win+E 热键的方法。

AutoHotKey 是一个编辑和管理 Windows 热键的开源软件,SciTEAutoHotkey 是编辑 AutoHotKey 脚本的开源软件。(也许某些人会惊讶,AutoHotKey 居然不自带脚本编辑器,还要别人帮它写,我想这也许是受到 Unix 哲学的影响:Do one thing and do it well.)

AutoHotKey 脚本的基本语法是很简单的,前面是热键,后面是执行的命令,启动脚本后热键就会起作用了。键盘上每个特殊键对应的符号在热键列表中有列出,像我前面替换热键 Win+E 为打开“我的电脑”且无左侧栏的语句是:

#e::Run ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}

::{20D04FE0-3AEA-1069-A2D8-08002B30309D} 是“我的电脑”的 CLSID(多谢 IronFeet 的提示),如果需要打开非特种文件夹,就不需要这么麻烦了,直接类似于 #e::Run C:WINDOWS 即可。同理,设置用 Win+C 打开控制面板可以写成:

#c::Run ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}::{21EC2020-3AEA-1069-A2DD-08002B30309D}

利用 AutoHotKey 可以做很强大的事情。比如我在 Linux 下使用 Evince 查看 pdf,可以使用 vim 的习惯,jkhl 上下左右移动 pdf 文档,那么我们可以在 Windows 下用 AutoHotKey 来实现对 Adobe Reader 同样的操控,语句如下:

#IfWinActive ahk_class AcrobatSDIWindow
j::Send {Down}
k::Send {Up}
h::Send {Left}
l::Send {Right}
#IfWinActive

这几句话的意思是,如果 AcrobatSDIWindow 这个 ahk_class 窗口在激活状态下的话,那么 jkhl 就被换成键盘上的上下左右键。AutoHotKey 的高级使用还是很麻烦的,它网站上的 Tutorial 是一个不错的入门教程。其实一般我都是用 Launchy 启动程序,对 AutoHotKey 的需求不是那么多,简单的几个组合键就够了。

我昨天才发现 Windows XP 家庭版和专业版的一个大区别:家庭版没有“组策略”编辑器。我电脑的“所有程序”->"启动"目录不知道被什么安全软件设置成只读了,我以为 ATTRIB 命令是修改文件权限的,却发现无法修改“启动”文件夹的权限。后来找到 CACLS 命令,可以用来指定特定用户对文件的访问权限,才把"启动"文件夹访问权限修改成了完全控制:

cacls 启动 /G Solrex:F

设置可写以后就可以把 AutoHotKey 脚本的快捷方式拖到“启动”文件夹,随系统一起启动了。

几种不得已时的上网办法

由于小弟最近上网受到诸多限制,在校时帐号爆掉,回家又没有网络可上,所以尝试了各种上网方法,也许对大家有用呢,所以下面分享及记录一下:

1. 手机作为 modem,使用 GPRS 拨号上网

这个一般受到手机版本影响,三星这方面做得非常不错。将手机使用数据线连接到电脑,打开 Samsung PC studio,选择 Network Wizard(网络向导?),创建连接,连接名称随便写,比如“中国移动”,下一步调制解调器选择“Samsun Mobile USB Modem”,下一步国家选择中国,网络供应商选择“China Mobile(Beijing)”(其实选择哪个好像无所谓),用户ID选择“cmnet”,密码也是“cmnet”,创建完成后就可以拨号了。因网络状况或者 GPRS 版本不同,连接速度可能是 153.5 kbps,或者 460 kbps。

GPRS 资费是非常贵的,不在不得已或者包月流量用不完时,最好不要用 GPRS 上网;即使用 GPRS 拨号上网时,也要切记关掉所有自动联网的软件,比如禁用杀毒软件和操作系统的自动更新,禁用浏览器插件等等,这样才能将有限的网速使用在优先的程序上。

2. 使用 201 卡进行古老的 modem 拨号上网

使用 201 卡拨号上网可能会受到运营商的限制。经过我多次咨询 10010 和动手尝试,北京网通(联通)的“阳光心语普通快捷卡”拨号上网方式是这样的:首先将电话线插到笔记本的 modem 口(一般台式机已经没有这个口了)。创建一个新的连接,“连接到 Internet”->“手动设置我的连接”->“用拨号调制解调器连接”->选择笔记本电脑自带的调制解调器(我从来没想过我会有使用它的一天...)->ISP 名称,随便填,比如“201”->电话号码:“2012,语言种类,卡号#,密码#,16911#”,语言种类为打201电话时选择的数字->用户名:169,密码:169。设置完后就可以拨号了,刚开始会听到愉悦的 201 拨号机器回复,最后就要忍受一会儿嘈杂的拨号音了。201 拨号上网的速度大概为 46.6 kpbs...

使用 16911 拨号上网资费大概是 0.07 元一分钟,所以也是相当贵的,只是在 201 卡快过期或者不得已时才能为之。

3. 借用 IPv6 上的 Google App Engine 上网

这个大概只适用于高校使用教育网的学生了。Google,作为一间牛逼闪闪的公司,当其他互联网公司还在 IPv4 上晃悠时,Google 已经将其几乎所有服务部署在 IPv6 互联网上了。作为 IPv6 网络用户,您只需要将所有 Google 相关的域名在 hosts 文件(C:\WINDOWS\system32\drivers\etc, /etc/hosts)中映射到 2001:4860:c004::68 这个 IPv6 地址即可,格式例如:

2001:4860:c004::68 www.google.com mail.google.com clients1.google.com talk.google.com ssl.goo飞gle-analytics.com

就可以使用浏览器访问 IPv6 上的 Google 服务了。目前中国的 IPv6 网络上是没有审查制度的,所以在 Google 搜索时,您可以放心地搜索任意关键词,以及查看网页快照了。

但是目前只解决了访问 Google 的问题,如何访问其它网站呢?就不得不提到我前段时间发布的 Tohr 项目了。Tohr router 可以运行在 Google App Engine 上,所以您只需要将您的 Google App Engine 的域名,比如 example.appspot.com 照上面格式添加到 hosts 文件中,就可以利用 Tohr 结合 GAE 作为一个 IPv4 over IPv6 通道来上网了。当然,GAE 有很多限制,所以有些网站是铁定上不了的。为了实现浏览器自动选择直连 IPv6 的 Google 服务和使用 Tohr 代理访问其他网站,强烈推荐您阅读一下我的这篇博客文章《浏览器自动选择 Proxy 配置案例》。

使用这种方法起码在访问只需要阅读的网站还是 OK 的,Twitter 也可以直接登陆。部分在登录时检查 HTTP 请求 Referer 的网站是无法登录的,比如豆瓣、开心网、Facebook 等,这些时候不要责怪我,因为这是 GAE 的限制,不许用户自定义 Referer;或者 gmail, google reader 等,这也可能是 GAE 限制访问的网站。

但比较遗憾的是,除了第3种方法在 Linux 一样好用以外,前两种方法我都不知道如何在 Linux 上使用。

SVN 技巧:GUI 版本比较和可执行属性

我曾经在《使用 kdiff3 进行 svn 版本比较》中介绍了为什么以及如何使用 kdiff3 或者 meld 等 GUI 比较工具进行 SVN 版本比较。但这样做有个小问题,就是如果设置了 GUI 工具作为比较工具,那么就没办法输出 diff 文件,而且每次都要关掉窗口才会出现下一个文件,就无法比较多个文件了。所以我觉得下面这种做法会更好一些:

$ more svndiff
#!/bin/bash
sed -i -e 's/^# diff-cmd.*$/diff-cmd=meld/' ~/.subversion/config
svn diff
sed -i -e 's/^diff-cmd.*$/# diff-cmd = meld/' ~/.subversion/config

其实就是用一个脚本 svndiff 来做 GUI 比较的工作。svndiff 执行时首先将 svn 配置文件中的比较工具改为 meld,然后进行比较,比较完后再将修改注释掉,这样就不会影响正常 svn diff 的功能。这样一来,svndiff 是 GUI diff,svn diff 就是命令行 diff。

设置文件可执行属性对 Windows 用户来说可能没什么用,可是对 Linux 用户来说用处就大了。没人希望每次一 update,就要重新对需要执行的脚本 chmod 一下。svn 修改文件可执行属性的命令太长了,我老记不住,所以放在这里做个笔记吧:

svn propset svn:executable ON filename

用 Wireshark 分析 RTP 流

Wireshark 是一个强大的抓包及网络分析软件,可以用来嗅探和分析多种网络协议的数据包和流,RTP 和 RTCP 也是其中的两种。

对 RTP 流的分析过程,在 Wireshark 的 Wiki 上讲得很清楚,下面我只是记录一下我在使用过程中的一些经验:

1. 要想分析 RTP 流,首先要把抓到的 UDP 包用 RTP 协议而不是默认的 UDP 协议 decode; Wireshark 默认只对选中的流(由端口区分)进行 decode,所以对 audio 和 video 流要分别 decode。

2. 直接从菜单中选择 RTP 的 Stream Analysis... 才是对双向的流进行分析,从 Show All Streams 中再分析只是单向的 RTP 流。

3. 不要过度相信 Wireshark 的能力,尤其是在无线网络或者网卡驱动不是很合适的情况下,Wireshark 也会有丢包,所以说 Wireshark 对 RTP 流的分析也是“仅供参考”——除非经过严格测试 Wireshark 不会错过任何包。

4. 这个页面上提到的 Sun 的 JMF JMstudio 的 Linux 版本状况很糟糕。首先其安装文件中使用的 tail 参数和 bash 中的 tail 参数不一样,导致执行安装文件不仅不会安装,反而会清除安装文件的内容。由于其将安装脚本和二进制文件写入到同一个文件中,所以最好是在外部手工用 tail 提取二进制文件的内容;其次无论如何配置,该程序运行时会去监听 IPv6 地址的端口而不是 v4 的端口——我一直想不通是什么原因,所以该程序可以说是基本不可用。

5. rtptools 是个好东西。我们可以先用 Wireshark 录制一段 RTP 流,保存成 rtpdump 格式,就可以用 rtpplay 不断地重放它,用来测试网络状况很方便。原本应该用 JMStudio 收听的,既然它不可用,只有用 rtpdump 在另一端收听了。

回复选登:

james:

博主请问有没有办法能够使wireshark能够在ubuntu下捕捉到所有的rtp包?

由于要做老板的项目,所以需要测量一系列delay,jitter等等数据。所以我用vlc做server向外multicast一个rtp stream (拓扑上用的全部是有线)。若传输的stream质量不高(比如dvdrip,大概速度也就1.5mbps),wireshark能够完全捕获所有的包。但是若是使用较高质量的stream(比如1080p,1080i的,大概在20mbps)就会出现wireshark丢包的情况。

所以我想知道wireshark丢包的原因是不是来自于cpu利用率太高?有没有办法在仍然使用wireshark的情况下捕捉到所有的包?如果有其他抓包、分析软件,博主可否给我推荐一下?

非常感谢!

Solrex Yang:

@james
非常抱歉,我所了解的知识无法解决您遇到的问题。如果您找到了解决方法,非常欢迎您回来再次留下您的评论。

james:

博主你好,这个问题已经解决了。

由于wireshark实时捕捉packet会非常消耗cpu资源,所以我使用tcpdump来抓包,并且加大了libpcap的缓冲区,问题就解决了。

当然,若是要在Gbps的网络环境中抓包,linux下的tcpdump的精度完全不够(尤其在包长度小的时候很明显),这个就是跟libpcap函数相关的。有个意大利大牛写了一个PF_RING的类似“zero copy”的应用,可以在很大程度上解决这个问题,如果大家有兴趣可以尝试。google上有相关介绍。

qRFCview Proxy Patch

This patch enables qRFCview to load proxy settings from environment variables such as "http_proxy" and "socks_proxy". Yes, popping up a dialog to set these things is fancier, but that means more coding work. I am pretty satisfied with this solution.

You can download the modified source code tarball from http://share.solrex.org/ibuild/qrfcview-0.62-solrex2.tar.gz . Binary packets for special Linux distributions can be found at http://share.solrex.org/ibuild/ too.

diff -aurN qrfcview-0.62/src/mainwindow.cpp qrfcview-0.62-solrex/src/mainwindow.cpp
--- qrfcview-0.62/src/mainwindow.cpp    2006-01-13 17:56:45.000000000 +0800
+++ qrfcview-0.62-solrex/src/mainwindow.cpp    2009-07-14 16:03:56.000000000 +0800
@@ -122,8 +122,10 @@
{
   // Load a RFC number
   bool bOK;
+  /* NOTE 20090714/Solrex  <http://solrex.org>:
+     Enlarge RFC number limit to 10000. */
   int iRFCNum = QInputDialog::getInteger(this, tr("Please enter a RFC number"),
-                                             tr("RFC#:"), 0, 1, 5000, 1, &bOK);
+                                             tr("RFC#:"), 0, 1, 10000, 1, &bOK);
   if (bOK)
     RFCLoad( iRFCNum );
}
diff -aurN qrfcview-0.62/src/rfcloader.cpp qrfcview-0.62-solrex/src/rfcloader.cpp
--- qrfcview-0.62/src/rfcloader.cpp    2006-01-13 17:56:45.000000000 +0800
+++ qrfcview-0.62-solrex/src/rfcloader.cpp    2009-07-14 15:58:50.000000000 +0800
@@ -25,11 +25,41 @@
#include <QMessageBox>
#include <QtDebug>
#include <QDir>
+#include <QNetworkProxy>

QRFCLoader::QRFCLoader(QObject *parent)
  : QObject(parent)
{
   m_qHttp=new QHttp(this);
+  /* NOTE 20090714/Solrex <http://solrex.org>:
+     Detect proxy settings via system environment variable
+     ``http_proxy'' and ``socks_proxy''. */
+  char *p;
+  QNetworkProxy qNetworkProxy(QNetworkProxy::NoProxy);
+  if ((p = getenv("socks_proxy")) != NULL) {
+    qNetworkProxy.setType(QNetworkProxy::Socks5Proxy);
+  } else if ((p = getenv("http_proxy")) != NULL) {
+    qNetworkProxy.setType(QNetworkProxy::HttpProxy);
+  }
+  if (p != NULL) {
+    QString proxyStr = p;
+    proxyStr = proxyStr.trimmed();
+    proxyStr.remove("http://");
+    QStringList list = proxyStr.split("@");
+    QStringList list1 = list[0].split(":");
+    if (list.count() > 2) {
+      qNetworkProxy.setType(QNetworkProxy::NoProxy);
+      qDebug() << "Unresolvable proxy setting:" << list;
+    } else if ( list.count() == 2) {
+      qNetworkProxy.setUser(list1[0]);
+      qNetworkProxy.setPassword(list1[1]);
+      list1 = list[1].split(":");
+    }
+    qNetworkProxy.setHostName(list1[0]);
+    qNetworkProxy.setPort(list1[1].toInt());
+  }
+  m_qHttp->setProxy(qNetworkProxy);
+  qDebug() << "Loaded proxy:" << p;
   connect(m_qHttp, SIGNAL( requestStarted(int) ), this, SLOT( startDownload(int) ) );
   connect(m_qHttp, SIGNAL( requestFinished(int, bool) ), this, SLOT( fileDownload(int, bool) ) );
   connect(m_qHttp, SIGNAL( responseHeaderReceived(QHttpResponseHeader) ), this, SLOT( receivedHeader(QHttpResponseHeader) ) );

RFC number limit issue was discussed at deb-packages-of-qrfcview-and-jabref.html .

在 Ubuntu 9.04 上安装 Kscope

Kscope 是我很喜欢的 Linux 平台上的代码查看工具,因为我不会用 Emacs,vim + ctags 又用得不熟,看看小程序还可以,看大项目就傻眼了。以前也尝试过 Source-Navigator(这个项目N年没更新,06年时候我装都装不上,08年底居然又复活了,有空了再去试试)、Eclipse、Kdevelop、CodeBlocks,总之都没有 Kscope 用着最舒服。Kscope 让我欣赏的特点主要有:

1. 它号称是代码编辑环境(source-editing environment),而不是IDE。我不用在建立 Kscope 项目时烦心地去选择项目类型、编译器、编译选项等等。编译我有 Makefile,我就是找个工具看看代码,用得着那么麻烦吗。 建立 Kscope 项目时只需要干两件事:选择项目名、项目保存地址和添加源文件。

2. 它不会在源文件目录下建立一堆乱七八糟的文件,影响市容。我记得 Eclipse、CodeBlocks 等都会把项目信息保存在源文件目录下,而 Kscope 的项目保存位置可以自己选,比如我一般都保存在 workspace/kscope 目录下面,这样对要查看的源文件目录没有任何影响。因此 Kscope 的项目和源文件基本没关系,我可以添加任何位置的源文件到某个项目中去。

3. 它不会去读非指定类型的文件。这是针对 Eclipse 来说的,每次在 Eclipse 项目中搜索时,一堆 .svn 目录中文件的结果让我感觉非常闹心,两年没用不知道现在的 Eclipse 是不是更智能点儿了,但是 Eclipse 改不了的毛病就是慢和吃内存。

4. 它支持代码查看的基本功能。其实我最常用的也就那么几个功能:语法高亮、同时打开多文件、整个项目中搜索字符串、查找函数定义位置和引用、项目文件列表+搜索。在这些条上据说 Windows 下的 SourceInsight 做得更好,但我没用过没有发言权。

简而言之,Kscope 与其它工具比就是快、简单、省心。但是时代在变革呀,转眼到了 KDE4 的时代,而 Kscope 仍然停留在 KDE3.5 上。现在的 Ubuntu 9.04 的依赖关系里,居然已经撤掉了 Kscope,在 9.04 上 sudo apt-get install kscope,会得到这样的消息:E: Couldn't find package kscope,真是让人丧气。

其实 Kscope 之所以不能安装,主要原因是它依赖于 Kate 的两个库:libkateinterfaces.so.0 和 libkateinterfaces.so.0,只需要从 KDE3.5 的 Kate 中提取出来这两个库安装到系统中后,Kscope 就可以正常运行了。Ubuntu 9.04 的依赖关系中虽然找不到 Kscope,但是 Ubuntu 的软件仓库中还有 Kscope 的包,我们可以手动下载安装。下面这个脚本的功能就是自动安装 kscope 到 Ubuntu 9.04,稍微修改一下也可以用于在其它 KDE4 桌面系统中安装 Kscope,或者解决 Kscope 无法运行的问题。您也可以从这里下载到该脚本:

#!/bin/bash
# This script helps you install Kscope on Ubuntu 9.04.
# You can also use it to fix "Kscope doesn't run in KDE4" bug.

echo "Determining machine hardware name... "
MACHINE=`uname -m`
case "$MACHINE" in
  i386 | i586 | i686)
    ARCH="i386"
    ;;
  x86_64)
    ARCH="amd64"
    ;;
  *)
    ARCH="i386"
    ;;
esac

# If Kscope is not installed, install it.
which kscope &> /dev/null
if [ $? -ne 0 ]; then
  echo "Installing kscope..."
  sudo apt-get install kscope || \
  wget http://archive.ubuntu.com/ubuntu/pool/universe/k/kscope/kscope_1.6.0-1_${ARCH}.deb && \
  sudo dpkg -i kscope_*.deb || \
  sudo apt-get -fy install || \
  echo "Oops, some error happens..."
fi

kscope -v &> /dev/null
if [ $? -eq 0 ]; then
  echo "Kscope works fine."
  exit
fi

echo "Downloading KDE3 libraries needed by kscope..."
wget http://ftp.debian.org/debian/pool/main/k/kdebase/kate_3.5.9.dfsg.1-6_${ARCH}.deb
dpkg -x kate_3*.deb kate

echo "Installing KDE3 libraries..."
sudo cp kate/usr/lib/libkateinterfaces.so.0.0.0 /usr/local/lib/
sudo cp kate/usr/lib/libkateutils.so.0.0.0 /usr/local/lib
sudo ln -s /usr/local/lib/libkateinterfaces.so.0.0.0 /usr/local/lib/libkateinterfaces.so.0
sudo ln -s /usr/local/lib/libkateutils.so.0.0.0 /usr/local/lib/libkateutils.so.0
sudo ldconfig

echo "Finished."

使用 kdiff3 进行 svn 版本比较

svn diff 命令的效果总的来说还是不错的。因为它是基于行的比较,在比较格式规范的程序代码文件时候也足够了,尤其是每行不超过 termial 宽度的时候。但是在比较那些单行长度比较长的文件时,比如 HTML, TEX 等,仅仅修改一个字母也会引起两行不同,用 svn diff 查看被修改的地方时就比较痛苦了。

Linux 下有一些比较好的比较程序,比如 kdiff3, gdiff, vimdiff 等,kdiff3 可以用不同颜色显示两个文档中不同的行、字符,算是比较理想的比较程序。我们可以拿它来替换掉 svn diff 默认的比较程序。

很显然这种需求别人也会有,所以早就有高手解决了这样的问题,您可以从这里下载一个 bash 脚本,将其重命名为 svndiffwrapper,加上可执行权限放到一个可执行路径(比如 /usr/bin/)下。然后修改您的 ~/.subversion/config 文件,找到 diff-cmd,修改为如下所示:

### Set diff-cmd to the absolute path of your 'diff' program.
###   This will override the compile-time default, which is to use
###   Subversion's internal diffimplementation.
diff-cmd = svndiffwrapper
### Set diff3-cmd to the absolute path of your 'diff3' program.
###   This will override the compile-time default, which is to use
###   Subversion's internal diff3 implementation.
diff3-cmd = svndiffwrapper

这样,当您再执行 svn diff 的时候,svn 会默认调用 kdiff3 进行文件比较。由于 kdiff3 是 GUI 程序,所以文件比较将会是一个一个进行的,关掉第一个文件比较的 kdiff3 窗口,才会显示第二个文件的比较窗口。

网友 sleetdrop 评论指出,如果使用基于 Python 的 Meld 作为 GUI 比较工具,那么不需要任何 wrapper,只要修改上述配置为:

diff-cmd = meld

即可。不可否认,这比 kdiff3 简便了不少,而且 meld 还支持在比较时编辑,这也是一个很大的优点。