当前位置

技术

技术

使用 httplib 而不是 urllib/urllib2

决定写一个 python 脚本来定时检查用户登录是否好用,本打算使用以前用过的 urllib2 模块的——qyt同志和我曾合力写了一个脚本从网站上爬数据,追踪我妈购买的三支股票的情况,结果发现并不那么合适。因为挂在 passport.sohu.com 这个域名下的机器有多台,urllib2 无法分布通过不同的内部 IP 进行连接。

在 CHM 里面搜索了一番,找到了 httplib。首先用 HTTPSConnection(host) 指定连接的目标,然后就可以发送 request 了;另外它也支持 https。

另外要注意的是 httplib 缺省是阻塞无超时机制的 socket 连接。使用之前需要

  1. import socket
  2. socket.setdefaulttimeout(5.0)
Topic: 

FireBug 1.0 !

这个月三个重量级的产品发布了新的里程碑:jQuery 1.1,prototype 1.5,然后就是 FireBug 1.0

其实我也就是最近才偶尔用用 FireBug,不过还是觉得这玩艺深深改变了以往调试 JS 程序的方式。Internet Explorer Developer Toolbar 好不容易赶上了 DOM Inspector + Web Developer 的功能,但又远远被 FireBug 落在了身后。

如果有工夫的话,倒是想着利用 python 给 IE 做一个开发用的插件,实现 HTTP Watch 的功能

Topic: 

Apache2 Module 开发后记

没有接触 Apache Module 开发的人可能觉得这是一个很深奥的事情,其实对于有一定经验的人来说还是挺简单的。当然最好是有这么一个环境,一些"SMTH系"的人的 blog 时常会提到什么什么时候又写了一个 Apache Module,语气犹如吃饭睡觉一样稀松平常;深受清华影响的 SOHU 也是如此,动辄就会有个人跳出来和你讨论某样业务如果用 Apache Module 来实现会如何如何,久而久之,就会在思维深处认为写 Apache Module 简直是天经地义。

1. 最通常的用法就是 ap_hook_handler. 这里是 http request 处理的最后时期。而且注册的所有的 handler 都会执行一遍。我做的模块的最核心的流程就是在某些条件下增加一个 HTTP Header 交给最终的内容处理引擎(比如JSP/PHP之类);以及设置一个 Response HTTP Header 项,当 Apache 开始向浏览器返回 Response 的时候,会把我这里添加的项目也输出出去。

2. ap_hook_handler 会应用于所有的请求,有些时候会显得效率有些低——比如对静态文件就没有必要执行额外的处理,这时候用 input_filter 可能会比较好。通过 AddInputFilter 可以设定对某些 Directory/Location 才执行对应的 filter 操作。不过据说 filter 应用也有一些效率问题,需要做详细的 benchmark 才能有结论。

input_filter 的另一个用途就是保持长连接,比如 webim 就可以通过这个方式来实现 Server 端的业务。

3. post_config 阶段可以用来检查运行模块所需要的参数是否都在 httpd.conf 里面被正确配置了。不知道 Apache 的人出于什么样阴暗的心理,post_config 会被执行两次!?这里有人提出了解决方案,如何确保自己的代码只运行一次,而不至于在 error_log 里面留下连续两行同样的LOG如同可笑的弱智bug。

由于我写的这个模块将会被部署到很多台很多台服务器上,万一哪天需要更换模块就需要找出所有部署的系统进行更新。于是每次 Apache 启动后会向一台中央服务器发送一条记录,通知该服务器维护人员的联系方式。这个流程也放在 post_config 阶段,此时 Apache 还没有 spawn 子进程,如果连接并发送记录花很长时间的话会影响 Apache 的正常服务。通常的思维是发 UDP 包出来,但这样的话需要额外写一个 UDP Server 接受它们,于是我在模块里面无耻的 fork 出一个子进程,利用 APR 提供的 socket 函数,大概 10 几行代码就搞定一次 HTTP 请求,然后马上 exit

Topic: 

openssl speed

使用 openssl speed [value] 可以测试某项算法的执行速度。

可以直接执行 openssl speed rsa,让他依次去计算 512bit、1024bit、2048bit、4096bit 的效率;也可以单独执行 openssl speed rsa512 来算。

在 PIII 700 上的结果为

                  sign    verify    sign/s verify/s
rsa  512 bits   0.0021s   0.0002s    475.4   5199.0
rsa 1024 bits   0.0102s   0.0005s     97.7   1883.4
rsa 2048 bits   0.0592s   0.0017s     16.9    582.2
rsa 4096 bits   0.3912s   0.0055s      2.6    181.9

speed 参数还支持 -multi n 参数来进行并发操作。在 PIII 700 双CPU 情况下并不是成倍增长,很奇怪。不过可能因为那台机器当时还有其他负载的缘故。

