《C程序设计语言》句读 20130120
在这里[http://www.tudou.com/programs/view/F80XyfJFBYE/]。
这次开始第1章,小程序示范。Hello world结束了,正讲到华氏度转摄氏度的循环。
--------------------
博客会手工同步到以下地址:
重剑无锋,大巧不工
《C程序设计语言》句读 20130120
在这里[http://www.tudou.com/programs/view/F80XyfJFBYE/]。
这次开始第1章,小程序示范。Hello world结束了,正讲到华氏度转摄氏度的循环。
--------------------
博客会手工同步到以下地址:
《C程序设计语言》句读 20130117在这里[http://www.tudou.com/programs/view/IP0uddL3wX8/]。这次句读完了绪论,第1章刚刚开始。我按现在的进度估算了一下总共需要的时间。全书一共190页,如果每次2页,我们需要95次,如果每周一次,需要95周,需要1.76923076923年。不到2年的时间。我又想起当年考研还是考博时的犹豫,犹豫所需要的时间,还有学完要花费又几年的时间。当时一个贴子让我明白了一点。贴子说,一个家伙犹豫要不要考研,心想,等我毕业需要三四年,那时我都快40了。我还要不要考呢?他的朋友说,你以为你不考,过三四就不四十了么?句读C语言需要两年的时间。我自问自己,你真以为如果不句读C语言,这两年就能做更有意义的事情啦?我们有时并不是有更重要的事情要去做,不过是对现状的绝望。
今天有领导训示大家,关于科研考核什么烂糟的。不是科研考核本身烂糟的,我是说我的科研成果烂糟的。有位同事说,"计算机学科这么弱,跟化学生物物理同一个标准不合适。"我不太以为然,自己不行么,要么争气,要么认命,也没啥可争的。包师弟有云,"眉毛上的汗水,眉毛下的泪水,你总得选一个。"反正你如果有目标,总归得工作或者哭。不过我不敢跟我的学生们说,怕他们认为我是在励志。因为我总记得我们最终还有一条路可选,就是放弃目标。但这话不能跟同学们说,他们该投诉我了。同事提到的学科差异,领导开玩笑地说,"那就得怪你选错学科了。"大家笑。我没配合笑一下,而且非常激动。所以当另一位领域问俺们,不是,问我有啥想法时,我就表达了一下。我们学科弱不错,全世界的计算机都比化学生物物理弱,也不错。但是我们热爱这个学科,你不能说我们选错了学科。就算你把我们拆了,全分到各个系看机房,我们还是热爱这个学科。上述,我表达得有点语无伦次,现场效果也就是如此。其实我想说的是,我没有别的选择,我只喜欢计算机。所以,我也没有什么别的可以做的。人人网还是哪,以前有过微博类调查,说如果没有你学习从事的这个专业,你想做啥去。如果那样,我想去死。没有别的选择的时候,人生就完全不同了。至少,你不会因为选择痛苦--因为你别无选择。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
读书怎么才能更快沙发上堆了不少书,这些都是计划要看完的。有的要精读,有的要粗读。精读和精读消耗的时间相差巨大。大抵上,读书想要更快,速度就在精读和粗读的速度差上了。当然,排除一种方法,就是你一顿瞎翻,啥也没记住。李笑来先生曾经说过,读书提速的方法,根本没有秘诀。无外乎多读,多读你的速度就快了。你可能问了,为啥啊。有人可能还听说过一种叫"快速阅读"的技术。练习以后,能一行一行地往下看,不是一个字一个字的看。大致上,跟竖着看书差不多。我小学的时候学过,貌似还有点用。英语阅读的时候,我能用别人一半的时间完成阅读和答题--当然准确率并不怎么出色。不过,即使我降速到原来的一半,准确率也就还是那样。这样看来,"快速阅读"似乎还有点用?这跟李笑来先生提到的没有秘诀是否矛盾呢?其实,不矛盾,都是一回事。一者,长时间地阅读,会自然地形成很多技巧,这些技术就跟走路多了的人会走路一样:把文字按行或按词组划分,不要每个字都读,跳着读,不要在心里出声,啥的。要想阅读超过人类的正常语速,还是挺容易的,只要读足够的量。所以,一般没有特殊训练,也容易达到。不过,当我们读教科书、经典著作,或者我们称为晦涩难懂的那些书的时候,问题就来了。这个时候快速阅读完全起到了相反的作用。比如第一次读《C程序设计语言》,比如读《纯粹理性批判》,比如读你明天要考试的那科教材。一目十行,合上就忘,甚至当时也不知道作者在说些啥。所以,计算机领域有一种说法,他们希望发明一种"慢速阅读"方法,从而能字斟句酌地一点点扣。这种时候最好的读书法是 不仅"读",而且"做"。正如CSAPP中说的,学习系统的最好方法,就是 "do
system"。当你沉浸其中,不看书实现一遍那些代码的时候,你就真正掌握了。有的似乎把这叫做在"内化"。扮演老师,给别人讲明白;找个实例按书里的路子剖析一遍……总之,经历过的事情,会让你刻骨不忘。这就是为什么讲起近三十几年的历史,三十几岁的人往往连书都不用翻,因为他们身在其中。当然,"do system"的方法,是个慢方法,而不是个快方法。不过,如果吃了东西都不消化,还吃它干什么。所以,"do
system"也是大量阅读中的好方法。更好的方法,是自己写一本。大量阅读,会自然形成阅读技巧,因此,会读得快。但大量阅读的作用,不止于此。其二,大量阅读会形成知识结构。这样,不仅技术使你读得快,知识结构还会使你越读越快。我面对那么书,也常常挠头,叹"吾生也有涯而知也无涯",悲夫。不过,到真正读的时候发现,有的书读起来比想像地快得多。比如我用一个晚上读完了今何在先生的《我的征途是星辰大海》,用大半个晚上读了半本二月河先生的《九王夺嫡》。这种速度和某些速读牛人比起来并不算什么,不过和我其他的记录相比就令我惊叹了。我读SICP的时候,有过2个小时1页的时候,读康德的时候,有好几天断断续续没翻过去一页的时候。和这些比起来,一晚上半本一本的速度就很快了。为什么会有这种差别呢?一个原因是,这些书的信息含量是不同的。信息论告诉我们:信息,是对无序的度量,只有当可能性未知时,即事件你还不知道结果的时候,告诉你的,才是信息。你明知道的事情,我再说一遍,对你而言是零信息。那种对话一般表达情感,或者是仪式,比如那句古老的"你吃了吗"或者"how
are you"。其实说话人对你吃了没有或者好不好一点也不感兴趣。小说和电影,如果只是为了欣赏,而非研究学习,那读起来就可以酣畅淋漓。按Johan Lilius教授对 the Big
Bang的评价,把脑子拿走一些看,效果会更好。按《破产姐妹》里胖姑娘的说法,对着电影大喊大叫,那正是享受电影。这样的时间,过得很快,其实也真的不多。一场电影1.5小时,可能康德还没有读完半页。另一种读起来快的书,就是里面的知识全是你知道的。我们翻金庸原版武侠的时候,感觉大概就是这样。谁什么时候要死了,什么时候要难过,后面还有啥阴谋,咱们全知道。只是为了再感动一次。可以几秒钟就翻过一页,如果不细品文字的话。还有精通一种语言的人,再学习其他的语言,看教材的时候,速度也非常快。因为他的头脑中,不管什么语言,都应该有变量声明、类型、结构体、数组、对象、判断、循环、函数、库。一般都这样,内容不变,只是语法上有差别。除非,你遇到了颠覆你人生观世界观价值观的东西。比如,LISP有那么一大堆括号不让人头疼,很多初学者的第一个问题是,这家伙没有循环怎么迭代,然后可能又遇到个问题,函数怎么可以没有名字,可能还会有人疑惑变量怎么可能没有类型。再比如,PYTHON初学者可能对结束没有";"还没有多大意见,缩进是语法的一部分,很多人好几年适应不过来。还有,当你打开罗素康德,看到他们所讨论的有的似乎你疑惑者,有的你根本不知道他们在说什么。他咔咔一顿推导,最后得出一个你万万不能支持的结论,突破了小资产阶级所谓"底线"。这可不行,还得掉头看他怎么推理的,或者扔掉再踩上一脚,评"什么破玩艺",或者"我可整不了"。所有这些,lisp,python,康德罗素,他们让我们不舒服,让我们阅读的速度大大降低,原因在于--他们正拓展我们的知识结构。探索新宇宙,开疆拓土,历来如此。想舒服,想快速,就停留在我们原有的知识结构上。拿起本小学数学,或者初中二元一次方程,那感觉,是不是很自信。我以前装机试软件的时候,曾经装过一个软件,考10以内加减法。我做完题,机器评论"你看是个天才"。但是我并没有什么满足感,只是觉得滑稽而已。大部分小学生看你现在要考试的教材,速度肯定比你慢上百倍。他的阅读速度,甚至认字和组词的能力,都阻碍他的理解。更重要的,你已经具备了这本教材的知识结构。知识结构的完备,大大减少了我们阅读时的信息量。读我们熟悉的东西,不过是增加细枝末节的了解,而框架的建立,而是伤筋动骨,痛苦而漫长。这也是为什么我们人类那么痴迷于"形而上",因为我们期待建立了它以后,剩下的可以不用想就推出来了。所以,大量阅读建立的知识结构支持我们更快的阅读,因为它大大减少了书本中我们要接受的 (未知的) 信息数量,那些都是我们已经知道的了。而且,随着你阅读数量的增加,知识结构的完善,你的阅读会越来越快。因为,你的知识结构越完善,在下一本书里,你未知的就越少。有人可能提到"知道的越多,未知的越多",那是针对知识总量而言的,而不是指特定的某一本。特定的一本书,你知道的越多,读起来铁定越快。除非,你是在研究,而别人只是在浏览。再回到我沙发上的那些书,精读和粗读。凡是新知识结构,都只能精读,这是没有别的办法的事情;娱乐的、补允细节知识的、学习别人表述方法的,那些读起来就快得多了。读书怎么才能更快?读得多了,就快了。你可能认为这是个悖论,因为你想知道读书快速的方法,就是为了多读书。不是的,你不是想多读书,而是想利用更少的时间读书。这个问题容易答多了:只有现在花时间多读书,以后才能少花时间。再说了,人生苦短,可也够长。你没用在读书上的那些时间打算干什么,打麻将么?--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
--
Sincerely,
YANG Guifu
School of Computer Science and Information Technology
Northeast Normal University
Changchun, P.R.China
----
杨贵福
无不大工。
精读经典,重新开始:《C程序设计语言》句读康德如此闻名,没有人敢慎重地说他写得都是些什么玩意,根本看不懂。但是,一直以来,很多人都提到,康德的著作太难读了,这抱怨还是针对汉译的。《纯粹理性批判》中文版,看着跟德文似的。所幸,邓晓芒先生著有《<纯粹理性批判>句读》,逐句翻译和扩展。这让我满怀希望,也许经过努力,总有一天能够明白。类似受到推崇和抱怨的,还有《C程序设计语言》一书,C和UNIX操作系统的发明人 K&R
两位先生的著作,是最优秀的C语言教科书。我在本科的时候幸运地从学校图书馆借到过这本,薄薄的小册子,讲解清楚明白。虽然我后来又读了很多书,它仍是对我影响最大的和最优秀的书之一。其他的,还有《牛虻》和《计算机解释的构造和解释》。牛的书,重构我们的人生观世界观价值观,或者知识结构,给我们新的生命。我对我的学生,我的学生也对我说过,要精读经典,重读经典,一遍又一遍。每一遍可能都有不同的体悟。贯彻这一原则,很久以来我一直想再次精读此书,并且希望我通读全书的过程能有益于你。所以,我开始录音这个过程,发布在网上。在这个录音中,有我的中文口音、我不认识的单词去查的过程,可能以后,还有你纠正了我的错误,我在以后的某次承认错误免得误导别人和对你的感谢。在这个录音中,还有我通读这本书的每一句,然后像英语精读课那样,划分句子成分,解释一些单词,从英语的语意,到计算机领域中它特殊的含义。还有我的各种猜测。这些过程,你都熟悉。你需要一本书,机械工业出版社 《C程序设计语言》英文版 第2版,作者 Brian W. Kernighan, Dennis M.
Ritchie,2009年3月第1版。其他的版本可能也行,内容也许略有差异。也许,你还需要一支笔,用于标注生词、句子的语法结构,一些知识点。你还需要一些时间,每一次大约45分钟。我会不定期更新,上传,然后在这里通报一下。我需要你的意见,如果你方便和乐意。受我的水平所限,难以保证正确和深入,愿与同样的初学者一起进步;也请大牛们指正,谢谢你帮助我进步。康德在《实践理性批判》中说:"有两样东西,愈是经常和持久地思考它们,对它们日久弥新和不断增长之魅力以及崇敬之情就愈加充实着心灵:我头顶的星空,和我心中的道德律令。"我想,他说的是,道德律令之于人类,就像星空一样真实地存在。可以触摸和感受,不可避免地影响我们,无法逃避。我们来自于它,归结于它。C程序设计语言,也是的。录音在这里,[http://www.tudou.com/programs/view/7uHPX99xDaA/]。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
用邮件分割和传送大文件,python实现 III4. 接收端baoyu4.1 导言和import这部分,是从zhumao.py中抄过来的。1 #! /usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # baoyu, 邮件接收者
5 __usage__ = "usage: %baoyu.py [--help]"
6 __version__ = "baoyu by Young 2012-12-21"
7
8 from optparse import OptionParser
9 import base64
10 import time
11 import sys
12 import poplib
13 import time
14 from email.Parser import Parser
15 from email.header import decode_header
164.2 helper函数们这里是一些在后面的业务逻辑实现中要调用的一些函数。它们在此声明和定义,定义的方式一般应依据动机、目的,而不是根据实现手段。也就是说,使用的词汇应该是分析阶段的词汇。函数被从"后面的业务逻辑"中抽取到这里,可能因为被调用很多次,也可能只调用一次,但是在业务上具有较为鲜明的特征。如果调用很多次,抽取出来的原因之一就是重用,这样可以避免后续维护的时候一旦有修改需求,这个功能相关的很多地方都要修改;如果只调用一次,但是业务特征明显,就是为了信息隐藏,以后或别人读代码的时候要容易一些。根据场合和组织方式的差异,这些函数有不同的称呼。在C++/java中,私有函数基本上实现了这样的功能;在flex/bison及我一时没想起来的很多领域中,它们被称为helper函数。17 ######
18 # helpers
19 ######
20 def getheader(header_text, default="ascii"):
21 """Decode the specified header"""
22 try:
23 headers = decode_header(header_text)
24 header_sections = [unicode(text, charset or default)
25 for text, charset in headers]
26 return u"".join(header_sections)
27 except:
28 return u"".join("invalidated encode")
29上面的代码是从某位貌似日本人的站点上抄来的,它的名字其实不应该叫做getheader,而是"根据charset解码"邮件头或正文。30 def get_msg(which):
31 return "n".join(server.top(which, 1)[1])这是根据 which指定的邮件id号,从邮件服务器上取得对应的邮件,但是不删除。server.top()。详见手册[http://docs.python.org/2/library/poplib.html],"POP3.top(which,
howmuch)"。33 def get_from(msg):
34 email = parser.parsestr(msg)
35 return email.get("From")上述的 pserser 就是 第14行 "from email.Parser import Parser"
中的Parser的实例,在下面的第82行。手册[http://docs.python.org/2/library/email.parser.html]。这个parser是专门用来从邮件中析出邮件头部等各个部分的。第35行,解析出From部分,也就是邮件发送者地址。baoyu.py根据这个来判断某封邮件符合"zhumao-baoyu"协议的发送者部分。这个粗糙的协议包括:发送者、邮件主题、第几封邮件、共几封。其中,发送者和邮件主题作为下载和删除邮件的过滤条件。37 def get_body(which):
38 msg = "n".join(server.retr(which)[1])
39 email = parser.parsestr(msg)
40 return email.get("BODY_START")与第33行开始的函数类似,get_body用于取得which指定的id对应的邮件的body。不同的是,get_body把这封邮件标记为已读。此外,上文提到,我们为了解析方便,在body的开头标记了"BODY_START:",所以此处,body可以视为"BODY_START"部分的值。42 def get_subject(msg):
43 return getheader(parser.parsestr(msg).get("Subject"))还是与第33行开始的函数类似,取主题部分。45 # e.g. [base64-2] 1/2
46 def get_cur_num(subject, subject_prefix):
47 start = subject.find(opt.subject_prefix)+len(opt.subject_prefix)
48 slash = subject.find('/', start)
49 return int(subject[start:slash])51 def get_all_num(subject, subject_prefix):
52 start = subject.find(opt.subject_prefix)+len(opt.subject_prefix)
53 slash = subject.find('/', start)
54 return int(subject[slash+1:])以上两个函数,是从邮件头里取得这是第几个包、一共几个包这两个数据,使用的方法是字符串处理,以"/"分割类似"[base64-2] 1/2"的邮件头部。4.3 命令行解析与发送端zhumao.py的命令行解析类似,解释从略。57 #--------------------------------------------------------------------
58 # 命令行解析
59 p = OptionParser(usage=__usage__, version=__version__, description=__doc__)
60 p.add_option("-F", "--file", dest="filename",
61 help="file need to be saved", metavar="FILE",
62 default="test.out")
63 p.add_option("-P", "--pop", dest="pop",
64 help="pop3 server", metavar="POP3_SERVER",
65 default="pop3.nenu.edu.cn")
66 p.add_option("-u", "--user", dest="user",
67 help="user name", metavar="USER")
68 p.add_option("-p", "--password", dest="password",
69 help="password", metavar="PASSWORD")
70 p.add_option("-f", "--from", dest="fromaddr",
71 help="from whom to be filtered", metavar="FROM",
72 default='[email protected]' )
73 p.add_option("-L", "--subject", dest="subject_prefix",
74 help="the prefix of mail subject as filter",
metavar="subject_prefix",
75 default='[zhumao_baoyu_mail]')
76
77 (opt, args) = p.parse_args()
784.4 准备连接邮件服务器82 parser = Parser()
83 server = poplib.POP3(opt.pop)
84 server.user(opt.user)
85 server.pass_(opt.password)
86 server.set_debuglevel(0)
87 sleep = 0.1
88 count = server.stat()[0]
89 d = dict()使用pop3接收,各种参数设置。第88行,取得stat命令时的邮件数量,即未读邮件数量。第89行,初始化一个字典 (映射)。后面准备把第1封邮件放到"1"的值里面,第2封邮件放到"2"的值里面,依此类推。这样,在拼邮件的时候,可以按key排序。4.5 接收邮件检查邮件,根据邮件头过滤,下载并删除符合要求的邮件,显示接收百分比。从第90行到第107行,是一个循环,用于遍历所有邮件,并在第103行当查找到所有符合要求的邮件 (数量达到要求)以后跳出循环。90 for i in xrange(1, count, 1):
91 current = get_msg(i)调用helper函数 get_msg,取得id为i的邮件 (的邮件头和body第一行) 。92 if (get_from(current).find(opt.fromaddr) != -1 and
93 get_subject(current).find(opt.subject_prefix) != -1):
94 b = get_body(i)如果邮件的发送者符合要求 (比如 [email protected]) ,并且主题的prefix也符合要求 (比如 [base64-2]),取整封邮件。如果不过滤直接在遍历的时候取整封邮件,因为邮件数量众多,带附件的邮件又很大,性能会比较低。而仅遍历邮件头,对网络带宽就没有那么高的要求了。95 print '+-------------------------'
96 print '|' + str(i)+' '+ get_subject(current)
97 # print '|' + b
98 print '+-------------------------'显示进度,避免用户着急。99 current_seq = get_cur_num(get_subject(current), opt.subject_prefix)
100 all_number = get_all_num(get_subject(current),
opt.subject_prefix)调用helper函数,取得当前是这一文件的第几包邮件 和 一共几包邮件。一共几句邮件,数值在遍历中一直不会变,但是重复计算了很多次。101 print (str(current_seq) +'/'+ str(all_number))再显示进度,第几封,共几封。102 d [current_seq] = b把第N封邮件放到字典键N的位置。参见前面提到的第89行,这里是向字典中插入数据。103 if len(d) >= all_number :
104 break
106 else:
107 print 'filtered out: '+str(i)+'/'+str(count)+'
'+get_subject(current)如果把这个文件对应的所有邮件都已下载完毕,跳出循环;否则的话,也告诉用户一声,这封邮件不符合条件,不然出现大量不符合条件的邮件时,用户看到的是程序假死。109 server.quit()收完邮件,关闭连接,保持优雅。4.6 合并文件111 # 合并文件
112 s=""
113 for k in xrange(1, all_number+1, 1):
114 s += d[k]
115接key的顺序遍历字典d,把对应的值拼接在一起。这个对应的值来自第102行的插入,此处是取出数据。字典d综上所述,在第89行初始化,在第102行插入数据,在第114行读取使用。如果不用字典,而使用一个链表,以下标代替key,也可以。4.7 解码文件我们拼接出来的文件是base64编码的,所以需要解码,然后写出。116 # 解码文件
117 s = base64.standard_b64decode(s)
118
119 file = open (opt.filename, "w")
120 file.write(s)
5. 回顾数据流发送端的数据流为: 文件binary -> 读入文件 -> base64编码 -> cut -> smtp.接收端的数据流为:pop3 -> merge -> base64解码 -> 写出文件 -> 文件binary。如果思想的传递,也能无误地这样传输,该有多好。6. 进一步的工作还有很多进一步的工作可以做,让这个协议及应用程序更好一些。比如,加错误检校,指定重传错误的包而不是全部重传,由baoyu访问zhumao的共享目录并指定下载某个文件,不使用SMTP/POP3而是通过论坛的贴子传递信息。还可以在传送前加压缩 (不过对于视频和音频,没啥意义)。还可以用这种隧道做成反向代理……未来有无数种可能。可能这正是人生的迷人之处,如果今天就能看到明天及所有以后的日子,那还有什么希望可言。完整代码在这里 [http://my.csdn.net/my/code/detail/33574] 和
[http://my.csdn.net/my/code/detail/33573].--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
用邮件分割和传送大文件,python实现 II3. 软件的使用过程下面这段,是软件写完以后运行的效果,不过,在软件开始写以前,它的样子就已经在我的心中。用个去年还是前年流行然后就消声匿迹的词来形容,软件在写第一行代码以前,就应该有个"愿景"。
以下,以发送191字节的 test.in
为例,分成3个包,每包100字节。从[email protected]发出,发给[email protected]。每包100字节是参数的默认值指定的。3.1. 发送方zhumao~/running/zhumao-baoyu-mail $ python zhumao.py -f [email protected] -t
[email protected] -L "[test-in]" -p "mypass***" -F test.inTo:[email protected] From: [email protected] Subject:[test-in] 1/3sent.To:[email protected] From: [email protected] Subject:[test-in] 2/3sent.To:[email protected] From: [email protected] Subject:[test-in] 3/3sent.3.2 接收方baoyu~/running/zhumao-baoyu-mail $ python baoyu.py -u [email protected] -p
"mypass***" -L "[test-in]" -f [email protected] -F test.out
+------------------------- |1 [test-in] 3/3 +-------------------------
3/3 +------------------------- |2 [test-in] 2/3
+------------------------- 2/3 +------------------------- |3 [test-in]
1/3 +------------------------- 1/3以上接收过程可以看到,一共3包,第3包的接收早于第2包,早于第1包。用diff对比发送和接收到的文件,一致。~/running/zhumao-baoyu-mail $ diff test.in test.out
~/running/zhumao-baoyu-mail $
3.3. 手册,帮助$ python zhumao.py --help Usage: %zhumao.py [--help]Options: --version show program's version number and exit -h, --help
show this help message and exit -F FILE, --file=FILE file need to be
sent -S SMTP_SERVER, --smtp=SMTP_SERVER smtp server -f FROM,
--from=FROM mail sender -p PASSWORD, --password=PASSWORD password -t
TO, --to=TO mail receiver -s SIZE, --size=SIZE size of each mail -L
subject_prefix, --subject=subject_prefix the prefix of mail subject$ python baoyu.py --help Usage: %baoyu.py [--help]Options: --version show program's version number and exit -h, --help
show this help message and exit -F FILE, --file=FILE file need to be
saved -P POP3_SERVER, --pop=POP3_SERVER pop3 server -u USER,
--user=USER user name -p PASSWORD, --password=PASSWORD password -f
FROM, --from=FROM from whom to be filtered -L subject_prefix,
--subject=subject_prefix the prefix of mail subject as filter4. 发送方zhumao以下是发送方zhumao.py的代码及讨论。希望能为像我一样的初学者带来启发的同时,渴望熟悉python什么的大牛们指导和批评我代码的各种错误,一方面我求进步,另一方面也免得我误导别人。谢谢啦。这两天又访问不了github了,所以暂时没传上去。各位将就着看吧。不连续的行号,是空行,我解释的时候略过了。4.1 基本相当于导言1 #! /usr/bin/python 2 # -*- coding: utf-8 -*- 3 4 # zhumao,邮件发送者第1行,注释,指定脚本解释器。这和shell程序设计是一个路子。第2行,注释,文件编码。祖国尚未统一世界,看来各种编码的乱像还会继续相当长时间。5 __usage__ = "usage: %zhumao.py [--help]" 6 __version__ = "zhumao by
Young 2012-12-21"我照抄的,看效果是显示使用方法。这个实现有意思,方便程序员与用户沟通啊。增加一点方便,估计就多几个百分比的程序员实现这一功能。8 from optparse import OptionParser 9 import smtplib 10 import base64
11 import time 12 import sys我猜就是 C里的include,猜的。还有名字空间、模块这样的作用。from的作用,似乎是使得模块中的符号名在当前作用域可见。这些模块是后面的代码要用到的。4.2 命令行解析这里使用了8 from optparse import OptionParser中指定的模块,第15行中的p是个OptionParser实例。在第16行以后,调用实例的方法
p.add_option。这些参数,基本可以根据出现的顺序、内容,与上述"愿景"对比,猜出来含义。不赘述。14 # 命令行解析15 p = OptionParser(usage=__usage__, version=__version__,
description=__doc__) 16 p.add_option("-F", "--file", dest="filename",
17 help="file need to be sent", metavar="FILE", default="test.in") 18
p.add_option("-S", "--smtp", dest="smtp", 19 help="smtp server",
metavar="SMTP_SERVER", default="smtp.nenu.edu.cn") 20 # help="smtp
server", metavar="SMTP_SERVER", default="smtp.gmail.com") 21
p.add_option("-f", "--from", dest="fromaddr", 22 help="mail sender",
metavar="FROM") 23 p.add_option("-p", "--password", dest="password",
24 help="password", metavar="PASSWORD") 25 p.add_option("-t", "--to",
dest="to", 26 help="mail receiver", metavar="TO") 27
p.add_option("-s", "--size", dest="size", 28 help="size of each mail",
metavar="SIZE", default=100) 29 p.add_option("-L", "--subject",
dest="subject_prefix", 30 help="the prefix of mail subject",
metavar="subject_prefix", default='[zhumao_baoyu_mail]') 31 32 (opt,
args) = p.parse_args()到这里为止,命令行参数 (及其默认值)就已经成为p的成员了。后面这样引用,比如: opt.smtp。第32行,这个返回值对C程序员来说,看起来有点奇特。手册[http://docs.python.org/2/library/optparse.html]说"parse_args() returns two values:options, an object containing values for all of your options—e.g. if
--file takes a single string argument, then options.file will be the
filename supplied by the user, or None if the user did not supply that
option args, the list of positional arguments leftover after parsing
options"4.3 输入文件34 # 输入文件35 file = open (opt.filename, "r") 36 s = file.read()第35行,opt.filename是从命令行中解析出来的,在我们的"愿景"中,就是test.in。open,
read,这样的写法,容易望文生义,而且似乎也对,不赘述。执行完这段以后,文件的内容全在s中了。4.4 编码文件38 # 编码文件39 s = base64.standard_b64encode(s) 40 41 ## sys.stdout.write(s)第39行,使用了 base64编码 字符串s,编码的结果再赋值给s。第41行是我写程序的时候用来输出测试的。4.5 准备发送,登录43 # 准备发送,登录44 sleep = 1 45 to = opt.to 46 user = opt.fromaddr 47 pwd
= opt.password 48 smtp = opt.smtp第44行,准备每发送一包睡一秒。根据你用的SMTP服务器对你的坏人判断有多严格,你可以调整sleep的值。从第45行至第48行,从命令行解析的结果中得到 发给谁、发送者、SMTP发送者的口令、SMTP服务器地址。49 smtpserver = smtplib.SMTP(smtp) 50 # smtpserver =
smtplib.SMTP(smtp, 587) # for gmail 51 smtpserver.ehlo() 52
smtpserver.starttls() 53 smtpserver.ehlo 54 smtpserver.login(user,
pwd)第49行使用smtplib,构造出smtpserver实例。如果用的是gmail,端口需要指定为587。从第51行到第54行,根据你选的smtp服务器的要求决定对它说些啥。我的smtp服务器要求先
扩展的hello,然后tls架密,然后再问候一次,然后登录。如果不知道应该说些啥,可以用thunderbird登录一次,用sniffer看一下正确的步骤。4.6 拆分-标记-发送麻烦的地方到了。4.6.1 拆成56 # 折分文件57 end = len(s) 58 for i in xrange(0, end, opt.size): 59 if
i+opt.size < end : 60 current = s[i:i+opt.size] 61 else: 62 current =
s[i:]python的for循环语法,我老是忘。希望这回能记住。"for 变量 in 待遍历的东西 : "。这里,待遍历的东西是一个数据范围,用xrange生成,从0开始,到end结束,步进为 opt.size。在循环体中--这也是python有意思的一个地方,缩进是语法要求,而不仅是为了美观--如果没有到最后一包,当前的这包就是字符串切割出来的。s[i:i+opt.size]表示切割s,从
i 切到 i+opt.size;如果不是最后一包,从i切到结尾,写作 s[i:]。python切割字符串的方法,还真是有C的风格,把字符串当成纯粹的容器/数组看待。4.6.2 标记还在循环里。63 # 标记64 subject = opt.subject_prefix + ' '
+str(i/opt.size+1)+'/'+str(end/opt.size+1) 65 header = 'To:' + to +
'n' + 'From: ' + user + 'n' + 'Subject:' + subject +' n' 66 current
= 'BODY_START:' + current + 'n' + 'BODY_END:NOTHINGGOESHERE' 67 print
68 print header第64行,生成主题subject,第65行,生成邮件头header,第66行,生成正文。第67和第68行,不是为了调试,而是为了避免用户在长时间切割的时候不知道跑了多远,还剩多远。这里输出的东西就是下面这段:To:[email protected] From: [email protected] Subject:[test-in] 2/3sent.其中,主题里的 [test-in]
是加的标记,包师弟接收的时候可以用这个标记过滤出我们特别的邮件。太阳底下无新鲜事,大毅同学提到在cisco设备中,vlan/trunk也使用了类似的方法做标记tag。后面的2/3表示共3包,这是第2包,用来在baoyu接收端拼接文件的时候作为顺序的依据,也用来显示出来,避免包师弟了解下载了多少,还有多少没下载。4.6.3 发送还在循环里。69 #发送70 msg = header + current 71 smtpserver.sendmail(user, to, msg)
72 print 'sent.' 73 time.sleep(sleep) 74 75 smtpserver.close()第70行,把邮件头和邮件正文拼在一起。这看起来是很天真的做法,邮件头和正文就这么就拼一起了啊?是的,是SMTP还是什么协议,就是这么规定的。好像head和body中间还有个回车。第71行,发送出去了。第72行,避免用户心急,程序把邮件发出去了要告诉用户一声。第73行,前面提到了,睡一下,避免SMTP服务器认为我们是发送垃圾邮件的坏人。第75行,离开循环,邮件都发送完了,断开连接。做事要有始有终,保持优雅。明天,或者后天,讨论一下接收端baoyu.py。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
两张图片:Visual Studio DSL工具特定领域开发指南 笔记精读了《Visual Studio DSL工具特定领域开发指南》,写了笔记,画了图。拖
了几天,估计还是没时间整理笔记。以下两张图片,权当笔记了吧。
--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
耳机收纳制作没有耳机听电话的时候耳机疼,有耳机呢,耳机线老是卷在一起。所以我用麦当劳的优惠卡做了一个耳机收纳,把线缠上面。用了几天,效果不错。我得意地掏出DIY的耳机收纳,鞠孙谷三位同学说,"你网上买的啊。"我说,"不是啊,我做的。"又问,"你了网上以后做的啊"。我说,"不是,独立创造的。"我又得意地掏出DIY的耳机收纳,关郑两位同学说,"你网上买的啊。"我说,"不是啊。为什么你们也这么说。"他俩说,"因为网上有卖的,而且巨便宜,种类也多。"我搜了下,真是不少,做成各种可爱卡通的。买了几种试用,都不咋地。重要原因是,它们都太小,耳机线缠很多圈,打开的时候费劲。不过,它们提供了很好的设计方案,比如都有个小孔,耳机线进去容易出来难。所以,我就照些改良了我原来的设计。变成这样。所用工具如图所示。缠上以后的效果。对比的产品。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
用邮件分割和传送大文件,python实现 I1. 限制和解决方案经常有人替我国导演和科幻作者们叫屈,说这样的环境怎么能出好作品呢;也经常有人为自己叫屈,类似他有这样的父母环境怎么能成才呢。不过,我看过一个故事,说法略有不同,名字忘了,应该还是个名篇。故事里说,有个家伙因为被抢劫,捆得很结实,而又刚刚好能动弹一点,能一跳一跳地走。他被救以后,发现能演小丑什么的,留在马戏团工作。因为绳子约束,力量更大,而且能做很多原来完不成的动作。最后,老板想杀他放出狼来,他做好准备放手一搏,觉得胜券在握。老板娘一刀把他身上的绳子割了,喊"那谁,你快跑啊。"然后就没有然后了。这哥们离了绳子啥也不是,后来是不是被狼咬死,我就忘了。这个故事告诉我,限制从来不一定是致命的阻碍,有时更可能是个磨砺人的挑战。包师弟和ZHUMAO聊,说到某单位的网络真是不咋地,下载居然要收费,不过有个漏洞。包师弟说,这个漏洞就是下载邮件的流量不算钱。这倒是也合理,不然就往网络中心或领导的信箱里成天发大附件就行了。同时,从原理上也说得过去,SMTH的时候,不是我乐意的,相当于接听电话不收费;而POP3的时候,已经是内网了。ZHUMAO说,这个漏洞可用。他提到,先把大文件切成几份,然后用邮件发给包师递,包师弟根据一定条件收邮件,然后拼起来。我说:你们应该用PYTHON整。ZHUMAO说:对,你整吧。于是我就整了。没有写容错部分,一共197行,拿出来讨论一下。2. 整体框架整个软件分成两部分,是两个.py文件。一个是发送文件用的,名字叫 zhumao.py,另一个是收文件用的,名字叫 baoyu.py。2.1 zhumao.py发文件的zhumao要顺序执行这样一些操作:* 编码文件用base64或可打印字符,因为邮件是ASCII文本的,而大部分二进制文件都有ASCII控制字符,比如电影。之所以编码,另一个原因是我不想使用附件,实现的时候更麻烦一些,以后也可以改成用附件。* 拆分文件把文件拆成定长的几段,比如10K一段,然后再发送。最后一段可能稍微短一些。* 标记及百分比,发送在邮件的subject上做标记,比如 [来自zhumao,好片子] 这样包师弟接收的时候过滤邮件更容易一些。然后找个SMTH邮件服务器发出去。* 避免被服务器视为垃圾邮件发送者邮件服务器可能会因为你一直发一直发认为你是恶意的,所以发一会要 sleep一会儿。对软件性能的影响,就是没有办法的事了。2.2 baoyu.py收文件这一端,要执行相反的操作,即顺序执行:* 检查用POP3检查所有的邮件头。* 根据标记过滤,下载并删除把符合条件的邮件,比如 [来自zhumao,好片子],下载下来,从服务器端删除。在这里,以后应该支持错误检校,出错重传。现在还没有支持,作为原型,就算对付吧,如果1G文件中间有一个坏的,就得重传全部。* 合并文件把文件从邮件body中析出来,然后拼成编码的文件。有些邮件服务器会在subject 之后加上乱糟的东西,比如 anti-spam
之类的,这破坏了一个通常的假设,即subject之后一行以后全是正文。这导致析出文件稍微麻烦一些。我为了实现简单,在body的最前面加了标记,后面也加了标记。反正邮件不是用人手,而是用zhumao.py发出的,所以这一部分可以视为
zhumao-baoyu 协议。* 解码文件把ascii文件解码为binary。* 接收百分比还要显示接收了多少。同时,因为邮件到达顺序可能与发送的不同,所以zhumao.py在发送的时候还在 subject 中还加入了共几包,当前这封邮件是第几包。2.3 实现列出上述框架以后,我先写zhumao.py,用 thunderbird 和 gmail 检验发送的内容;然后再写
baoyu.py,此时用已经实现的zhumao.py发送测试用例。因为我不熟悉python,很多语法和底层的机制 (如分割字符串)
,都是一边写一边查的。估计有更优雅的实现方案,不过那就不是我这样的初学者能提供的了。所以,大牛们读到此处,已经可以评判 zhumao-baoyu 方案了。初学者们请明天再来,我们继续一起学习吧。此外,这个zhumao-baoyu草稿在计算机网络中也可以视为 smtp-pop3 协议基础上实现的文件传递协议,还可以扩展更多的功能,比如
baoyu 要求列出 zhumao端 提供的文件目录,选择文件下载。在协议之上建立新的协议,VPN中的l2tp、WAN口连接使用的
PPPoE,都与此类似,称为隧道协议。在隧道协议中,表面上我们谈论的是一件事情,而实际上,我们真正想传递的,往往另有深意。就像年终岁尾,大家喝酒的时候,逼你喝酒的那些人,他表达的是:"你应该表达臣服于我,低个头啥的。"请脑补雄性大猩猩拍胸脯的动作。突然想起来北京土著喜欢自称为"爷"的习惯,还有四川土著喜欢口头对别人的"婆娘"不敬这两件事,他们可能还会解释为"啊呀,我就是习惯了,没有恶意。"明知对方的感受,不郑重道歉的就是恶意。坏习惯是病,如果能改就改,如果不能改,就得治。我对四川同学说过,你说别人的媳妇啥都行,对我得例外。期待机会哪天对哪位北京同学喊一嗓子,你TM是谁的爷。终于还是跑题了。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]
Linux shell脚本,Linux下的西红柿时间管理法 IV续 清理本来以为三次就写完了,用了几天这两个脚本,发现了一点问题,所以还得再说
两句。希望这次就真的结束了。我习惯不用计算机的时候,扣上盖,然后机器休眠。这个习惯与上述西红柿时间
管理结合在一起产生了一个问题:at任务还在继续,再唤醒机器的时候,时间管
理还在继续,可能正进行到第5分钟,也可能是第12分钟,而我希望重新计时。重新计时也很简单,再执行个20.sh就行了。这么做带来的问题是,这个新的时间
管理起始点建立了,旧的却没有清除掉,所以可能过不了几分钟,旧的休息时间
就到了。清除掉旧的任务也容易。比如执行 atq 显示当前的任务为:~ $ 20.sh
~ $ atq
3890 Mon Dec 17 21:31:00 2012 r young
3891 Mon Dec 17 21:32:00 2012 r young3890和3891就是当前的两个任务。清除的命令是:~ $ atrm 3890; atrm 3891
~ $ atq
~ $任务果然清理干净了。但是每一次都要atq,然后去读那两个任务号,然后再atrm,挺麻烦的。所以,有
了下述脚本,用于清理旧的时间管理任务。代码如下:1 #!/bin/bash
2
3 task=$(atq -q r | cut -f1 )
4 if [ -z "$task" ]; then
5 echo "No task in queue r."
6 exit 0
7 fi
8
9 for t in $task
10 do
11 atrm $t
12 done第3行,用atq显示任务列表,然后管道给cut,得到第1列,也就是任务号,看起
来的效果就是:3890
3891这些数据赋值给了变量 task。第9行,遍历数组task,对于其中的每个变量 t ,应用atrm操作,相当于:atrm 3890
atrm 3891这样,每当我开机的时候,不必再atq看是否有任务,然后再记住任务号什么的,
只要执行 clear_at.sh,旧的任务就清理掉了。既往不咎,一切重新开始。--------------------博客会手工同步到以下地址:[http://giftdotyoung.blogspot.com][http://blog.csdn.net/younggift]