qyb的博客

取本机所有的 IP

代码修改自 qmail 的 ipme.c , 要点是对于 struct ifreq 里定义了 ifr_addr.sa_len 的系统(比如 FreeBSD),是和 Linux 不太一样的。
在 CentOS 3 和 FreeBSD 4.7 上测试通过

  1. /* ipme.c from qmail */
  2. #include "sys/types.h"
  3. #include "sys/ioctl.h"
  4. #include "sys/socket.h"
  5. #include "netinet/in.h"
  6. #include "net/if.h"
  7.  
  8. int main(int argc, char *argv[])
  9. {
  10.     struct ifconf ifc;
  11.     int sockfd;
  12.     char buf[20000];
  13.     char *ptr;
  14.  
  15.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  16.         return -1;
  17.     }
  18.  
  19.     ifc.ifc_buf = buf;
  20.     ifc.ifc_len = sizeof(buf);
  21.     if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
  22.         return -1;
  23.     }
  24.  
  25.     ptr = buf;
  26.     while (ptr < buf + ifc.ifc_len) {
  27.         struct ifreq *ifr;
  28.         struct sockaddr_in *sin;
  29.         int len;
  30.  
  31.         ifr = (struct ifreq *)ptr;
  32. #ifdef __FreeBSD__
  33.         len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
  34.  
  35.         if (ifr->ifr_addr.sa_family == AF_INET) {
  36.             printf("%s", ifr->ifr_name);
  37.             sin = (struct sockaddr_in *)&ifr->ifr_addr;
  38.             printf("\t%s", inet_ntoa(sin->sin_addr));
  39.             if (ioctl(sockfd, SIOCGIFFLAGS, ifr) == 0) {
  40.                 if (ifr->ifr_flags & IFF_UP) {
  41.                     printf("\tUP\n");
  42.                 } else {
  43.                     printf("\tDOWN\n");
  44.                 }
  45.             }
  46.         }
  47.  
  48.         // 这段代码来自 qmail 的 ipme.c, 在 FreeBSD 上实测中没有出现过 len 小的情况
  49.         if (len < sizeof(struct ifreq))
  50. #else
  51.         if (ioctl(sockfd, SIOCGIFFLAGS, ifr) == 0) {
  52.             if (ifr->ifr_flags & IFF_UP) {
  53.                 if (ioctl(sockfd, SIOCGIFADDR, ifr) == 0) {
  54.                     if (ifr->ifr_addr.sa_family == AF_INET) {
  55.                         sin = (struct sockaddr_in *)&ifr->ifr_addr;
  56.                         printf("%s\t%s\n", ifr->ifr_name, inet_ntoa(sin->sin_addr));
  57.                     }
  58.                 }
  59.             }
  60.         }
  61. #endif
  62.         len = sizeof(struct ifreq);
  63.         ptr += len;
  64.     }
  65. }
Topic: 技术

昨天终于把《快乐的农夫》的右手弹得像模像样了

"Joyous Farmer" Robert Schumann

左手好几个月前就能弹了,但右手怎么也不行... 后来挺忙的,就一直没有练这个曲子。

前天晚上练极简单的 Ode to Joy 以后,突然想着去把这首舒曼右手再练一下,没想到就很感觉很熟练了,:)

昨天反反复复弹到大拇指下某根筋隐隐作痛;今年的目标是把两手合起来...... 主要是缺练琴的时间,难啊~~~

自己弹没有感觉,看人家的演奏发现弹起来手的表演性还真强。

Topic: 生活 音乐

方刚的"三个容器"

见:http://fangzl.blog.sohu.com/102159550.html

昨天在一个小会上听方刚提到这三个容器,现在我觉得我可以帮着解读一下这三个代表的意思了....

第一个容器,是搜狐博客
第二个容器,搜狐空间... 搜狐空间只是起了一个 Space 的名

第三个容器,是....一张白纸. 用毛主席的话,就是好画最新最美的图画

核心是,这三个容器,在方刚看来,是...完全不兼容的。

但有总线把这三个容器串在一起...

但为什么方刚没有把privacy和 profile/relationship 归一处。而是和 APP 放在一个总线里面呢? 这个可得再问问他

