2008-06-10
子曰-群而不党
君子和而不同,小人同而不和。
君子矜而不争,群而不党。
君子同而不比,小人比而不同。
-- 《论语》子路篇第十三
柏邦妮是这么解读的:
在我的理解里,这是一种人生要求:
你融和于俗世,但内心葆有不同之处,
你接纳于群体,但不要搞什么小圈子。
世事纷争,莫过于此。受教了。
君子和而不同,小人同而不和。
君子矜而不争,群而不党。
君子同而不比,小人比而不同。
-- 《论语》子路篇第十三
柏邦妮是这么解读的:
在我的理解里,这是一种人生要求:
你融和于俗世,但内心葆有不同之处,
你接纳于群体,但不要搞什么小圈子。
世事纷争,莫过于此。受教了。
冷雨敲窗不可听,
挑灯闲看牡丹亭。
人间亦有痴于我,
岂独伤心是小青?
今天研究了一下windows远程桌面客户端,就是system32下面的mstsc.exe。
一向讲究易用性的微软在mstsc.exe中提供了一个将主机地址,用户名、密码等连接所需信息保存到缀名为.rdp的文件中,以便将来快速打开的功能 。
现在我想要做的是,如何自己生成这个.rdp文件,让我自己的程序更方便地调用mstsc.exe?
首先需要做的就是分析.rdp文件的格式。
用文本编辑器打开.rdp文件,可以发现rdp文件的内容以是文本形式的,而且大部分都是明文,只有密码这个字段,明显是经过加密的。
所以,自制rdp文件的任务的关键就是要生成这个密码。
查了一下,mstsc.exe使用的加解密算法分别是CryptProtectData和CryptUnProtectData两个windows API。
知道了这个的话就好办了,直接照着MSDN上CryptProtectData的示例改就行了。
下面给出代码:
#include <stdio.h> #include <windows.h> #include <Wincrypt.h> void main() { DATA_BLOB DataIn; DATA_BLOB DataOut; // mstsc.exe中使用的是unicode,所以必须做宽字符转换 BYTE *pbDataInput =(BYTE *)L"freedom"; DWORD cbDataInput = wcslen(L"freedom")*sizeof(wchar_t); DataIn.pbData = pbDataInput; DataIn.cbData = cbDataInput; FILE *fp; if(CryptProtectData( &DataIn, L"psw", // A description string // to be included with the // encrypted data. NULL, // Optional entropy not used. NULL, // Reserved. NULL, // Pass NULL for the // prompt structure. 0, &DataOut)) { printf("The encryption phase worked.\n"); fp = fopen("password.txt","w"); int count=0; while ( count <= (int)DataOut.cbData ){ // 因为一个unsigned int 占32位 // 转换成成16进制要占两位 // 所以这里需要用%02 fprintf(fp,"%02X",DataOut.pbData[count]); count++; } fclose(fp); } else { printf("Encryption error using CryptProtectData.\n"); exit(1); } }
编译时需要指定连接crypt32.lib库,所以一个最简单的编译命令为
cl rdp.cpp crypt32.lib
意外的是,这个程序生成的加密字符串比mstsc.exe生成的要短很多,后面一部分也不一样。但既然是用CryptProtectData加密的,自然也应该能用CryptUnProtectData来解密。实验了一下,果真如此。
回头再想想,微软这么做也是有道理的。因为直接存储CryptProtectData加密过的数据的话,任何人都能使用CryptUnProtectData恢复出明文,加密也就失去了意义。但如果不公开加密算法,那这个rdp文件对于非微软内部的程序员来说,灵活性就变成了0。现在的处理方式既保证了密码的安全性(某种程度上的),也为程序员留下了扩展开发的余地,一个小程序的生命力也由此得到了增强。
见微知著,从一个小东西里面,也可以学到很多。
–EOF–
最近有个句式很流行,就是当要比较夸张地表达你对某人的感情的时候,可以这么说:
“我对你的xx,犹如滔滔江水,延绵不绝”
一般这里的xx可以换作鄙视、敬仰等词。
而我伟大的同学老唐,将这句话扩展延伸了一下:
“我对你的xx,犹如滔滔江水,延绵不绝;又如黄河泛滥,一发不可收拾;一江春水向东流,奔流到海不复回;才下眉头,却上心头。”
念完自己笑抽。
可见,修辞是个大学问啊。
–EOF–
吃完晚饭路过超市,遇到蹲在路边摆摊卖棒冰的小贩。
最近哈尔滨的夜晚格外地冷,深吸一口气,细细感觉一下的话,甚至可以感觉到夹杂的煤烟味的空气顺着嗓子一路渗入肺部,吃掉你的体温,进入你的血液。再厚的口罩,再厚的棉服,也难挡这四面八方涌来的寒冷。
我们可以快步前行,赶紧回到温暖的室内开着窗户挥霍暖气,可他们却不得不守在街头,只为挣得明天的生活。
看着他们在寒冷中不住跺脚以驱赶寒冷,忍不住上前买了一支。
今天是基督徒的平安夜,没有上帝的祝福,给自己买支棒冰,也算是给自己的小小的礼物。
Merry Christmas.
记得大四有一晚不愿意睡觉,一个人在黑暗中靠着墙坐在床上。想到,五六年后,当我工作之后,带着一身疲倦回到家,是不是会和现在一样,一个人坐在床头失眠?
如果生命注定孤独,而孤独又是如此痛苦,那生活的意义又在哪里?
在黑暗中不由得感觉自己的意识已经飘远,在高空的某处俯视蜷缩在床头的自己,就在那个瞬间,忽然想起村上的《斯普特尼克恋人》,忽然明白了那种寒彻整个宇宙的孤独。
Lonely Christmas.
当天亮的时候,生活还得继续。毕竟,身后还有殷切期盼的家人。
总会有爱的。
所以,
期待2008。
从开始用Linux的那天起,就始终被告知平时不要使用root帐户。但我一直认为,偶是程序员,又不是系统管理员,用root调试程序能方便很多,又何必给自己设这么多限制。
记得上次看到不要用root帐户的理由是:“直到你有一天无意间在根目录下rm -rf *,就会知道这么做的后果” 。当时就感觉这话言过其实了,那有人会那么呆啊。
再说我为人谨慎,一般也是不会误删什么的啦。
后来转用ubuntu,这系统做的更绝,直接把root给禁了。但这对于我也是徒劳,因为每次我装完系统,第一件事就是开启root用户。好在用debian用惯了,平时登陆xwindow不像redhat那样直接用root,但开命令行一般直接就是su -。
今天分到个写安装脚本的任务,用bash。
我也没学过bash编程,但想想也简单,就答应了。边学边写,临近晚饭,差不多快写完了。
就在这时,突然发现某个位置似乎对用户交互不合理,于是改之(事后证明是白改,根本不需要也不能这样)。
改完,测试,快到最后一步的时候报错:
rm : can not delete /dev/xxxx
正在纳闷,这是哪出的错。突然意识到大事不好,ctr+c打断执行,可是为时已晚,根目录下的大部分文件都被删掉了,包括/bin目录。
就这样,一百多G的电影、软件、音乐、还有很多代码,都没了。
写安装脚本的vi窗口还没关,能看到代码,仔细检查,发现问题出在了一个条件判断上
echo -n "请输入xxx安装路径[默认:/usr/local/MyPast] " read PROG_PATH if [ "PROG_PATH" = "" ] then PROG_PATH="/usr/local/MyPast" fi ... rm -rf $PROG_PATH/*
看出来了么?PROG_PATH前少了个”$”。
测试时选择了默认路径,也就是直接回车,read PROG_PATH后变量PROG_PATH的值为空。
而接下来if中的条件判断由于少了个$,导致比较结果为非真。PROG_PATH=”/usr/local/MyPast”没有执行。
到了下面, rm的参数$PROG_PATH/*被解释为/*
所以 rm -rf $PROG_PATH/*就变成了rm -rf /*
“直到你有一天无意间在根目录下rm -rf *,就会知道这么做的后果” 。
妈的,这回我懂了。
看来这两天真是脚本与维护不宜。前天搞坏了数据库里的数据,今天又干掉了一个系统,郁闷。
上联:正龙拍虎画中取;
下联:关克护虎政绩来;
横批:一塌虎图。
— 网语
Linux下的编程一直是C语言的天下,但老是用C感觉写的很乏味。用面向对象方法编程,听着都倍有面子。于是决定先在的这个项目用C++来写。虽然不一定能“以C++的思想”来写C++,少会有C++的样子。
但是问题来了:我需要在程序中动态创建一个线程,而pthread不接受C++类的成员函数作为参数。
原因也很简单,类成员是在类被实例化成为对象后才存在的,即在编译时是不存在的,编译器无法取得函数的确切入口地址,自然无法通过编译。
照这个分析,如果把要调用的类成员函数声明为静态的,pthread_create就可以找到函数的地址了。但这样一来的话,由于类中的静态函数无法调用类的非静态成员。线程函数的功能就受到了很大限制,也就没有比要将其放在类中了。
最容易想到的解决方案就是写个C函数,然后再C函数中调用C++对象的成员函数。
比如类为
class foo(){ public : thread(); } class *f; void *bar(void *arg){ f->thread(); return NULL; } int main(){ ......... f=new foo(); pthread_create(&tid,&tattr,bar,NULL); }
显然这种发法太笨了,而且对象只能是全局的。
注意到线程函数bar可以有一个任意类型的指针作为参数,那我们何不将对象通过这个指针将对象变为bar的一个参数,从而让我们的程序好看一些。
class foo(){ public : thread(); } void *bar(void *args){ foo *f=(foo *)args; f.thread(); return NULL; } int main(){ ......... foo *f=new foo(); pthread_create(&tid,&tattr,bar,f); }
如果把上述两种方法结合起来即对象中的静态函数+通过指针参数传递对象,那又会怎么样呢?
class foo(){ public : int thread(); static void *wrapper(void *args){ foo *f=static_cast<foo *>(args); f->thread(); return NULL; } } int main(){ ......... foo *f=new foo(); pthread_create(&tid,&tattr,foo::wrapper,&f); }
现在,强迫症患者,是不是觉得整洁清楚很多了呢?
–Reference–
http://www.osix.net/modules/article/?id=450
–EOF–
标准的好处就是,它提供了很多选择。如果你不喜欢,还可以等明年的。
Andrew S. Tanenbaum. Computer Networks