程序员心法三则

本文不是介绍奇技淫巧,甚至本质上并不是技术,而是态度,心法。

1.抓住问题的本质,在源头解决问题

简单地说,A 有八哥,B 依赖 A,所以导致依赖 B 的 C 出问题,您会通过修改 B 来解决问题吗?正常人都知道要先解决 A 的八哥,蛋似,稍微复杂、含蓄点的问题就有人迷糊了:

一个浮动小窗体,不希望在任务栏上出现标签。

UMU 见过有人使用了 ITaskbarList 对象的 DeleteTab 方法来删掉任务栏上的标签,很高端的做法。蛋似,不够本质,我们要的是不让它出现,而不是出现后擦掉……很早以前,explorer.exe 挂掉后,任务栏通知区域的 QQ 图标就消失了,因为当时 QQ 没有处理任务栏重建的通知消息 TaskbarCreated,重新添加图标。前面说的方法,有同样的问题,explorer.exe 重启后,标签又会出现,还要再删除一次。

正确的主流做法有两个,看情况采用:(1)、WS_EX_TOOLWINDOW;(2)、指定一个隐藏窗体为自己的拥有者。

另一个脱裤子放屁的例子:获得一个文本文件大小,然后 new 一个够大的 char 数组 p,把内容读到 p 上,最后 ::std::string str = p; delete[] p;,这个见太多次,都懒得喷了。::std::string 有 resize 方法,可以直接分配,不需要 new 一个临时数组,再 delete……

判断系统是不是 XP》,也包含了这一哲学,表面上看有好多函数可以获得系统信息,但要明白他们的本质其实有差别,不是都可以混用。

2.要有远见,没有?至少不要不见棺材不落泪!

Y2K 已经过去了,但还有一个 Y2K38,又称 Unix Millennium Bug,历史原因 Unix 时间戳是一个 32 位整数,记录从 1970 年 01 月 01 日开始的秒数,它所能保存的最大时间长度大概是 68.1 年,2038 年 1 月 19 日 03:14:07 之后。

以前硬盘容量小,也不看高清,很多代码都认为文件大小用 32 位表示就够了,结果后来出现很多 ISO、高清电影,都超过 4G……还见过有人采集流量用 32 位整形表示,时间跑久了就溢出了。

远见未必人人都有,退一步说,UMU 敢保证,有很多人即使知道 32 位不够用,还是继续用着,明知道 IPv6 已经出现了很久,还是各种硬编码,认为 IP 地址一定是 IPv4 的地址。态度问题!

3.不要姑息养奸

遇到不合理的情况,UMU 认为应该给力地告诉该知道的人。比如,函数不希望入参是某指,可是调用者偏偏就输入了那个值,怎么办?打印调试信息?不够给力,容易被忽视,应该中断一下,告诉开发者。

配置文件字段被改错,怎么办?如果这个文件是技术人员维护的,应该抛出异常,死给修改配置文件的人看;如果是一般的最终用户,那应该弹出界面,友好提示哪里、怎么错了。

早期,很多程序员为了避免头文件被重复包含,就用了以下代码:

1
2
3
4
#ifndef XXX
#define XXX
// 各种语句
#endif

后来,大家喜欢用 #pragma once,省事,又不容易漏掉最后的 #endif。但是这样做之后会……姑息养奸!除非十分通用的工具类,对严谨的人来说,重复包含是不应该的!所以应该这样:

1
2
3
4
5
#ifdef XXX
#error "您不严谨了!"
#endif
#define XXX
// 各种语句

有重复包含立刻告警,而且都是集中在开头,不存在漏掉 #endif 的问题。

态度问题!这里只是举几个简单的例子~

卸载 LSP 并重启系统依然有服务加载它

发现问题,2012-12-11 18:16:00

快游(网游加速器)包含一个 LSP,属于加速核心组件,在测试 LSP 期间,发现一个奇怪的现象:反注册它,并 netsh winsock reset 加重启好几次……依然有程序加载它。用 Process Explorer 查看是:IpOverUsbSvc.exe 和 daemonu.exe。把 LSP 的 DLL 文件删掉,再重启,可以消灭这个奇怪的现象。但后来想重现这个怪现象时,却无法重现。