Topic: 商业

dup2.org 恢复访问

由于原来的 vmmatrix 服务调整,现在把dup2.org切换到新的一个 VPS 上,感谢老韩友情赞助服务资源。

顺便把 drupal 也升级到了最新的 6.x

在从 5.x -> 6.x 的升级过程中,导出的 sql 文件有 1 个G!! 检查后发现都是 watchdog 这个表的内容。

watchdog 在 5.x 是核心模块还不能 disable,现在升级到 6.x,可以把"Database logging"这个模块禁用了,hoho

扩展模块现在只剩下 4 个: GeSHi Filter (满足时不时贴代码的需求)、XML Sitemap (搜索引擎优化)、CAPTCHA(对付垃圾留言)、Similar entries (提高网站的可阅读性). 别的东西我觉得都没有用,否则每次升级 drupal 都是一个麻烦事。

说实话,如果不是已经熟悉了 drupal 以及国外的 blog 服务容易被盾,真想切换到 blogspot 上. 要么使用 blog.sohu.com?? 好像很不严肃的样子...

文本聚类研究

最近一直在研究文本分类。到今天,终于搞出一个收敛的单词聚类算法。

最主要的时间是在磨刀上——前前后后总共差不多有 1 周的时间在看 sogou 分词库的文档,以及给它开发一个 python-binding

然后是差不多花了半天的时间写爬虫,获得最初的文档库

利用"[PDF] WRM :一种基于单词相关度的文档聚类新方法"里介绍的概念计算单词两两之间的相关度

最麻烦的就是利用相关度对单词聚类,论文里介绍的方法好像并不好用。从周二到周日,都在不停的找论文,试验新算法,运行测试,修正... 的循环里度过

失败无数次后,最后在 Fuzzy C-Means Clustering 的指导下,投机取巧的设计了一个方法以及判断收敛的机制,今天下午已经成功的跑完一次聚类到 250 个集合的过程,另一个聚类到 100 个集合的过程虽然比较慢,但在 2 个小时前也已经结束。Oh, my god, 看起来是可以正常工作了。

感谢分词库开发者,感谢搜狗新闻、关键字广告 TEAM 曾给的帮助

【尤其是 sogou 的开发包,能返回词的词性... 虽然还有瑕疵,但已经对我帮助很大了】

感谢python, 没有它不可能短时间内把算法体无完肤的改上10几次

感谢《鬼吹灯》,周末的晚上是它让我保持清醒,时不时的去看一眼后台跑的计算过程.

感谢家里人忍受我最近的加班

Topic: 技术

在 PyS60 上使用 ctypes 修改 WIFI 的 MTU

自从换了 DELL 无线路由后,俺的 E61i 也出现无法正常连接 WLAN 上网的情况,而且和当初 Vista 的故障一样——可以访问 google,但大部分网站的连接不上,据以往经验,估计还是因为手机的 MTU 大于这个路由器最大支持的能力。

在网上搜了半天,发现在 S60 2nd 机型上,有一种改 genericnif.ini 的方法可以改变 MTU,但是到了 S60 3rd 机型,貌似就只能自己动手写程序了。

但 Symbian 下的 C++ 开发俺不熟啊,PyS60 没有接口啊,怎么办。正好在查相关开发信息的时候,发现 Symbian 出了一个 POSIX 兼容层(S60 平台上的称呼是 Open C),PyS60 社区有人据此移植了 libffi_ctypes 过去;又有人包装了兼容 Python2.5 的 ctypes 提供一些外围函数;wiki 上还有一个 open c 下执行 setsockopt 的例子

于是安装了 Open C 的 SDK, 然后在它的文档里找到这么一段:
The following flags will work only on hardware because it is supported by the underlying symbian API.

  • SIOCGIFMETRIC
  • SIOCGIFMTU
  • SIOCGIFNETMASK
  • SIOCGIFBRDADDR
  • SIOCGIFFLAGS
  • SIOCGIFDSTADDR
  • SIOCGIFPHYS
  • SIOCSIFMETRIC
  • SIOCSIFMTU
  • SIOCSIFFLAGS