按照《应用密码学》里的建议(Applied Cryptography),2007 年企业应用应该考虑 1536bit,但 openssl speed 不支持1536bit的benchmark,于是自己写了一个程序来计算效率。

  1. /*
  2.  * openssl genrsa -out rsa1536.key 1536
  3.  * openssl rsa -pubout < rsa1536.key > rsa1536.pub
  4.  * gcc -o benchmark benchmark.c -lcrypto
  5.  *
  6.  */
  7. #include <unistd.h>
  8. #include <signal.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <openssl/rsa.h>
  12. #include <openssl/pem.h>
  13.  
  14. int global_flag = 0;
  15. void signal_alrm(int sig)
  16. {
  17.     global_flag = 1;
  18. }
  19.  
  20. int main(int argc, char *argv[])
  21. {
  22.     char *buf;
  23.     int size, ret;
  24.     FILE *pubfp;
  25.     FILE *prifp;
  26.     RSA *pub;
  27.     RSA *pri;
  28.     int i;
  29.  
  30.     OpenSSL_add_all_algorithms();
  31.     ERR_load_crypto_strings();
  32.  
  33.     pubfp = fopen("rsa1536.pub", "r");
  34.     prifp = fopen("rsa1536.key", "r");
  35.     pub = (RSA *)PEM_read_RSA_PUBKEY(pubfp, NULL, NULL, NULL);
  36.     pri = (RSA *)PEM_read_RSAPrivateKey(prifp, NULL, NULL, NULL);
  37.     fclose(pubfp);
  38.     fclose(prifp);
  39.  
  40.     if (pri == NULL) {
  41.         printf("PEM_read_RSAPrivateKey error\n");
  42.         ERR_print_errors_fp(stderr);
  43.         return 1;
  44.     } else if (pub == NULL) {
  45.         printf("PEM_read_RSA_PUBKEY error\n");
  46.         ERR_print_errors_fp(stderr);
  47.         RSA_free(pub);
  48.         return 1;
  49.     }
  50.  
  51.     size = RSA_size(pri);
  52.     buf = (char *)malloc(size);
  53.  
  54.     signal(SIGALRM, signal_alrm);
  55.     alarm(10);
  56.     i = global_flag = 0;
  57.     while (1) {
  58.         if (0 == RSA_sign(NID_md5, "0123456789abcdef", 16, buf, &ret, pri)) {
  59.             printf("RSA_sign error\n");
  60.             ERR_print_errors_fp(stderr);
  61.             free(buf); RSA_free(pub); RSA_free(pri);
  62.             return 1;
  63.         }
  64.         i++;
  65.         if (global_flag) break;
  66.     }
  67.     printf("RSA_sign: %d\n", i);
  68.  
  69.     i = global_flag = 0;
  70.     alarm(10);
  71.     while (1) {
  72.         if (0 == RSA_verify(NID_md5, "0123456789abcdef", 16, buf, ret, pub)) {
  73.             printf("RSA_verify error\n");
  74.             ERR_print_errors_fp(stderr);
  75.             free(buf); RSA_free(pub); RSA_free(pri);
  76.             return 1;
  77.         }
  78.         i++;
  79.         if (global_flag) break;
  80.     }
  81.     printf("RSA_verify: %d\n", i);
  82.  
  83.     free(buf); RSA_free(pub); RSA_free(pri);
  84.     return 0;
  85. }

10秒种内 sign/verify 一个长度为 16 位的字符串结果如下:
PIII 700 330/8680
XEON 2.4G 666/17034
XEON 3.0G 799/22633
XEON 5130/2.0G 1053/29154
感觉这样的效率还是不错的,需要在实际系统中进一步小心的验证。

还有就是 openssl 编译优化的问题。为了测试 ECC 的支持,我自己编译了 openssl-0.9.8。结果发现在计算 rsa512 的时候,我编译的 openssl(采取缺省configure) 比系统缺省的 openssl 慢了 10% (470 vs 420)。改了改config,可以提升到 450 左右,后来就没有再仔细琢磨下去。

最后用 openssl 0.9.8d 测试了一下 ECC 的签名校验效率(ECDSA),执行 openssl speed ecdsa (PIII 700)

                              sign    verify    sign/s verify/s
 160 bit ecdsa (secp160r1)  0.0013s   0.0061s    786.1    162.9
 192 bit ecdsa (nistp192)   0.0013s   0.0062s    774.7    160.4
 224 bit ecdsa (nistp224)   0.0016s   0.0079s    616.5    126.4
 256 bit ecdsa (nistp256)   0.0020s   0.0101s    503.8     99.0
 384 bit ecdsa (nistp384)   0.0046s   0.0249s    218.5     40.1
 521 bit ecdsa (nistp521)   0.0097s   0.0519s    103.0     19.3
 163 bit ecdsa (nistk163)   0.0046s   0.0125s    219.8     80.3
 233 bit ecdsa (nistk233)   0.0090s   0.0240s    110.7     41.6
 283 bit ecdsa (nistk283)   0.0140s   0.0447s     71.5     22.4
 409 bit ecdsa (nistk409)   0.0315s   0.1063s     31.7      9.4
 571 bit ecdsa (nistk571)   0.0705s   0.2507s     14.2      4.0
 163 bit ecdsa (nistb163)   0.0046s   0.0133s    218.8     74.9
 233 bit ecdsa (nistb233)   0.0091s   0.0268s    110.3     37.3
 283 bit ecdsa (nistb283)   0.0141s   0.0506s     71.2     19.8
 409 bit ecdsa (nistb409)   0.0316s   0.1224s     31.7      8.2
 571 bit ecdsa (nistb571)   0.0704s   0.2877s     14.2      3.5