重现和解决问题,2012-12-25 15:38:00

问题自然重现,继续研究。这两个进程对应的服务名是:IpOverUsbSvc 和 nvUpdatusService。手动重启这两个服务后,即不再加载 LSP。推理:这两个服务很可能每次重启机器时都没有正常关闭,系统提供了某种机制让他们在下一次重启后快速恢复了运行现场(保留了有 LSP 注册时的环境)。

分析问题,2013-03-26 23:24:30

时隔三个月,偶然看到介绍"混合式关机"的文章,恍然大悟,原来是这货引发的八哥!

在安装 Win8 后,很多人都体验到了其开关机惊人的速度,尤其是开机速度,相比 Win7 之下,它提升的不止是一点半点。在某些超极本和配备了 SSD 的机器上,其开关机速度可以在数秒以内。例如 Surface Pro,其实测系统引导速度为2秒,从启动到自动登录到开始屏幕只要6秒。

究竟是什么技术提升了 Win8 的开关机速度呢?如果要用最简单的一句话概括,那应该是"系统会话休眠",或者更简单的,“混合式关机”。

在 以往的 Windows OS 中,典型的关机顺序为:

  1. 单击"关机"。

  2. Windows 广播运行应用程序关机信息,让应用程序可以保存数据和设置。应用程序也可以要求一些额外的时间以结束其当前工作。

  3. Windows 为每个登录用户关闭用户会话。

  4. Windows 向服务发送关机信息,通知已开始关机,接着关闭服务。如果服务未响应,系统将强制关闭。

  5. Windows 向设备广播信息,示意设备进行关闭。

  6. Windows 关闭系统会话(也称为"会话 0")。

  7. Windows 刷新系统驱动器待决数据,以确保完全保存。

  8. Windows 通过 ACPI 界面向系统发送信号以给计算机断电。

看着以上的典型关机步骤,你是不是也有想到一些步骤对应的屏幕上的 UI 表现呢~

再来看看 Windows 8 采用的混合式关机主要步骤:

  1. 单击"关机"。

  2. Windows 广播运行应用程序关机信息,让应用程序可以保存数据和设置。应用程序也可以要求取得一些额外的时间以结束其当前工作。

  3. Windows 为每个登录用户关闭用户会话。

  4. 系统会话休眠,并掉电。

可见,Windows 8 只关闭用户会话而不像以前那样完全关闭计算机。此时, Windows 不再等待并结束系统服务和关闭会话 0,而是让其进入休眠。这种关闭用户会话+休眠系统服务和系统会话的做法,被称为"混合式关机",也就不难理解了。

或者说得通俗点,就好比你之前打扫卫生时,需要先组装专业的拖布,组装好了以后,才能开始打扫卫生。而现在,你可以拿起拖布直接开始打扫,因为你上次打扫完之后,并没有将拖布这一工具像以往那样拆卸下来收好。

开机在结构上是关机的逆过程,所以有了混合式关机,开机自然也就快了。但是,除了 RAID 卡外,一般硬盘的读取速度会比写入速度略快,加上关机的时候,系统会通知并等待应用程序退出,所以从感官上,开机过程会比关机过程显得要快一些。

枚举物理网卡

其实目的是获取靠谱的 MAC 地址,但这个任务真蛋疼!不信您看看搜索出来的乐射……

神马 GetAdaptersInfo、GetIfEntry、GetAdaptersAddresses、NetWkstaTransportEnum,还有读取注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards。这些都会枚举到虚拟网卡,给您举个例子“VirtualBox Host-Only Ethernet Adapter”,读取神马 NetCfgInstanceId、MediaSubType,都不靠谱,没有平台移植性!

用 Setup API 枚举 Interface,匹配 PCI 和 USB 类型是比较靠谱的。