只要确认 SIOCSIFMTU 是可以用的就好办了,对一个熟练的 C 程序员且有一定 ctypes 使用经验的人来说,除了平台移植问题外,开发是没有什么困难的。

开发过程如下

  1. 在手机上安装 libffi、Ctypes (_ctypes.pyd)、ctypes
  2. 在 Windows 下安装 S60 C++ SDK,以及 Open C plugin。可以找到 pips_nokia_1_3_SS.sis 等一共 4 个 .sis 文件,都安装到手机上
  3. 找到 winscw\udeb\libc.lib,然后用 dumpbin.exe /exports libc.lib 寻找函数名对应的序号,PyS60 的 ctypes 必须得用序号去定位函数,比如这样
    1. from _ctypes import *
    2. from ctypes import *
    3. libc = dlopen("libc.dll")
    4.  
    5. socket  = lambda x,y,z: call_function(dlsym(libc, "339"),   (x,y,z))
    6. ioctl   = lambda x,y,z: call_function(dlsym(libc, "180"),   (x,y,z))
    7. close   = lambda x:     call_function(dlsym(libc, "57"),    (x,))
    8. perror  = lambda x:     call_function(dlsym(libc, "255"),   (x,))
    9. dup     = lambda x:     call_function(dlsym(libc, "67"),    (x,))
    10. close(2)
    11. dup(1) #把标准错误重定向到标准输出,这样 perror 就输出到标准输出了
    12.  
    13. ntohl   = lambda x:     call_function(dlsym(libc, "168"),   (x,))
    14. ntohs   = lambda x:     call_function(dlsym(libc, "169"),   (x,))
    15. print ntohs(1), ntohl(256)  #简单的测试脚本
  4. 没有 dumpbin.exe 这个工具(VC++)的,也可以用 MinGW 的 nm.exe 来处理 libc.lib,只不过输出结果还需要再处理一下
    1. f = open("c:\libc.txt")
    2. idx = 1
    3. for i in f.readlines():
    4.     if i.startswith("00000000 T "):
    5.         if i[11] == '.':
    6.             continue
    7.         print idx, i[11:].strip()
    8.         idx += 1
  5. 根据 SDK 的头文件,找出 SIOCSIFMTU 这样的常量定义写成 python 语句
    1. IOCPARM_MASK = 0x1fff
    2. _IOC = lambda inout,g,n,l: (inout | (l & IOCPARM_MASK) << 16 | ord(g) << 8 | n)
    3. _IOR = lambda group, num, len: _IOC(0x40000000L, group, num, len)
    4. _IOW = lambda group, num, len: _IOC(0x80000000L, group, num, len)
    5. _IOWR = lambda group, num, len: _IOC(0x40000000L|0x80000000L, group, num, len)
    6.  
    7. SIOCGIFCONF     = _IOWR('s', 3, SIZEOF_IFCONF)
    8. SIOCGIFFLAGS    = _IOWR('i', 17, SIZEOF_IFREQ)
    9. SIOCGIFMTU      = _IOWR('i', 51, SIZEOF_IFREQ)
    10. SIOCSIFMTU      = _IOW('i', 52, SIZEOF_IFREQ)
    11.  
    12. IFF_UP          = 0x1
    13.  
    14. AF_INET         = 0x0800
    15. SOCK_DGRAM      = 2
    16. IPPROTO_UDP     = 17
  6. 还要去找 struct ifconf, struct ifreq 是怎样定义结构体的,结构体大小是多少
    1. SIZEOF_IFREQ = 84
    2. SIZEOF_IFCONF = 8
    3. IFREQ_IDXFMT = '52sH'
    4. IFREQ_MTUFMT = '52sI'
    5. IFREQ_FLAGSFMT = '52sBB'
    6. autopadding = lambda start, size: start + str(size - calcsize(start)) + 's'
    7. ifreq_idxfmt = autopadding(IFREQ_IDXFMT, SIZEOF_IFREQ)
    8. ifreq_mtufmt = autopadding(IFREQ_MTUFMT, SIZEOF_IFREQ)
    9. ifreq_flagsfmt = autopadding(IFREQ_FLAGSFMT, SIZEOF_IFREQ)
  7. 真正的操作很简单:
    1. sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
    2.  
    3. result = create_string_buffer(SIZEOF_IFREQ * 20)
    4. ifc = create_string_buffer(pack("II", SIZEOF_IFREQ * 20, addressof(result)), SIZEOF_IFCONF)
    5.  
    6. ret = ioctl(sockfd, SIOCGIFCONF, ifc)
    7. ifc_len, ifc_buf = unpack("II", ifc.raw)
    8. count = ifc_len / SIZEOF_IFREQ
    9. for i in range(0, ifc_len, SIZEOF_IFREQ):
    10.     ifreq = result.raw[i:i+SIZEOF_IFREQ]
    11.     ifr_name, ifr_idx, padding = unpack(ifreq_idxfmt, ifreq)
    12.     ifr = create_string_buffer(ifr_name, SIZEOF_IFREQ)
    13.     ret = ioctl(sockfd, SIOCGIFFLAGS, ifr)
    14.     ifr_name, ifr_flags, ifr_flagshigh, padding = unpack(ifreq_flagsfmt, ifr)
    15.     if not (ifr_flags & IFF_UP):
    16.         print "%s: DOWN" % ifr_name
    17.         continue
    18.     ret = ioctl(sockfd, SIOCGIFMTU, ifr)
    19.     ifr_name, ifr_mtu, padding = unpack(ifreq_mtufmt, ifr)
    20.     print "%s: UP, MTU: %d" % (ifr_name, ifr_mtu)
    21.     if ifr_mtu > 1400: #凡是 MTU > 1400 的,都改成 1400
    22.         ifr = create_string_buffer(pack(ifreq_mtufmt, ifr_name, 1400, padding), SIZEOF_IFREQ)
    23.         if -1 == ioctl(sockfd, SIOCSIFMTU, ifr): foo = perror("why")
  8. 但...为什么 perror 会报 Permission denied 呢? 后来查了半天,发现是 SIOCSIFMTU 需要有 NetworkControl 权限。于是去 这里 申请一个自己手机 IMEI 对应的证书(免费的),证书对应的 key 在这里
  9. ensymble 这个工具来给 libffi/Ctypes/PythonScriptShell(unsigned_testrange) 重新签名,加上 NetworkControl 权限
    ensymble.py signsis --cert=20081008001.cer --privkey=dospy.key --passphrase="" --execaps="ALL-TCB-ALLFILES-DRM" PythonScriptShell_1_4_4_3rdEd_unsigned_testrange.SIS imei_PythonScriptShell_1_4_4_3rdEd.sis

    ensymble.py signsis --cert=20081008001.cer --privkey=dospy.key --passphrase="" --dllcaps="ALL-TCB-ALLFILES-DRM" libffi.sisx imei_libffi.sis

    ensymble.py signsis --cert=20081008001.cer --privkey=dospy.key --passphrase="" --dllcaps="ALL-TCB-ALLFILES-DRM" ctypes.sisx imei_ctypes.sis

  10. 这下大功告成,我....我终于又可以在家里坐在马桶上用手机上无线了!!