签名速度还可以,就是校验速度慢死了..

Topic: 

做一个半瓶子 Javascript 程序员

最近项目需要一部分 javascript 代码做 DOM 操作,并且最终是要提供给其他项目调用的。组内的其它同事对 JS 不算精通,虽然 Web 前端开发咱不专业,但好歹有幸和 Lewisrealazy 两位高人同事过,这就叫没吃过猪肉也看过猪跑,于是承担起代码初始编写的任务。

过程很简单:首先是根据需求写了大约 1100 行可以工作的代码,交付给第一个用户 todd,然后俺按照他的建议花了大约1天半的时间把代码改写了一遍,剩下最后的逻辑和界面剥离的任务交给别的同事完成。

以前也用过 javascript,这次才真正以开发产品的目的来写代码。(伪)静态类、函数式编程、闭包这些概念首次接触到,感觉 Javascript 是一门很严肃的程序设计语言,要想掌握或者说精通绝对是一个挑战。具体到 Javascript 在浏览器环境(DOM/HTML)的运行就更需要经验了,好比把 Linux 程序移植到 Solaris 和 AIX,总会在一些细微的地方有什么东西会跳出来捣乱。

假设你已经很熟悉一门开发语言了,由于某些原因需要做一点儿 Javascript/AJAX 开发,那怎么开始呢?

1. 从根本上要重视 Javascript 语言。相比较服务器端主流的 C/C++/Java/PHP 而言,Javascript 属于动态语言(在对 Python/Javascript 有了一些初步了解后,我发现严格上来说 PHP 都不能算动态语言),我认为只有掌握了语言的精髓才能写出好的代码。

2. 需要一个好的调试环境。至少现在为止,Firefox + FireBug 的组合应该是无人可敌的吧。

3. 参考手册。MSDN 和 MDC 上都有很好的在线文档。我个人偏好 MDC,包括 Gecko DOM ReferenceCore JavaScript 1.5 GuideCore JavaScript 1.5 Reference。微软还有一个中文的离线文档 jscript5.chm,似乎是随着 Office 2000 一起安装的,网上很多地方提供下载。

4. 学习别人的代码。prototype 是一个很好的起点。

今天刚刚发现一个更简单的代码集合,里面包括"$ function, getElementsByClassName, event handling, the JS 1.6 array methods, and the DOMContentLoaded event",如果 prototype 看的头大,可以先把这个看明白再说。

除了 prototype 外,JQuery 偏重于 DOM/CSS 特效,被视为 prototype 有力的竞争对手。

5. 补充读物。推荐 deanppk 的 blog。

成为一个 JS 半瓶子程序员并不是太难达到的目标。:)

Topic: 

非常时期下载 sf 软件的方法

已经 2 天了,连接国外死慢死慢,估计这样的日子还要持续一段时间。今天发现了一个速度还不错的 sourceforge 的 mirror,这里推荐一下。

首先要知道项目名,比如 abc123,那么它的 mirror 地址为
http://ftp3.ie.freebsd.org/pub/sourceforge/a/ab/abc123/?C=M;O=D

后面的 C=M;O=D 表示文件列表的顺序为日期最新的排在前面,加快查询速度,呵呵。

比如,FileZilla 就可以从这个地址找到
http://ftp3.ie.freebsd.org/pub/sourceforge/f/fi/filezilla/?C=M;O=D

Topic: 

最近的日子

软件工程里有一个很有趣的“定理”:一个项目的花了 90% 的工期完成了前 90%,但剩下的 10% 要花同样的 90% 的时间才能完成。目前我手头的这个项目似乎就处在这个完成度 90% 的状态下,似乎已经没有什么事情可做了,但离完工好像还是遥遥无期。

在搜狐接触的人多了,总会碰到那么一两个不大合拍的人,其中一个说话的态度好像我欠他钱,另外一个大部分时候还算和善,不过偶尔会发发飙。回想起来其实都是跳槽带来的挑战,以前在亿邮的时候别人和我说话几乎都是恭恭敬敬,现在得时时提醒自己,“心态要端正...冷静,一定要冷静...冲动是魔鬼...”

或者终极心理暗示大法:这也会过去

总之突然圣诞节那天快下班时觉得状态非常不好,或许是周日在 SOGO 血拼满三百返三百太疲倦的缘故,遂等公共汽车的时候去麦当劳买了杯热巧克力喝下。26 日一个朋友在 MSN 上祝我 Merry Xmas,一下子又充满了干劲。在这里向所有看我 blog 的朋友们说,Merry Xmas!Happy New Year!我永远爱你们;虽然从来不群发短信,但我永远是一个 rapport 的家伙,这点是错不了的。

明后天计划做做公钥算法加密解密的benchmark,刚刚发现除了 RSA/DSA 外,ECC(椭圆曲线密码)也是属于公密钥体系(非对称加密)的,似乎有超越 RSA 的势头。

Topic: 
订阅 RSS - 技术