蛋似,虚拟机的网卡也是虚拟的,为了方便在虚拟机测试,您要注意放开一些特例……很抱歉,领导说代码要保密,自己搜吧,关键字:SetupDiGetDeviceInterfaceDetail、OID_802_3_PERMANENT_ADDRESS。

给个蛋碎的例子:\\.\pci#ven_10ec&dev_8168&subsys_050e1028&rev_06#4&224db6dd&0&00e5#{ad498944-762f-11d0-8dcb-00c04fc3358c}\{4cc0ea76-88b7-40e1-8b4b-6339f8dd49bf} 可以简称为 \\.\{4cc0ea76-88b7-40e1-8b4b-6339f8dd49bf} 或者 \\.\Global\{4cc0ea76-88b7-40e1-8b4b-6339f8dd49bf}

协议加速的三个时代

这里要说的是基于反向代理+缓存的加速。位于客户端和服务端之间的加速系统,理解某些协议,并对这些协议进行处理,使客户端不需要做任何改动的前提下,其请求被重定向到更“近”的“代理服务器”上。

普通时代

主要处理公开的协议,最明显的例子是 HTTP 下载,加速系统理解 HTTP 协议,当收到 GET 请求时,伪造 302 等跳转回应,使客户端改向加速系统提供的“代理服务器”下载。

当一个域名只用于 HTTP 服务时,还可以对这个域名做文章……DNS 协议也是公开的。

文艺时代

各种下载器、视频应用开始采用私有协议……所以,逆向就必不可少了,这个时代加速服务提供商必须有一定开发实力,不能再用一些开源代码整合就了事。

二逼时代

某些下载器的公司出于各种原因不希望别人假扮自己的“服务器”,于是做出了艰难的决定,下载协议使用非对称算法加密,这样一来,即使那些逆向高手把整个下载器客户端都逆向了,那也只是做出一个客户端,无法扮演服务端,于是乎……加速服务公司都 2B 了,要私钥吗?分点钱吧!

吃屎是不可避免的未来~

未来,可能是为了节省能源,或者出于“猪”道主义,人类已经不吃禽兽这类比较有情感的动物了,根据泥巴娃所梦,未来的人都是吃虫的。
果蝇、蛆等虫,虽然恶心,但是经过加工,确实是很好的蛋白质来源。
泥巴娃注意到这个流程:人拉屎,养蝇蛆,产蛋白质,加工成肉,人吃肉,拉屎……
这个过程很快,很快,快到来不及反应,就变成了——人吃屎!
一个个面目狰狞,手里还捧着一坨屎,要请泥巴娃吃,泥巴娃眼一睁,整个世界清静了~

诗盗·鲸神链

《#诗盗#·鲸神链》:尘网乱我眼,封七鹰三十年。修心识本性,笑谈鲸神链。

注解

“鲸神链”的由来:大三或者大四时,申请了一个新 QQ,想取个特别的昵称,当时想自己是“技术流”,所以就输入 jsl,结果出来的是“精神恋”,感觉也不错,因为 UMU 觉得爱情的最高境界就是“精神恋”,但直接这么下去肯定很多人喷,所以就用了“鲸神链”。

尘世太多喧嚣、压抑物欲横飞遮乱了人们的眼睛,让人看不清真相本源。

哥因此封印了天生敏锐的感情世界,转眼三十年过去了……

世道修心是体会人间悲苦离合,虽然大家都是杯具,蛋似哥坚持聪明天赋、善良本性。

笑看当今物欲世界,哥一直认为精神恋才是爱情的最高境界,这在凡人眼里只是笑话,只有哥还在谈情说爱大笑。

诗盗·古古锅锅给哦哦哦

《#诗盗#·古古锅锅给哦哦哦》:退田盖新房,旧屋种菜偿。家鸡不识哥,十年亦沧桑。

注解

泥巴娃小时候,老家就是典型的农村,很多田野,种各种菜,后来退田盖新房,但是妈妈保留了种菜自己吃的习惯,于是在旧屋的屋顶搞了很多塑料泡沫箱子来种菜,屋内则养鸡鸭。最近去旧屋看了一圈,觉得陌生了许多,才十年而已,却恍如隔世。