Topic: 技术

关于牛奶

From blog 配图

十一期间亲戚们一起吃饭,收到一条彩信报,说是北京市决定给每头奶牛每天补贴伙食费15元。我把这条新闻当笑话讲给同桌的人听——这也太扯了,算下来每个月伙食补贴比搜狐午餐补贴还高——但正好我老婆的表哥曾经养过奶牛,他给我说:

奶牛的伙食是很好的,比如一头奶牛一天 50 斤奶的话,大概要吃 25 斤的粮食。光吃草,是产不出奶来的。

见到这里有一个奶牛专家,我一下来了兴趣,于是又从他那里了解到好多奶牛知识。

  1. 牛奶这条供应链上是三个环节,奶农、奶站、生产企业。
  2. 奶站以1.2元/斤的价格从奶农那里收奶,然后以1.3的价格卖给企业
  3. 奶站必然是要掺水的,氮化合物也随之添加
  4. 企业,或者说企业的原料采购部门对这个猫腻是很清楚的,据说曾有企业向奶站提出过以1.4的价格收购,前提是不要掺水,但奶站不干
  5. 假如收购价格从1.3提高到1.4还达不到掺水的利润的话,可见掺水的比例之高,或者说有毒物质比例之高
  6. 现在由于奶制品销量剧减,需求不足,最新的模式是奶站收了奶去卖,然后按卖的价钱计算给奶农的付款
  7. 养奶牛的成本是很高的,一头牛大概1w元。因为一年才一胎,就是说一只奶牛两年才能产一只新奶牛。奶牛也不是随时都有奶,还是在哺乳期内奶量大。
  8. 供应链还有一种优化的模式是"托牛所",就是养户出钱购买奶牛,集中交给奶站养,饲料什么的都由奶站负责

好啦,科普结束。

问题是,企业明知道它的供应商提供不合质量的产品,为什么长时间以来无法解决(我家一本十年前的书上就描述了如何检查牛奶中是否含有尿素)

我更关心的是:是不是在现有体系下,跨农业和工商业的(以及跨地域的)供应链就根本无法优化?比如"托牛所"这个东西,乳品企业能参股,或者是自己组建吗?县级/乡级政府在这里面的角色是什么?

如果供应链上游不能真正市场化,我觉得最后还是要出问题。

Topic: 商业 社会

我要抵制蒙牛了

本来我是一个很和谐的人,虽然平时有很不和谐很不主流的思想,但还不至于到网上发表右派言论或愤青言论。。。

但这次不做点什么也太对不起蒙牛了...

先抵制5年再说,不知道到 2013/9/28 ,这家企业还在不在

最后,马上就是共和国59年大庆。在生日之际像鲁迅那样说:"这孩子将来是要死的" 太恶毒。我的祝愿是:再坚持15年,就比苏联(1917—1991)更长寿了,hoho

Topic: 社会

给奥组委做的邮件系统容灾方案

据说一共有5家厂商提供了方案,俺代表搜狐提的方案最后得到采纳,日后要说起bj2008,我可以对达达说:当年你老爸也是为奥运建设出过一份力的...

现在残奥会也已经结束,按照当初商定的合同,搜狐的支持服务在一周后也就是9/30将正式终止,我想现在讲一下技术细节应该不会有什么影响了。

要解决的问题简单说就是:万一奥组委的邮件系统瘫痪,怎样才能让邮件系统尽快可用。

系统出问题有很多种,除了硬件故障、软件故障外,网络故障和机房故障也是需要考虑在内的。我根据搜狐邮件中心所能做的工作,提出的是一个异地容灾方案:

灾备系统在我们这里,把它设为低级别的 MX,平时不启动 25 端口,一旦奥组委确认需要启动该灾备系统,则启动 25 端口。将所有收到的邮件,比如说发给 foo@beijing2008.cn 的,利用 Milter 协议的 addRcpt 功能,增加一个 foo@vip.beijing2008.cn 的收件人。vip.beijing2008.cn 是本地 host 的一个邮件域,在紧急情况下,奥组委邮箱的原用户可以登录到这里查看并回复新收到的邮件。而发给 foo@beijing2008.cn 的邮件会在我们的 postfix 队列里等待,一旦奥组委的故障恢复,自然就能重新投递过去。

技术核心就是 Postfix 的 Milter 支持能力,以及针对 beijing2008.cn 的投递不是 DNS 查询而是 transport_table 指定。实施上最麻烦的是用户数据问题,和邮件没任何关系,却花了大量的时间在上面。

灾备准备好了,奥运期间也没有出现突发事件需要考验俺的这个方案。算是好消息,但也有点小遗憾。

最后要说的是,奥组委的IT部门,业务能力还是很不错的,比我以前做项目时接触的几个甲方单位强多了;还有一个首信的同仁,不知道是做项目监理还是负责整个的项目集成,几个电话打下来对他的敬业精神和认真态度也是很佩服。从小见大,奥运会本身怎么怎么样不去评论,但确实是把中国最优秀的人才集中在了一起去支持这个 big project。。。咳咳,上句所说的最优秀人才不包括我.

Topic: 技术
订阅 RSS - qyb的博客