-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.json
More file actions
1 lines (1 loc) · 164 KB
/
content.json
File metadata and controls
1 lines (1 loc) · 164 KB
1
{"meta":{"title":"Mi Tang","subtitle":"匠子生活","description":"生活简单 快乐不难","author":"fish·nut","url":"http://lpbobo.com"},"pages":[{"title":"About","date":"2016-05-07T15:03:03.000Z","updated":"2015-09-15T15:09:26.000Z","comments":true,"path":"About/index.html","permalink":"http://lpbobo.com/About/index.html","excerpt":"","text":"this is lp and bobo’s land."}],"posts":[{"title":"论语(11)","slug":"论语(11)","date":"2016-06-18T14:36:00.000Z","updated":"2016-06-18T14:47:59.000Z","comments":true,"path":"2016/06/18/论语(11)/","link":"","permalink":"http://lpbobo.com/2016/06/18/论语(11)/","excerpt":"为政篇第二 2.21或谓孔子曰:“子奚不为政?”子曰:“《书》云:‘孝乎惟孝,友于兄弟,施于有政。’是亦为政,奚其为为政?”","text":"为政篇第二 2.21或谓孔子曰:“子奚不为政?”子曰:“《书》云:‘孝乎惟孝,友于兄弟,施于有政。’是亦为政,奚其为为政?” 义:孔子表达个人是否为官并不重要,重要的在于个人以孝来齐家,流风所及而化育万物,使全国上下形成孝的风气。 2.22子曰:“人而无信,不知其可也。大车无輗,小车无軏,其何以行之哉?” 音:无輗(ní),无軏(yuè) 义:孔子教育学生要忠信笃敬 2.23子张问:“十世可知也?”子曰:“殷因於夏礼,所损益,可知也;周因於殷礼,所损益,可知也。其或继周者,虽百世,可知也。”” 义:古代30年为一世,孔子历来不反对变革,但是一切变革都是在既有的基础上进行的,是有迹可寻的,孔子在这里还提出了“损益”的概念,即增减。 2.24子曰:“非其鬼而祭之,谄也。见义不为,无勇也。”","categories":[],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(10)","slug":"论语(10)","date":"2016-06-16T14:13:00.000Z","updated":"2016-06-16T14:21:24.000Z","comments":true,"path":"2016/06/16/论语(10)/","link":"","permalink":"http://lpbobo.com/2016/06/16/论语(10)/","excerpt":"为政篇第二 2.18 子张学干禄。子曰:“多闻阙疑,慎言其余,则寡尤。多见阙殆,慎行其余,则寡悔。言寡尤,行寡悔,禄在其中矣。”","text":"为政篇第二 2.18 子张学干禄。子曰:“多闻阙疑,慎言其余,则寡尤。多见阙殆,慎行其余,则寡悔。言寡尤,行寡悔,禄在其中矣。” 义:子张请教求得官职的方法。孔子说:“多听,把不明白的事情放到一边,谨慎的说出那些真正懂得的,就能少犯错误;多观察,不明白的保留在心中,谨慎的实行真正懂得的,就能减少懊悔……” 2.19 哀公问曰:“何为则民服?”孔子对曰:“举直错诸枉,则民服;举枉错诸直,则民不服。” 义:直,正直的人;枉,邪曲 2.20 季康子问:“使民敬、忠以劝,如之何?”子曰:“临之以庄,则敬;孝慈,则忠;举善而教不能,则劝。”","categories":[],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(9)","slug":"论语(9)","date":"2016-06-15T14:33:00.000Z","updated":"2016-06-15T14:38:30.000Z","comments":true,"path":"2016/06/15/论语(9)/","link":"","permalink":"http://lpbobo.com/2016/06/15/论语(9)/","excerpt":"为政篇第二 2.15 子曰:“学而不思则罔,思而不学则殆”","text":"为政篇第二 2.15 子曰:“学而不思则罔,思而不学则殆” 义:学习而不思考就会迷惘无所得,思考而不学习就会疑惑不解 2.16 子曰:“攻乎异端,斯害也已” 义:过和不及都是祸害 2.17 子曰:“由!诲女,知之乎?知之为知之,不知为不知,是知也”","categories":[],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(8)","slug":"论语(8)","date":"2016-06-14T12:57:09.000Z","updated":"2016-06-14T13:06:49.000Z","comments":true,"path":"2016/06/14/论语(8)/","link":"","permalink":"http://lpbobo.com/2016/06/14/论语(8)/","excerpt":"为政篇第二 子曰:“君子不器”","text":"为政篇第二 子曰:“君子不器” 义:孔子认为君子应该为通才,博学多能 子贡问君子。子曰:“先行其言而后从之。” 义:对于要说的话,先做到了,再说出来。 子曰:“君子周而不比,小人比而不周。” 义:周,普遍也;笔,偏党也","categories":[],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(7)","slug":"论语(7)","date":"2016-06-13T14:27:00.000Z","updated":"2016-06-13T14:49:01.000Z","comments":true,"path":"2016/06/13/论语(7)/","link":"","permalink":"http://lpbobo.com/2016/06/13/论语(7)/","excerpt":"为政篇第二 2.9 子曰:“视其所以,观其所由,察其所安。人焉廋哉?人焉廋哉?”","text":"为政篇第二 2.9 子曰:“视其所以,观其所由,察其所安。人焉廋哉?人焉廋哉?” 音:“廋”,sōu,隐藏 义:看一个人的所作所为,考察他初始的动机,了解他心安于什么事情。那么,这个人的内心怎能掩盖的了呢? 2.10 子曰:“吾与回言终日,不违,如愚。退而省其私,亦足以发,回也不愚。” 义:“我整天对颜回讲学,他从不提出什么反对意见,像个蠢人。等他退下,我观察他私下里同别人讨论时,却能发挥我所讲的,可见颜回他并不愚笨呀” 颜回,大智若愚 11.子曰:“温故而知新,可以为师矣。”","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(6)","slug":"论语(6)","date":"2016-06-12T13:01:00.000Z","updated":"2016-06-12T13:30:45.000Z","comments":true,"path":"2016/06/12/论语(6)/","link":"","permalink":"http://lpbobo.com/2016/06/12/论语(6)/","excerpt":"为政篇第二 2.5 孟懿子问孝。子曰:“无违。”樊迟御,子告之曰:“孟孙问孝于我,我对曰:‘无违。’”","text":"为政篇第二 2.5 孟懿子问孝。子曰:“无违。”樊迟御,子告之曰:“孟孙问孝于我,我对曰:‘无违。’”樊迟曰:“何谓也?”子曰:“生,事之以礼;死,葬之以礼,祭之以礼。” *义:无违,不要违背礼节 2.6 孟武伯问孝。子曰:“父母唯其疾之忧。” *义:孟武伯是上文孟懿子的儿子 2.7 子游问孝。子曰:“今之孝者,是谓能养。至于犬马,皆能有养;不敬,何以别乎?” *义: 2.8 子夏问孝。子曰:“色难。有事,弟子服其劳;有酒食,先生馔,曾是以为孝乎?” *《礼记·祭义》:孝子之有深爱着必有和气,有和气者必有悦色,有悦色者必有婉容。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(5)","slug":"论语(5)","date":"2016-06-11T04:35:00.000Z","updated":"2016-06-11T05:10:48.000Z","comments":true,"path":"2016/06/11/论语(5)/","link":"","permalink":"http://lpbobo.com/2016/06/11/论语(5)/","excerpt":"为政篇第二 子曰:“为政以德,譬如北辰,居其所而众星共之”","text":"为政篇第二 子曰:“为政以德,譬如北辰,居其所而众星共之” 音:“共”通“拱” 子曰:“《诗》三百,一言以蔽之,曰:‘思无邪’。” 义:敝,概括;思无邪,思想纯正。 子曰:“道之以政,齐之以刑,民勉而无耻;道之以德,齐之以礼,有耻且格。” 陆陇《松阳讲义》:操术不同,功效各异。路头一差,而风俗由之而殊,气运由之而变,不可不辨也。 义:法制以惩罚性手段使人心存畏忌,免于惩罚;而礼治德政却使人心悦诚服,顺应了人的廉耻之心,可以教会打字纠正自己的错误。 子曰:“吾十有五而志于学,三十而立,四十而不惑,五十而知天命,六十而耳顺,七十而从心所欲,不逾矩。” 音:“有”通“又” 义:立:立身处世;耳顺:对于外界的一切相反相异、五花八门的言论,能分辨真伪是非,并听之泰然;可以随心所欲的说话,不会超越规矩。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(4)","slug":"论语(4)","date":"2016-06-10T02:01:00.000Z","updated":"2016-08-04T07:20:53.000Z","comments":true,"path":"2016/06/10/论语(4)/","link":"","permalink":"http://lpbobo.com/2016/06/10/论语(4)/","excerpt":"学而篇第一 1.10 子禽问于子贡曰:夫子至于是邦也,必闻其政,求之与,抑与之与?”子贡曰:“夫子温、良、恭、俭、让","text":"学而篇第一 1.10 子禽问于子贡曰:夫子至于是邦也,必闻其政,求之与,抑与之与?”子贡曰:“夫子温、良、恭、俭、让以得之。夫子之求之也,其诸异乎人之求之与?” 音:“抑”:还是,反语词;其诸:大概,不太确定的语气助词 义:温和、善良、恭敬、节俭、谦让 感:与人相处不强求,好好做到这些 1.11 子曰:“父在,观其志。父没,观其行。三年无改于父之道,可谓孝矣。” 感:对父母的观点,即使不正确,也要尊重。虽然现在做子女的有很多辩证的观点,但父母作为最亲的人,初衷是善意的,观点往往是经验和立场的不同长期总结来的,无需过分辩驳,给予父母尊重是每个子女最基本的孝心。 1.12 有子曰:“礼之用,和为贵。先王之道,斯为美。小大由之,有所不行;知和而和,不以礼节之,亦不可行也。” 义:礼在于处事和顺,从前圣明君主治理国家,最可贵的地方就在这里。无论大小事,都按照这个观点处理。如果遇到不能解决的问题,仍一味追求和顺,不用礼节管理它,也是不可取的。 感:“礼制”是一种自发性的,需要全民参与的,需要大环境熏染的;如今的“法制”更多的强调了个体,却确实了很多温度。 1.13 有子曰:“信近于义,言可复也;恭近于礼,远耻辱也;因不失其亲,亦可宗也。” 音:“远”yuàn,远离 义:符合道义的约定,才可以实现;符合礼仪的恭敬,才能远离耻辱,倚靠的都是亲密的人,也就可靠了 感:前半段是交友待人的方式,后半段不是很赞同了,或者说在一定层面上,很多成功的人士,或者说企业家都在遵循这个定律,但是就年轻人而言,我更喜欢趣味相投的朋友,更喜欢与可以互相理解,有共鸣的人相处。 1.14 子曰:“君子食无求饱,居无求安,敏于事而慎于言,就有道而正焉,可谓好学也已。” 感:孔子定义的好学 1.15 子贡曰:“贫而无谄,富而无骄,何如?”子曰:“可也。未若贫而乐,富而好礼者也。”子贡曰:《诗》云,‘如切如磋!如琢如磨’,其斯之谓与?”子曰:“赐也!始可与言《诗》已矣,告诸往而知来者。” 义:贫穷而不谄媚,富贵而不傲慢;不如贫穷却乐于道,富贵却谦虚好礼 感:能做到子贡说的程度已经很厉害了,孔子的标准能做到的寥寥无几 1.16 子曰:“不患人之不已知,患不知人也。” 义:不要担心别人不了解自己,应该担心的是自己不了解别人 感:期待别人做什么自己是很无力,将主动权掌握在自己手中,或者说自省、自行多一些,天真的期待少一点。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(3)","slug":"论语(3)","date":"2016-06-07T13:33:00.000Z","updated":"2016-06-10T02:05:35.000Z","comments":true,"path":"2016/06/07/论语(3)/","link":"","permalink":"http://lpbobo.com/2016/06/07/论语(3)/","excerpt":"学而篇第一 1.7 子夏曰:“贤贤易色;事父母,能竭其力;事君,能致其身;与朋友交,言而有信。虽曰未学,吾必谓之学矣”","text":"学而篇第一 1.7 子夏曰:“贤贤易色;事父母,能竭其力;事君,能致其身;与朋友交,言而有信。虽曰未学,吾必谓之学矣” 义:孔子育人注重人的品质德行修养,其次才是文化知识 感:“世事洞明皆学问,人情练达即文章”——《红楼梦》 1.8 子曰:“君子不重则不威,学则不固。主忠信。无友不如己者。过则无惮改” 音:“无”通“毋”wú;惮 dàn 义:一个人内心的端正庄严会反映到气质容颜上,神态庄重,使人更加信服;故有人比自重而后人重之,人必自侮而后人侮之 感:精神状态,外貌整洁,能够从环境上、气场上帮助自己 1.9 曾子曰:”慎终追远,民德归厚矣” 义:孔子思想中,孝是修身基础,忠是孝的延续。孔子不信鬼神,看中的是礼仪来实行教化。 感:有些时候,很多场合,许多文化,形式或者说仪式确实可以给人一些不一样的感触。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(2)","slug":"论语(2)","date":"2016-06-06T13:44:00.000Z","updated":"2016-06-06T13:50:57.000Z","comments":true,"path":"2016/06/06/论语(2)/","link":"","permalink":"http://lpbobo.com/2016/06/06/论语(2)/","excerpt":"学而篇第一 1.4 曾子曰:“吾日三省吾身:为人谋而不忠乎?与朋友交而不信乎?传不习乎?”","text":"学而篇第一 1.4 曾子曰:“吾日三省吾身:为人谋而不忠乎?与朋友交而不信乎?传不习乎?” 音:zēng ; xǐng ; chuán 义:“忠”在于“尽”,“信”在于“不欺”,“习”在于“持”。 1.5 子曰:“道千乘之国,敬事而信,节用而爱人,使民以时” 音:“道”通“导”,dǎo,千乘shèng 义:敬事、信、节、爱、不误农时。 感:敬事而信、节用是对自己的约束,爱人、不误时节是对别人的善用;严于律己、知人善用。 1.6 子曰:“弟子入则孝,出则弟,谨而信,泛爱众,而亲仁,行有余力,则以学文。 音:“弟”通“悌”, 义:在家孝顺父母,在外尊敬师长,说话谨慎,言而有信,与众多人有爱相处,躬亲仁行,做到如此仍有经历,再学习古代典籍。 感:行动、环境是影响人性的首要要素,最真切的渲染比书本典籍来的要切身的多,想要完善自己,找些好的朋友相处,找些正能量的环境生活,以书本为辅,让行动先行。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"论语(1)","slug":"论语(1)","date":"2016-06-05T14:00:00.000Z","updated":"2016-06-07T13:58:17.000Z","comments":true,"path":"2016/06/05/论语(1)/","link":"","permalink":"http://lpbobo.com/2016/06/05/论语(1)/","excerpt":"说在前面现在回想起去年决定要学习或者说拜读论语的理由,貌似是去年大胖胖生日问他要什么礼物,人家随口一句“送我本论语吧”。自己想想觉得没什么心意(人家准备礼物还是很用心的^.^),所以决定要不就直接送到脑袋里去吧","text":"说在前面现在回想起去年决定要学习或者说拜读论语的理由,貌似是去年大胖胖生日问他要什么礼物,人家随口一句“送我本论语吧”。自己想想觉得没什么心意(人家准备礼物还是很用心的^.^),所以决定要不就直接送到脑袋里去吧,想着一天一句论语总记得住吧,所以就是接下来上班下班抽查胖胖同学有没有背会,还曾一度被胖同学戏称“小于先生”,“哈哈,不敢不敢当”。至于有没有必要,不做讨论了,几千年沉淀下来的,尽管有不符合时代要求的部分,还是值得我们用虔诚和敬畏的心去膜拜的。 至于有没有坚持下来,说来惭愧,从每天背一句,转换到每天读两句,后来又变成了每天抄四句。实在是对不住自己,对不住小胖同学的期望。所以啦,要说到做到,决心以此文为证。 我会将每天要背诵下的句子记载在文章里,每个句子通过“音”、“义”、“感”填加注释。顾名思义“音”,既然要背诵它,诵读是第一要务;“义”是抄录比较欣赏的名家注解;“感”就是我个人小小的感受了。接下来的论语文不为别的,只为督促自己,只为给自己这段久违的背诵经历留点痕迹,外加个读书笔记了,还望走过路过的多多包涵! “当你的才华撑不起你的野心的时候,低下头来学习吧!”。 学而篇第一学而篇是论语的第一篇,相对来说还是可以背诵的很熟练的,这让我想到在喜马拉雅听一个GRE老师说中国学生背诵最熟练的就是abcz开头单词。动机谁都有,坚持诚可贵呀! 11.1 子曰:“学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知而不愠,不亦君子乎?” 音:“说”同“悦”yuè 义:开宗明义,概括了孔子人生理想的三个方面 感:通过学习找寻自身的满足,通过朋友感受外在的交往,通过控制情绪修身养性。 11.2 有子曰:“其为人也孝弟,而好犯上者,鲜矣;不好犯上,而好作乱者,未之有也。君子务本,本立而道生。孝弟也者,其为仁之本与” 音:“弟”同“悌”tì,子女对父母,弟弟对兄长的正确态度;鲜xiǎn,少;“与”同“欤”yú,论语中的与在句尾多是这个用法,表示疑问的助词。 义:仁的根本在于孝悌,由此推己及人。 感:很喜欢论语中“推”这个概念。 11.3 子曰:“巧言令色,鲜矣仁!” 音:xiǎn yǐ rén 义:巧言令色:满口说着讨人喜欢的话,满脸装出讨人喜欢的脸色;令色:令,好;色,脸色。 朱熹注曰:“好其言,善其色,致饰于外,务以说人。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"literature","slug":"literature","permalink":"http://lpbobo.com/tags/literature/"}]},{"title":"再理解tcp backlog","slug":"再理解tcp-backlog","date":"2016-06-03T01:15:40.000Z","updated":"2016-06-03T07:03:47.000Z","comments":true,"path":"2016/06/03/再理解tcp-backlog/","link":"","permalink":"http://lpbobo.com/2016/06/03/再理解tcp-backlog/","excerpt":"","text":"最近读到一篇分析文章TCP SOCKET中backlog参数的用途是什么?,其中有这样一段描述: 在linux 2.2以前,backlog大小包括了半连接状态和全连接状态两种队列大小。linux 2.2以后,分离为两个backlog来分别限制半连接SYN_RCVD状态的未完成连接队列大小跟全连接ESTABLISHED状态的已完成连接队列大小。互联网上常见的TCP SYN FLOOD恶意DOS攻击方式就是用/proc/sys/net/ipv4/tcp_max_syn_backlog来控制的,可参见《TCP洪水攻击(SYN Flood)的诊断和处理》。 在使用listen函数时,内核会根据传入参数的backlog跟系统配置参数/proc/sys/net/core/somaxconn中,二者取最小值,作为“ESTABLISHED状态之后,完成TCP连接,等待服务程序ACCEPT”的队列大小。在kernel 2.4.25之前,是写死在代码常量SOMAXCONN,默认值是128。在kernel 2.4.25之后,在配置文件/proc/sys/net/core/somaxconn (即 /etc/sysctl.conf 之类 )中可以修改。我稍微整理了流程图,如下: 回过头来看之前自己的一篇文章调查SocketServer,发现有一段描述有误: 也就是说,backlog形容的是server在与客户端建立tcp连接的过程中,SYN队列的大小,在socket的listen接口中,一般第二个参数就是backlog的大小。 listen(socket, backlog)的两种实现方式在How TCP backlog works in linux一文中,作者给出了比较详细的分析: 第一种实现方式在底层维护一个由backlog指定大小的队列。服务端收到SYN后,返回一个SYN/ACK,并把连接放入队列中,此时这个连接的状态是SYN_RECEIVED。当客户端返回ACK后,此连接的状态变为ESTABLISHED。队列中只有ESTABLISHED状态的连接能够交由应用处理。第一种实现方式可以简单概括为:一个队列,两种状态。 第二种实现方式在底层维护一个SYN_RECEIVED队列和一个ESTABLISHED队列,当SYN_RECEIVED队列中的连接返回ACK后,将被移动到ESTABLISHED队列中。backlog指的是ESTABLISHED队列的大小。 传统的基于BSD的tcp实现第一种方式,在linux2.2之前,内核也实现第一种方式。当队列满了以后,服务端再收到SYN时,将不会返回SYN/ACK。比较优雅的处理方法就是不处理这条连接,不返回RST,让客户端重试。 在linux2.2后,选择第二种方式实现,SYN_RECEIVED队列的大小由proc/sys/net/ipv4/tcp_max_syn_backlog系统参数指定,ESTABLISHED队列由backlog和/proc/sys/net/core/somaxconn中较小的指定。 但是在windows server中,底层选择winsock API实现,backlog的定义是represents the maximum length of the queue of pending connections for the listener(这是一个比较模糊的定义……来源于BSD),当队列满了后,将会返回RST。 if (ESTABLISHED is full) {SYN.req -> ESTABLISHED?}考虑这样一种情况,当ESTABLISHED队列满了,此时收到一个连接的ACK,需要将此连接从SYN队列移到ESTABLISHED队列中,会发生什么? linux底层的关键代码是: 12345listen_overflow: if (!sysctl_tcp_abort_on_overflow) { inet_rsk(req)->acked = 1; return NULL; } 除非系统的tcp_abort_on_overflow指定为1(将返回RST),否则底层将不会做任何事情……这是一种委婉的退让策略,在服务端处理不过来时,让客户端误以为ACK丢失,继续重新发送ACK。这样,当服务端的处理能力恢复时,这条连接又可以重新被移动到ESTABLISHED队列中去。 参考 How TCP backlog works in Linux TCP SOCKET中backlog参数的用途是什么? Windows中的backog处理策略","categories":[],"tags":[]},{"title":"倒腾hexo","slug":"倒腾hexo","date":"2016-05-26T14:34:29.000Z","updated":"2016-06-06T14:15:26.000Z","comments":true,"path":"2016/05/26/倒腾hexo/","link":"","permalink":"http://lpbobo.com/2016/05/26/倒腾hexo/","excerpt":"MiTang的博客是15年下半年才开始写的,当时中意的主题是hueman,一个富展现形式的博客主题,从wordpress的主题改造而来。但在写文章的过程中发现,为了效果,每次都需要去制作一张图片,有时候会浪费写技术内容的精力,如果不细心打点,博客整体的效果就不会最好,对于强迫症的我而言,这是不能容忍的。","text":"MiTang的博客是15年下半年才开始写的,当时中意的主题是hueman,一个富展现形式的博客主题,从wordpress的主题改造而来。但在写文章的过程中发现,为了效果,每次都需要去制作一张图片,有时候会浪费写技术内容的精力,如果不细心打点,博客整体的效果就不会最好,对于强迫症的我而言,这是不能容忍的。 第一次接触node就是在用hexo的时候,当时也倒腾了下hueman的主题,改配置神马的,运行了半年以后,在研究java nio的时候无意中发现了小e的笔记的博客,风格简明,以内容为主,每篇博文的两侧没有任何干扰项,与我自己的想法不谋而合,所以果断将hueman的主题切换为apollo。 作为一个后端的程序员,搞搞前端模板稍显痛苦,总觉得这是一个螺旋式的过程,想想前端模板引擎的设计初衷,仿佛看到了jsp的影子,各种复杂的语法和糅杂,让我稍觉蛋疼…… 搞完一个ejs的模板,又来看jade,虽说搞过python,但是jade还是让我理解起来有些燥热,一个下午好不容易自己添加点内容。不过在这个过程中,从零开始定制hexo主题的参考让我体会颇深,进而在深夜看了很多博主的文章,觉得还是蛮有意思的,这也是写博客的一种乐趣吧,其中一段: 真正想要了解一只青蛙,传统的解剖不是办法,更好的方式是构造一只青蛙(Don’t dissect the blog, build it.) 与hueman的distraction不同,apollo的博客内容看起来让人非常舒畅,由于太过简明,加上自己目前的主要精力原因,恐怕只有过一段时间再做一些深度自定义了,集中在tags,header定制吧。 今天花了半个小时的时间,自己用PPT做了一个png的图标,暂觉不错: 不过大宝贝分分钟用procreate做了一个lpbobo的图标,导致我的可爱小图标未正式上线就已夭折,路过的朋友可以来点个赞: 小于同学对页面的设想,胖胖同学敢接招吗 需求 效果 分栏目 需要增加“文”和“游”模块,之前的“柴米油盐”是个不错的设想;博客首页是四个方块滚动式的,下拉条可以选择该栏目下的预览,炫酷 正文可以增加颜色吗? 每篇文章加个小图标? 类似通讯录","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"hexo","slug":"hexo","permalink":"http://lpbobo.com/tags/hexo/"}]},{"title":"bitcoinj(1) Getting started","slug":"bitcoinj","date":"2016-05-12T03:00:00.000Z","updated":"2016-05-26T15:19:30.000Z","comments":true,"path":"2016/05/12/bitcoinj/","link":"","permalink":"http://lpbobo.com/2016/05/12/bitcoinj/","excerpt":"bitcoinj是一个由java实现的比特币核心功能的开源库[Github地址],项目主页为https://bitcoinj.github.io/。项目的核心开发者来自于Google,项目的文档十分丰富,非常适合Java开发者入手bitcoin的具体实现。","text":"bitcoinj是一个由java实现的比特币核心功能的开源库[Github地址],项目主页为https://bitcoinj.github.io/。项目的核心开发者来自于Google,项目的文档十分丰富,非常适合Java开发者入手bitcoin的具体实现。 注:本篇文章是笔者对bitcoinj研究过程的总结,内容主要来自项目主页、源代码以及个人理解,如果读者对bitcoin不熟悉的话,请先移步此处,了解比特币的核心内容。 编译bitcoinj 从Github下载release版本的bitcoinj源码,最新(截至2016-05-12)版本为release-0.14; bitcoinj工程是由maven管理的,可以通过maven命令进行编译,bitcoinj根目录下的pom.xml组织起多个子工程,在根目录下输入命令进行编译: 1mvn clean package 或者可以直接导入至IDE中,官方推荐IDEA,笔者使用eclipse,基本工程结构如下: 简单示例bitcoinj提供的核心对象包括: NetworkParameters from org.bitcoinj.core Wallet from org.bitcoinj.wallet PeerGroup from org.bitcoinj.PeerGroup BlockStore from org.bitcoinj.store BlockChain from org.bitcoinj.core WalletEventListener from org.bitcoinj.wallet.listeners WalletAppKits from org.bitcoinj.kits examples文件夹下的org/bitcoinj/examples/ForwardingService类展现了一个相对完整的使用示例,每当钱包收到bitcoin时,将会把它们发送到输入参数中的地址。 123456789101112131415161718BriefLogFormatter.init();if (args.length < 1) { System.err.println(\"Usage: address-to-send-back-to [regtest|testnet]\"); return;}NetworkParameters params;String filePrefix;if (args.length > 1 && args[1].equals(\"testnet\")) { params = TestNet3Params.get(); filePrefix = \"forwarding-service-testnet\";} else if (args.length > 1 && args[1].equals(\"regtest\")) { params = RegTestParams.get(); filePrefix = \"forwarding-service-regtest\";} else { params = MainNetParams.get(); filePrefix = \"forwarding-service\";} 至少需要1个输入参数,第2个输入参数为网络连接类型,默认为主链,testnet与regtest分别代表公有的测试链和私有的测试链,其中regtest模式下区块生成速度非常快。 1forwardingAddress = Address.fromBase58(params, args[0]); 程序第1个参数应为一个接收方的钱包地址,经过Base58编码过的,形如“17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL”。forwardingAddress是一个Address类型的对象,表示目标地址。 1kit = new WalletAppKit(params, new File(\".\"), filePrefix); kit是一个WalletAppKit对象,相当于一个包装,其中自动引用了一些底层对象的操作,简化客户端的处理,具体可以参考WalletAppKit的实现。 12kit.startAsync();kit.awaitRunning(); 等待区块同步完成。 12345678910111213141516171819202122kit.wallet().addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() { @Override public void onCoinsReceived(Wallet w, Transaction tx, Coin prevBalance, Coin newBalance) { Coin value = tx.getValueSentToMe(w); System.out.println(\"Received tx for \" + value.toFriendlyString() + \": \" + tx); System.out.println(\"Transaction will be forwarded after it confirms.\"); Futures.addCallback(tx.getConfidence().getDepthFuture(1), new FutureCallback<TransactionConfidence>() { @Override public void onSuccess(TransactionConfidence result) { forwardCoins(tx); } @Override public void onFailure(Throwable t) { throw new RuntimeException(t); } }); }}); 在钱包中新增一个入账的监听器,当钱包收到bitcoin时,将会触发WalletCoinsReceivedEventListener,打印出交易的基本信息。然后首先调用 1ListenableFuture<Transaction> future = tx.getConfidence().getDepthFuture(1) 我们知道区块链中一般至少经过6次确认才能确认一笔交易的真实性,目的是防止双花。Confidence对象表示客户对交易的信任程度,满足不同的阈值要求。ListenableFuture对象表示一个未来需要监听的事件,此处就是指getDepthFuture(1),即当确认数为1时被触发,当然也可能被异常触发。在FutureCallback的回调函数中“确认”触发onSuccess,其中调用forwardCoins,异常则触发onFailure。 1234567891011121314151617181920private static void forwardCoins(Transaction tx) { try { Coin value = tx.getValueSentToMe(kit.wallet()); System.out.println(\"Forwarding \" + value.toFriendlyString()); final Coin amountToSend = value.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); final Wallet.SendResult sendResult = kit.wallet().sendCoins(kit.peerGroup(), forwardingAddress, amountToSend); checkNotNull(sendResult); System.out.println(\"Sending ...\"); sendResult.broadcastComplete.addListener(new Runnable() { @Override public void run() { System.out.println(\"Sent coins onwards! Transaction hash is \" + sendResult.tx.getHashAsString()); } }, MoreExecutors.sameThreadExecutor()); } catch (KeyCrypterException | InsufficientMoneyException e) { throw new RuntimeException(e); }} 发送bitcoin的过程就比较简单了,首先从交易中拿出我们收到的bitcoin,然后发送到指定的地址,监听发送结果。 总的来说,bitcoinj是由google得工程师写的,其中用到了很多google自己封装的数据类型,而且整体是一种事件编程的风格,用到很多listener,看起来有些复杂,用起来更复杂……搞完了入门,基本就可以开始看核心的API了。","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"bitcoin","slug":"bitcoin","permalink":"http://lpbobo.com/tags/bitcoin/"}]},{"title":"别学了,开始做吧","slug":"别学了,开始做吧","date":"2016-05-06T11:00:00.000Z","updated":"2016-05-23T09:04:58.000Z","comments":true,"path":"2016/05/06/别学了,开始做吧/","link":"","permalink":"http://lpbobo.com/2016/05/06/别学了,开始做吧/","excerpt":"不断地积累积累,看到了未来,却没有连接现在。不注重现在,需要的一切都是假的。活在当下,大胆的去做想做的,跳出习惯的枷锁,停止恶性循环。","text":"不断地积累积累,看到了未来,却没有连接现在。不注重现在,需要的一切都是假的。活在当下,大胆的去做想做的,跳出习惯的枷锁,停止恶性循环。 36Kr原文链接","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"collection","slug":"collection","permalink":"http://lpbobo.com/tags/collection/"}]},{"title":"解读Java关键字final","slug":"解读Java关键字final","date":"2016-04-30T01:41:00.000Z","updated":"2016-05-25T08:59:38.000Z","comments":true,"path":"2016/04/30/解读Java关键字final/","link":"","permalink":"http://lpbobo.com/2016/04/30/解读Java关键字final/","excerpt":"在Java中通过final关键字来声明对象具有不变性(immutable),这里的对象包括变量,方法,类,与C++中的const关键字效果类似。","text":"在Java中通过final关键字来声明对象具有不变性(immutable),这里的对象包括变量,方法,类,与C++中的const关键字效果类似。 immutable指对象在创建之后,状态无法被改变 可以从三个角度考虑使用final关键字: 代码本身:不希望final描述的对象所表现的含义被改变 安全:final对象具有只读属性,是线程安全的 效率:无法修改final对象本身,对其引用的操作更为高效 final 变量定义final Object a,则a只能被初始化一次,一旦初始化,a的数据无法修改,若a为引用类型,则不能重新绑定其他对象。未被初始化的final变量被称为blank final,若为成员变量,则必须被初始化或在构造器中赋值。 例子:12345678910class Circle { static final double PI = 3.1415926; final int radius = 5; final int xPos; final int yPos; public Circle(int x, int y) { xPos = x; yPos = y; }} final 方法定义final method,则该方法无法被重载,方法设计者不希望由于对方法的重载导致其他相关功能出现异常。 例子:1234567class BaseClass { public final void method() {}}class DerivedClass extends BaseClass { public final void method() {} // 编译出错} 需要注意的是,final方法的定义不一定能够产生inline的效果,因为方法是否inline取决于JVM的策略,而非final关键字,通过final的设计提高方法效率是不准确的。 final 类final class X定义的类X无法被继承。 在Java中,String类被设计成final,其定义如下 public class final String extends Object implements Serializable, Comparable<String>, CharSequence 为什么String被设计成final? 一个String类的实例被初始化后,其在堆上的内容无法被改变,String类提供的任何修改String对象的方法都只能够产生一个新的String对象,大大简化了对String的操作,是代码更易于阅读和理解; String final是实现String interning(在内存中不同的string值只有一份)的必要条件,因为通常代码中存在大量的String对象,不同的引用会指向相同的字符串空间,若String不为final,则当一个字符串空间的内容改变时,所有的引用都需要知道这一情况,这一机制的实现是十分复杂的,无疑会影响效率。String interning能够节省内存空间,同时也节省时间花销; String只读,则不必担心非常重要的内容被篡改; 内部类与final在一个方法内定义匿名内部类时,内部类只能访问方法内的final类型变量,使得Java编译器能够提前捕获变量的值,并在内部类保存一份副本,当方法销毁时,内部类的内存空间依然完整。 例子: 12345678910111213public class Wrapper { public static void main(String[] args) { // Object obj = null; //编译出错 final Object obj = null; new Thread(new Runnable() { public void run() { obj = \"hello\"; } }).start(); }} 参考 Wiki: https://en.wikipedia.org/wiki/Final_(Java)#cite_note-3 Wiki: immutable Immutable: Java Glossary","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"Java","slug":"Java","permalink":"http://lpbobo.com/tags/Java/"}]},{"title":"深入浅出区块链","slug":"深入浅出区块链","date":"2016-04-30T00:30:21.000Z","updated":"2016-05-26T15:15:29.000Z","comments":true,"path":"2016/04/30/深入浅出区块链/","link":"","permalink":"http://lpbobo.com/2016/04/30/深入浅出区块链/","excerpt":"本篇文章能让新手直观上认识区块链,而不仅仅是纠结于算法与模型,尤其是工作量证明机制;能使有经验的同学在了解的基础上,搞清楚区块链如何解决实际问题,发挥自己的想象力,结合实际应用区块链。","text":"本篇文章能让新手直观上认识区块链,而不仅仅是纠结于算法与模型,尤其是工作量证明机制;能使有经验的同学在了解的基础上,搞清楚区块链如何解决实际问题,发挥自己的想象力,结合实际应用区块链。 数字货币的命题科技改变世界,每一个科技创新一定是为了解决某个实际的问题或者是表现一种追求完美的态度,想想智能机,物联网,VR…,right?那么在货币领域呢?数字货币就是为了升级流行了几百年的以纸币为核心的货币体系,能够适应未来的人类生活方式。 最近这两年,普通人的生活方式已经被移动互联网改变,刷新闻,刷社交……其中,毫无疑问,支付方式最贴近人的现实生活。一个人可以不拿钱包出门,吃饭刷手机,逛街刷手机,路边买盒饭也可以刷手机……在这个过程中,现金慢慢地向电子化过渡,钱已经不是一捆捆放在桌子上看着开心的纸了,仅仅是手机上显示的一串数字。这与互联网能够带来的快捷密不可分,方便才是王道,貌似也很健康。对于银行而言,减少使用现金也可以大大降低成本,对于国家而言,也是开心的。适应这种节奏,电子现金慢慢成为主流。 电子现金只是数字货币体系的一部分。实际上,数字货币的概念是几十年前提出的,是与现有的纸币系统平行的一套体系。在现有的系统中,现金是有序列标识的,可鉴别真伪的,由国家发行监管的,现金的交换价值与市场相关。同样,数字货币体系要想实施,也需要对数字货币做这样的处理,保证数字货币的可流通,这就是数字货币需要考虑的命题。 在这个题目里有三个方面需要考虑, 第一,如何确定收款人; 第二,如何确定汇款人; 第三,如何保证交易的唯一性; 前两个难题在几十年前就已经被解决了,通过公钥/私钥非对称加密的方法能够确定交易双方的身份,但是第三个问题却迟迟找不到答案,与现金这种实体资源不同,数字货币无法在网络上实现“给予”的功能,即give。这个命题又被称作“双花问题”,如何解决数字资源的传递问题,是数字货币流行的关键。 直到2008年,区块链的问世,才让人们看到了数字货币的曙光。 为什么要去中心化?沉思三分钟,如果换做是你如何去解决双花问题? 1,2,3…… 头脑风暴最直接地会告诉你这样一种答案:类似现实中的银行,搞个中央银行,每个人在银行里有个账户,交易记录由银行来完成。 其实这种方案是可行的,银行也很乐意去做,因为银行可以利用每个用户的钱去投资,去创造价值。但实际上存钱的过程就是一个投资的过程,利息算是你的回报率,如果这样一想的话,你就可能觉得自己的回报率太低了,而且投资就是有风险。在国内,这种风险很小,因为银行是国家的,只要天朝不倒,就不用担心自己血本无归,但偶尔也会看到由于各种异常导致的自己账户资金减少的情况。 但在国外,银行就没有这么让人信服了,2008年的金融危机就是鲜活的例子,也算是一个导火索,让那些寻找公平的人想要去创造一个没有银行存在的货币体系,于是乎比特币作为第一个成熟的数字货币体系诞生了。(don’t mess with badass scientists) 在比特币系统中,去中心化是一种需求,是一个充分条件。 分布式总账去中心化意味着整个网络是分布式架构的,沉思一分钟,比特币如何在分布式的网络中解决双花问题呢? 1…… 尽管数字货币没有实体货币的可转移性,但却比实体货币更容易追踪,在数字货币体系中,每一笔“钱”都可以轻易地追踪到流向。如此,只要在总账中记录每一笔交易,便记录每一笔钱的踪迹,便可以解决双花问题。 听起来很简单,但是如何保证记录的每笔交易是真实的却面临一个分布式网络中必须解决的问题:拜占庭将军问题。 拜占庭将军问题描述的是如何在不可信的消息通道上通过消息传递达成共识,这个问题没有确定的解,而是需要考虑一种容错方案,保证决策正确。 在分布式总账中,拜占庭将军问题可以这样描述: 每一个节点都有记账的权利,也有确认交易有效性的权利,可以被称作“记账人”,记账人存在不诚实的可能性。系统中产生的任意一笔交易,每个记账人都会记录,然后全网广播,被其他记账人认可后才能够被添加到总账中。每一个记账人都会希望自己的账本有效(系统有奖励),其余的记账人有可能赞同,也有可能反对,因为这个账本有可能是真实的,有可能是伪造的。最终不同记账人可能出于不同的利益关系怀有这几种心态:赞同真实的账本,赞同伪造的账本,反对真实的账本,反对伪造的账本,那么添加到总账中的账本就有可能是虚假的。 区块链设计了工作量证明机制确保记账人愿意记录真实的交易信息。 工作量证明(pow)解决拜占庭将军问题工作量证明的过程就是计算机通过穷举去匹配一个由SHA-256算法加密的随机数,这个期间产生的CPU消耗被称为工作量证明,也证明了记账人愿意为了记账付出一定的成本(CPU运算消耗的资源)。最终记账权由工作量证明最快的CPU获取。 每个记账人出于成本因素会考虑自己账本内容的真实有效性,因为虚假的账本意味着同样付出的其他记账人很大程度上不会投票赞同这份账本,那么自己的成本将产出空值。 同时,区块链中的“链”则表明了交易的前后存在关系,每一个区块中包含多笔交易,区块就是每个记账人心中的账本,每一个区块对应的随机数将作为下一次工作量证明的输入,从而形成一条链条。 上面的分析简单说明了记账人愿意宣布真实的账本以防止白忙乎,但是没有证明记账人一定不会作假,还存在着拉帮结伙、同谋的可能性,但是“总账链”的方式确保了记账人不会作假。记账人投票的方式是在下一轮的工作量证明中获胜,并把自己的区块加入到赞同区块的后面,由此区块链也是一个工作量证明的链条。 假设在链条的某个区块上产生了分叉,一个虚假,一个真实,那么虚假链条上的记账人则需要保证自己在每一轮的工作量证明中都需要优胜才能够维持自己链条的发展,与诚实的链条产生竞争。可想而知,随着时间的推移,维护虚假链条的记账人最终会放弃,因而确保了总账记录的每一笔交易将以诚实的状态发展。 工作量证明解决拜占庭将军问题的核心在于尽管互不信任,但是出于利益最大化,成本最小化的考虑,记账人愿意展开公平的竞争,这种机制有效控制了整个社区的平衡发展。 本质上来说,工作量证明的本身是没有任何附加价值的,胜出者仅仅是计算能力最强的CPU,但是工作量证明对整个区块链生态的发展的意义却不止CPU计算这么简单。生物学中,不利原理阐述的是在自然选择的条件下,那些不利于物种本身的条件,比如孔雀的大尾巴,鹿的大角……,将最终促进整个种群的发展。在区块链生态中,CPU就是新的物种,工作量证明作为其不利条件的表现,将促进CPU本身的发展,并扩大整个网络的范围,最终带来整个生态的繁荣。 工作量证明机制的补充 - 权益证明(proof-of-stake)工作量是一个去中心的投票过程,但是在其发展过程中,矿池的算力越来越大,逐渐朝一个中心化的机构发展,当其算力超过51%时(历史上出现过一次),将破坏整个网络的发展。 权益证明机制的设计能够解决工作量证明机制中的网络安全问题,货币的持有者拥有相应的“权益”,当把货币花费时,权益得到证明,因此若想要发动51%攻击,则需要花费全网51%的货币,实现这一目标的成本将要比51%算力还高。 一个单独拥有权益证明的体系无法保证投机行为对货币价值造成的冲击,同时在货币体量较小时,安全性也很低。 一种混合工作量证明与权益证明的体系将两者的优点互相结合,缺点互相补充,构成了一个更加完备的系统。 区块链的价值区块链中没有中心化的机构,每个节点都能够拥有相同的总账,总账中的每一笔交易无法被篡改,简而言之,区块链就是一个无法修改的数字账本。 理解到这层含义,那么去中心化也可以看成是一个区块链的必要条件了。 区块链对于数字货币而言,其意义是巨大的,第一次实现了数字资产在网络上的“传递”,使数字货币成为可能。 扩展到互联网上,“”无法修改的账本“”意味着区块链可以改变现实生活中一切信任成本较高的行业,房地产、股票、证券、合约、供应链、银行清算结算…… 比特币是区块链唯一成熟应用区块链既然潜力如此之大,为何只有比特币是唯一成熟的应用呢? 第一个原因,先有了比特币的想法,才有了区块链的设计,区块链设计之初就是用来服务比特币的。 第二个原因,区块链的生态系统需要足够的壮大。迄今为止,比特币已经发展了9年,但是依然还未成熟,还在不断地进化,一个不成熟的系统若不能够确保“无法修改的数字账本”的稳定性,也就失去了所有的意义。 第三个原因,工作量证明的成本对于数字货币体系是可以接受的,对于其他行业,则需要一种有效的替代,因此也有了其他各种币。 第四个原因,其他应用系统不够开放。一个去中心化的系统如果不够开放,相当于搬起石头砸自己的脚。 参考1.比特币的未来:POS vs POW","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"blockchain","slug":"blockchain","permalink":"http://lpbobo.com/tags/blockchain/"}]},{"title":"聊聊区块链","slug":"聊聊区块链","date":"2016-04-29T00:40:58.000Z","updated":"2016-05-07T15:25:05.000Z","comments":true,"path":"2016/04/29/聊聊区块链/","link":"","permalink":"http://lpbobo.com/2016/04/29/聊聊区块链/","excerpt":"2008年世界范围内的金融危机爆发,2009年比特币横空出世。比特币是一种点对点的电子现金系统,无需第三方信用机构介入就能确保交易的可信性,突破了传统金融体系中需要企业或机构背书的事实。作为底层实现技术,区块链大放异彩。区块链是一种去中心化的协议,是一个安全的分布式账本,交易可信性由计算机cpu的算力及密码学原理确保,无需中心化机构审核,交易不会被伪造或篡改,交易内容既可以是数字货币,也可以是股权等数字资产,能够颠覆现实世界中所有信任成本较高的产业,包括金融、股票、审计、物联网等,具备无限潜能。","text":"2008年世界范围内的金融危机爆发,2009年比特币横空出世。比特币是一种点对点的电子现金系统,无需第三方信用机构介入就能确保交易的可信性,突破了传统金融体系中需要企业或机构背书的事实。作为底层实现技术,区块链大放异彩。区块链是一种去中心化的协议,是一个安全的分布式账本,交易可信性由计算机cpu的算力及密码学原理确保,无需中心化机构审核,交易不会被伪造或篡改,交易内容既可以是数字货币,也可以是股权等数字资产,能够颠覆现实世界中所有信任成本较高的产业,包括金融、股票、审计、物联网等,具备无限潜能。 初识比特币比特币是一种P2P的数字货币,在交易过程中不需要任何第三方支付系统,打个比方,就是我们在淘宝上购物时,直接把钱付给商家。作为一种数字货币,比特币具备货币的几个基本职能:s 价值尺度 流通手段 贮藏手段 支付手段 世界货币 数字货币与Q币等虚拟货币具有本质的不同,Q币是腾讯发行的,在腾讯的游戏平台里使用,是以腾讯的信用为担保的,消费者认同Q币在腾讯平台下的价值,但是Q币不能在其他渠道下流通,也不能够反向转换成现金。而数字货币可以用于真实世界的商品和服务交易,不受到网络虚拟空间的局限。 比特币大火的原因,就在于比特币不是由某一家企业或机构的信用背书的,其价值来自于基于数学体系的自证其信,核心意义就是解决了分布式节点之间如何达成共识的问题(拜占庭将军问题),不需要第三方(银行、机构等)。作为一个分布式账本,互联网上每一个账本都记录着所有的交易信息,交易的有效性来自于网络上其他节点的见证,是一个群体投票的过程。这种去信任的特性造就了比特币的与众不同。 背书:原意表示在支票等背后签名表示支付、收到或同意转让等,表示用信用支持。 拜占庭将军问题:分布式节点之间如何达成共识的问题。 去信任是一种颠覆从货币的发展来看,银行就是一个货币发行机构,拥有很高的信誉程度,客户可以放心的把钱存在银行,放心的通过银行做交易,拥有庞大的可辨识客户的基础,拥有处理复杂金融规则方面的经验。我们可以把银行比作数据库,里面记录了个人所有的交易信息,由银行负责对这个数据库进行更新和验证。但是这不代表银行是完全可信的,第三方总存在不可信的可能性。 互联网上的贸易,几乎都需要借助金融机构作为可资信赖的第三方来处理电子支付信息。虽然这类系统在绝大多数情况下都运作良好,但是这类系统仍然内生性地受制于“基于信用的模式”(trust based model)的弱点。我们无法实现完全不可逆的交易,因为金融机构总是不可避免地会出面协调争端。而金融中介的存在,也会增加交易的成本,并且限制了实际可行的最小交易规模,也限制了日常的小额支付交易。并且潜在的损失还在于,很多商品和服务本身是无法退货的,如果缺乏不可逆的支付手段,互联网的贸易就大大受限。因为有潜在的退款的可能,就需要交易双方拥有信任。而商家也必须提防自己的客户,因此会向客户索取完全不必要的个人信息。而实际的商业行为中,一定比例的欺诈性客户也被认为是不可避免的,相关损失视作销售费用处理。而在使用物理现金的情况下,这些销售费用和支付问题上的不确定性却是可以避免的,因为此时没有第三方信用中介的存在。 银行也是中介,没人从根本上喜欢中间商赚差价,去信任就意味着我们可以省去中间环节的一切开销,颠覆中介,约吗? 比特币的诞生 所以,我们非常需要这样一种电子支付系统,它基于密码学原理而不基于信用,使得任何达成一致的双方,能够直接进行支付,从而不需要第三方中介的参与。杜绝回滚(reverse)支付交易的可能,这就可以保护特定的卖家免于欺诈;而对于想要保护买家的人来说,在此环境下设立通常的第三方担保机制也可谓轻松加愉快。 于是乎,在2008年的全球金融危机产生后,网名为中本聪的人发表了一篇论文,描述了一种点对点的电子现金系统,称作比特币白皮书,并在2009年创建了第一个区块Genesis Block,发布了有史以来的50个比特币。 在中本聪的论文中,提出了一种通过点对点分布式的时间戳服务器来生成依照时间前后排列并加以记录的电子交易证明,从而解决双重支付问题。只要诚实的节点所控制的计算能力的总和,大于有合作关系的(cooperating)攻击者的计算能力的总和,该系统就是安全的,为比特币的可能性提供了验证条件。 拥有去信任、去中心化的特性,比特币就是粉碎了信用需要第三方背书的事实,从而自证其信,其实现的机制-区块链可以被称作“创造信任的机器”。截至2016年,已经发展了7年,期间发生过许多大事件,比特币的影响力也越来越大,中国是世界上最大的比特币交易市场。 更形象地说,比特币就是虚拟世界的真金白银,是虚拟世界的实体货币。 比特币完全具备这种取代现有货币体系的潜力,这不是吹嘘,而是来自于其区块链技术技术的完备性。 区块链 区块链是一种新型去中心化的协议,能安全地存储比特币交易或其他数据,信息不可伪造和篡改,可以自动执行智能合约,无需任何中心化机构的审核,交易既可以是比特币这样的数字货币,也可以是期权、股权、版权等数字资产,区块链解决了拜占庭将军问题,大大降低了现实经济的信任成本与会计成本,重新定义了互联网时代的产权制度。 交易首先看看区块链中的基本数据元素:交易。每一个区块中包含了一组交易数据,一笔交易定义了数字货币在两个交易者间传递的情景: 每一笔交易至少包含一个输入、一个输出,每一个输入和输出中都必须包含下图中所示的变量: 同时,每个输入都使用上一笔交易的输出作为输入,每一个输出都在等待着被下一个输入消费。 交易解决了钱从哪来,又到哪去的问题,每一条交易都将被串起来,交易信息都可查。在每笔交易的末尾签署下一位拥有者的公钥,收款人通过自己的私钥使用这个货币。在每笔交易的开始签署拥有者的公钥,收款人通过检查发送者的签名,就能确认交易的拥有者。 这种数字签名的方法,在30年前就已经被发明,而数字货币迟迟没有诞生的原因在于一直没有解决双花问题,如何确定钱没有被同时转给两个人,构成欺骗?也就是说数字货币需要在互联网上进行“传递”(我给你,你就有了,我就没有了),而这个技术难题是一直没有被解决的,区块链则在这个方向是一次技术突破。 时间戳服务器若想防止双重支付,则需要确保之前的拥有者没有对更早发生的交易实施签名。为了确保某一笔交易真实存在,唯一的方法就是获取该笔交易之前所有的交易,在去中心化的场景中,需要全网广播,所有的节点都保存相同的交易记录,记录了每一笔交易的先后顺序,对于每一笔交易而言,如果绝大多数的节点都认同该交易,则有效,就解决了双重支付的问题。 如何确保交易存在的有序、有效性? 中本聪提出的解决方案中设计了时间戳服务器。时间戳服务器通过对以区块(block)形式存在的一组数据实施随机散列而加上时间戳,并将该随机散列进行广播。显然,该时间戳能够证实特定数据必然于某特定时间是的确存在的,因为只有在该时刻存在了才能获取相应的随机散列值。每个时间戳应当将前一个时间戳纳入其随机散列值中,每一个随后的时间戳都对之前的一个时间戳进行增强(reinforcing),这样就形成了一个链条(Chain)。 但是需要注意的一点是存在一种双重支付的可能:欺诈者利用正常交易等待全网确认的时间实施一次欺诈交易,而被骗商家没有等到本次交易的全网认可就提供了商品交换,等到正常交易被确认后,欺诈交易将被驳回,但此时商品已被交换。这也就意味着,每次的交易成功需要全网确认后才算生效。 如何确认交易,由谁记录交易 交易广播到全网所有的矿工,矿工通过交易者的公钥简单确认交易,并记录在内存中,与此同时矿工们在不停地挖矿,想要获得记录交易的权利,而挖矿的过程即是一个工作量证明的过程,挖矿成功的人能够将交易打包到区块中,加入区块链,并获得一定数量的比特币奖励,一次挖矿的平均时间被设定为10分钟。 工作量证明(proof-of-work)矿工是比特币网络的计算节点,利用自己的计算机计算去竞争记录区块的权利,这个过程被称为挖矿,挖矿的过程也被称为工作量证明。 工作量证明:对计算机而言,就是一个匹配SHA-256随机数的过程,整个过程CPU产生的工作量消耗为工作量证明。 为什么要有工作量证明 工作量证明机制是最好的共识的机制。 在新的区块生成前,网络中会存在大量的交易待确认,这些交易中包含正常交易、欺诈交易、无效交易等,哪些交易该被记录,对于每一个矿工而言,选择不一定相同,这就需要一个合适的随机选择机制,这就是一个群体如何达到共识的问题。生物学中有一个原理叫做不利原理(the Handicap Principle),该原理可以帮助理解工作量证明。 产生区块的能力是计算能力的表现,这正是比特币网络所需要的,同时因为同意对下一区块产生竞争,显示了尊重社区利益而不是为一己私利操作区块,集体维护保证了整个区块链的诚实性。当然,矿工能够获取一定数量的比特币奖励作为激励,让矿工产生记账的动力。 工作量证明维护了区块链的诚实性,防止骗子通过分叉伪造交易;同时确保了交易信息的不可逆性,如果要篡改某个区块的交易信息,则必须完成该区块的工作量外加该区块之后所有区块的工作量,并最终赶上诚实节点的工作量,而这是不可能完成的。 所以,工作量证明(挖矿)的过程是一个投票的过程,通过投票来替代“老大”,而具有投票权的“人”则是每一个CPU。工作量证明可以看作是不信任的互联网上达到共识的一种手段。 交易过程描述整个过程的运行步骤如下:1) 新的交易向全网进行广播;2) 每一个节点都将收到的交易信息纳入一个区块中;3) 每个节点都尝试在自己的区块中找到一个具有足够难度的工作量证明;4) 当一个节点找到了一个工作量证明,它就向全网进行广播;5) 当且仅当包含在该区块中的所有交易都是有效的且之前未存在过的,其他节点才认同该区块的有效性;6) 其他节点表示他们接受该区块,而表示接受的方法,则是在跟随该区块的末尾,制造新的区块以延长该链条,而将被接受区块的随机散列值视为先于新区块的随机散列值。 节点始终都将最长的链条视为正确的链条,并持续工作和延长它。如果有两个节点同时广播不同版本的新区块,那么其他节点在接收到该区块的时间上将存在先后差别。当此情形,他们将在率先收到的区块基础上进行工作,但也会保留另外一个链条,以防后者变成最长的链条。该僵局(tie)的打破要等到下一个工作量证明被发现,而其中的一条链条被证实为是较长的一条,那么在另一条分支链条上工作的节点将转换阵营,开始在较长的链条上工作。 所谓“新的交易要广播”,实际上不需要抵达全部的节点。只要交易信息能够抵达足够多的节点,那么他们将很快被整合进一个区块中。而区块的广播对被丢弃的信息是具有容错能力的。如果一个节点没有收到某特定区块,那么该节点将会发现自己缺失了某个区块,也就可以提出自己下载该区块的请求。 颠覆领域区块链是基于密码学与计算机算力的共识网络,由区块链技术支持的电子账本是无差错、不可篡改的可靠系统,大大降低信用评估所带来的高额成本,对支付、清算、交易、确权等有深刻影响,颠覆信任的浪潮即将席卷这些行业: 银行结算:R3CEV 股票证券:小蚁 物联网:ADEPT 智能合约:hyperledger,ethereum(智能合约编程平台) 审计公证:Factom 供应链:Vechain …… 一个通用的区块链系统具有如下的组织层次: 在一个由区块链实现的系统中,实体E1到E2之间数据的传递是不可逆的,整个网络系统没有中心机构,由分布式的网络节点投票确定交易的真实性。通过区块链的开发平台,可以构建出无数类型的去信任应用。 以ADEPT为例,ADEPT是IBM与三星合作开发的区块链物联网系统,底层是以太坊(Ethereum)平台构建的区块链系统,上一层是telehash构成的通信协议层,顶层是BitTorrent构建的数据传输层。 以区块链为中心,ADEPT能够实现物理设备的自治化,在整个物联网系统中,设备与人之间的关系是平等的,设备能够通过记录数据追踪到不同设备之间的关系,设备与人之间的关系,人与人之间的关系,从而实现授权的安全转移,如门锁可以安全地与手机交互,或者与他人的手机交互。 从物联网的角度出发,区块链能够减少设备与云端的交互,使设备尽可能避免维护,大大降低云控制中心运维带来的成本,同时,设备变得更加灵活,设备资源变得更具有流通性。 区块链助力银行自助渠道紫金公司作为金融自助服务领域的领军企业,致力为银行客户提供低成本高质量的解决方案,凭借多年的行业积累,针对用户痛点对症下药。 目前,银行的网络相对封闭,自助设备与客户之间依旧是一种交易型的关系。通常情况下,一个银行的营业网点部署了大量的设备,包括:ATM、VTM、BSM、发卡机、柜员机、排号机、服务机器人、查询终端等等,尽管连接统一的银行后台,但这些设备之间的弱连接性使得它们并未成为一个统一的服务实体。 银行的服务模式在转变,电子渠道与自助渠道是两个关键点,自助渠道的服务模式应该走在转变浪潮的前端。如何让设备更加智能,从交易型向服务型转变是问题的关键,能不能真的创造出一个无人管理的智慧银行呢? 从设备运维的角度分析,一个无人的智慧银行必定是一个分布式网络架构,区块链技术可以为设备自治提供基础。在一个区块链构成的去中心网络中,运维的成本会大大降低,根据业务流量的因素,设备可以改变自身的服务状态,在睡眠、运行、停机等状态间切换,而无需人工干预。如果出现设备异常,整个网络可以应对,保留正常服务或整台设备进入休眠状态。 从设备服务的角度分析,分布式网络中所有资源实现共享,对自助设备而言便是硬件资源共享、交易共享、服务状态共享,这些状态或资源可以在节点间实现安全转移。设想这样一个场景:一台ATM机器无法打印凭条,客户办理交易完成后,机器将打印凭条的任务转交给可用的机器,完成打印凭条服务的转移。 以上的两个角度仅仅是区块链自助行业应用的冰山一角,去中心的可信网络,由于其成本优势,势必会被逐渐的接纳和采用。 当然,要完全实现一个无人的智慧银行还有很多问题要解决,尽管客户体验越来越重要,但交易安全性还是首要考量,因此生物识别等技术是客户体验与安全性完美结合的首要前提。同时,不可忽略的是银行电子化对自助渠道的影响,在中心城市,现金的需求量逐渐减少,那么以现金业务为中心的自助服务如何提供更多优质的金融服务是个重要的问题。银行业转型背负着沉重的包袱,自助渠道需要在变革中一步一步引导消费者,路漫漫其修远兮,吾将上下而求索。 参考 区块链是什么 理解区块链 知乎-区块链 从中本聪的白皮书来重新审视区块链 比特币白皮书(中文) 比特币白皮书(英文) 比特币交易概念 工作量证明概念 一个故事告诉你比特币的原理及运作机制 挖矿与共识 区块链助力上海国际金融中心 区块链成为金融领域的tcp/ip 区块链细节讲解 什么是公有链 区块链的私有链、混合链开源项目介绍","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"blockchain","slug":"blockchain","permalink":"http://lpbobo.com/tags/blockchain/"}]},{"title":"金融自助领域的创新思路","slug":"金融自助领域的创新思路","date":"2016-04-26T02:21:00.000Z","updated":"2016-05-26T15:16:20.000Z","comments":true,"path":"2016/04/26/金融自助领域的创新思路/","link":"","permalink":"http://lpbobo.com/2016/04/26/金融自助领域的创新思路/","excerpt":"金融自助?就是以ATM为代表的啦。","text":"金融自助?就是以ATM为代表的啦。 在当下互联网时代,银行出于成本和效率的考虑,一定会着力于自助化和电子化。 在自助渠道方面,ATM机器承担着重要的角色,通常以群集部署于营业网点,或以单台机器部署于公共场所。自助设备的运营成本和维护成本相对较高,但相比一个重型的柜台式服务网点,对银行而言还是自助设备能够节约成本。但以目前自助设备的水平,仅支持功能型的业务交易,使广大群众对ATM等设备还停留在取现、存款上,即使开发了新的功能,也无法落地实施。 要打造以自助设备为主的轻型无人网点,需要让机器变得更加智能。 ATM的战略定位不仅限于传统的取款、存款、转账等业务,可以提供第三方服务,如代缴费,缴罚款,也可以提供增值业务,如电影票、门票,ATM是一个培养客户的服务中心。 要满足这样一个愿景,有几个方面可以探索: 运维角度:统一的机器服务状态后台监控,为运维人员的智能分配提供数据来源;一个网点内部机器的相对自治,提供统一的对外服务。 用户体验:根据客户画像提供个性化的服务界面及服务流程,结合服务地点的环境因素,提供增值业务的推广功能,最后能将数据反馈到银行,进行数据的二次挖掘 与移动设备交互:手机与自助设备均基于LBS,可以提供例如消息推送,特色业务推广等服务,可以设想一个A把钱放到C机器上,只有B能够通过私钥去取,基本就实现了一个异地现金汇款的业务。 最后还要提一点,类似magic,FB推的虚拟助理这样的客服机器人,在金融领域应用很广,能够扩大服务范围,提升服务体验,同时还可以结合现有的业务资源,与呼叫中心结合,这个方向公司应该深挖一下。","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"finance","slug":"finance","permalink":"http://lpbobo.com/tags/finance/"}]},{"title":"jdk1.8 HashMap源码分析","slug":"jdk1.8 Hashmap源码分析","date":"2016-04-25T15:42:00.000Z","updated":"2016-05-07T15:19:14.000Z","comments":true,"path":"2016/04/25/jdk1.8 Hashmap源码分析/","link":"","permalink":"http://lpbobo.com/2016/04/25/jdk1.8 Hashmap源码分析/","excerpt":"根据jdk1.8的源码,分析HashMap底层实现机制,研究HashMap的数据结构的设计。","text":"根据jdk1.8的源码,分析HashMap底层实现机制,研究HashMap的数据结构的设计。 本篇文章所有源码均来自jdk1.8版本,将在后续博客中与之前版本进行对比。 定义Hashmap类的定义如下: 1public class **HashMap<K,V>** extends AbstractMap<K,V> implements Map<K,V>, Serializable, Cloneable AbstractMap缩减了HashMap需要实现的接口集合,Hashmap是可以序列化的,是可以拷贝复制的 构造函数默认构造器,初始化bucket数目为16,负载因子为0.75:Hashmap() initCapacity表示bucket的数量,在预知key的数量时,能够有效避免扩容,提高性能:Hashmap(int initCapacity) loadFactor表示负载因子,衡量散列表的空间使用程度,用于平衡散列表的空间利用率和查找时间:Hashmap(int initCapacity, float loadFactor) 前两种构造函数实际均调用第三种: 12345678910public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException(\"Illegal initial capacity: \" + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException(\"Illegal load factor: \" + loadFactor); this.loadFactor = loadFactor; this.threshold = tableSizeFor(initialCapacity);} 其中,threshold表示需要resize数组后的大小,值为大于initCapacity的最小的2^n(比如15对应的临界值为16),当数组的实际大小超过initCapacity时,将会扩容至threshold。 第四种构造函数为拷贝构造:HashMap(Map<? extends K, ? extends V> m) 数据结构hashmap的底层基本数据结构是Node对象构成的数组,定义如下:transient Node<K,V>[] table 其中Node是key-value的存储结构,并包含指向下一个Node节点的指针,从而当碰撞发生时构成一条链,基本定义如下: 12345static class Node<K, V> implements Map.Entry<K, V> { ... Node(int hash, K key, V value, Node<K, V> next) {} ...} 当链表长度超过8时,链表将转换为红黑树,其定义如下: 12345static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> { ... TreeNode(int hash, K key, V val, Node<K,V> next) {} ...} 关键源码分析 计算key的hash值: 1234static final int hash(Object key) { int h; return (k == null) ? 0: (h = key.hashCode()) ^ (h >>> 16);} java中hashcode为32位,默认的table大小为16。为了能够将hashcode映射到table空间内,java采取了取hashcode的低位值做法(table.length-1) & hashcode,那么就意味着hashcode的高位值在映射过程中不起作用,这很容易发生碰撞。因此,通过>>>16将hashcode的高位与低位进行异或,合并高位与地位信息,使得映射均匀。 计算扩容大小: 123456789static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;} tableSizeFor是一个求解大于cap的最小2^n算法,通过填充cap所有低位值为1,然后+1实现。 V put(K key, V value) 1234567891011for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e;} 当binCount达到8时,表示需要通过treeifyBin将list转换成tree结构,以减少碰撞发生时的性能损失,提升查找速度。另外,判断一个key是否存在时需要两个条件:hashcode相同,key相同。 hashmap性能分析 hashmap中采用了大量的位运算加快计算速度 hashmap的table长度为2^n,使不同hash值发生碰撞的概率比较小,数据分布均匀,增加查询效率. hashmap在最佳情况下的时间复杂度为O(1),但是若发生碰撞,则需要遍历链表,那么最坏的时间复杂度就是O(n),通过红黑二叉树对大量碰撞做优化,最坏的时间复杂度降为O(logn) 当hashmap需要扩容时,会重新映射已有的Node,是一个耗时操作,需要尽量避免。 参考资料 Hashmap的实现与优化","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"java","slug":"java","permalink":"http://lpbobo.com/tags/java/"}]},{"title":"高并发I/O模型","slug":"高并发IO模型","date":"2016-04-21T08:00:00.000Z","updated":"2016-05-26T15:20:06.000Z","comments":true,"path":"2016/04/21/高并发IO模型/","link":"","permalink":"http://lpbobo.com/2016/04/21/高并发IO模型/","excerpt":"听起来很高端的高并发,需要操作系统和应用程序的完美配合。 在网络文章中经常能够看到一些架构师常提“高并发”、“高可用”这样的描述,看到“NIO”、“epoll”、“select/poll”这样的缩写,总会有疑问,什么才是高并发?为什么要高并发?怎么高并发?高并发很难么?","text":"听起来很高端的高并发,需要操作系统和应用程序的完美配合。 在网络文章中经常能够看到一些架构师常提“高并发”、“高可用”这样的描述,看到“NIO”、“epoll”、“select/poll”这样的缩写,总会有疑问,什么才是高并发?为什么要高并发?怎么高并发?高并发很难么? 总的来说,深入理解高并发服务端程序的构建确实很难,需要了解网路、操作系统、webserver、web application、web架构等等,而且需要与实际的业务需求相结合,认真处理每一环节才能构建一个性能优越的web系统,这个过程中涉及到到的编程知识都很基础,但是组合在一起就是个考验。 尽管平时没有涉及到,但是了解相关知识对我们的编码能力绝对有提高,遇到有人装X的时候也可以直接打脸。我们就从一些基础的知识聊起,谈一谈服务端程序中的并发,希望大家能够掌握以下几点知识: linux下NIO、BIO、select/poll/epoll、AIO模型 事件驱动式编程 根据不同I/O模型及应用场景构建并发web服务 IO性能瓶颈分析 基础概念同步 VS 异步 从用户的角度来看,调用一个操作,一直等待操作执行完成返回结果,那么这个操作就是同步的 从用户的角度来看,调用一个操作,操作直接返回一个调用结果,等待任务执行完成后,再通知用户,那么这个操作就是异步的 同步与异步关注的是消息通知机制,举个通俗栗子:同事出差,可以选择自己去网站购买机票,一步一步选择直至交易成功,也可以打电话给前台,让前台帮订票,订票成功后,前台会短息或者电话通知。这个过程中,自己买票就是同步的,委托前台就是异步的。 阻塞 VS 非阻塞 阻塞是指调用结果返回之前,线程会被挂起 非阻塞是指不能立刻得到结果之前,线程不会被挂起 阻塞与非阻塞关注的是程序等待时的状态。依照上面的例子,我在等待前台通知的过程中,可以做其他工作,这个状态是非阻塞的,也可以一直等待,这个状态是阻塞的。 线程 VS 进程 进程是程序在处理器上的一次执行过程,是拥有资源的独立单位。线程是进程内的一个可调度实体,是调度和分配的基本单位,线程自己只拥有少量资源,但与进程内的其他线程共享进程拥有的全部资源。 多线程是指一个进程中拥有多个线程,这些线程驻留在同一地址空间,并且可以访问相同数据。 在操作系统中引入进程的目的是使多道程序能并发执行,以改善资源利用率及提高系统吞吐量,再引入线程,则是为了减少程序并发执行所付出的时空开销,使操作系统具有更好的并发性。 现代服务器一般是多核CPU配置(大多数是linux),提高程序的并发性更多需要考虑核心切换开销(数据在内核态与用户态间的拷贝),由于进程的内存空间独立,切换时不需要考虑上下文,而线程的内存空间需要共享,共享资源需要在核心间拷贝,多核下多线程的性能不如多进程。但是在单核上,进程切换的开销还是要远远大于线程切换的开销的。 多线程共享内存是一个优势,当任务需要大量的共享数据或者频繁通信时,建议使用多线程,其他情况,尽量使用多进程。 并发 VS 高并发 并发(concurrency):并发是程序的一种执行属性,可以同时执行一个或多个任务。 在一个并发的环境中,刨除外界环境因素,资源读取的开销是固定的,而如何同时更有效地利用其他计算资源是提高并发能力的关键。高并发一般是在电商系统中被提及的,由于各种秒杀活动的兴起,高并发成为一个web后台服务必备性能。web服务的高并发性能指标可以通过QPS(Query per second)来衡量,QPS指每秒处理请求数,可用(并发数/一般响应时间)来计算。 linux I/O模型一个基本的网络I/O过程涉及到应用进程以及linux内核两个对象,分为两个阶段: 数据准备:通常涉及等待数据从网络中到达。当所等待分组到达时,它被复制到内核中的某个缓冲区 数据拷贝:把数据从内核缓冲区复制到应用进程缓冲区 在linux中,根据两个阶段的处理不同,可以划分为以下五种IO模型: 阻塞式I/O(blocking I/O) 非阻塞式I/O(nonblocking I/O) 多路复用I/O(I/O multiplexing) 信号驱动式I/O(signal-driven I/O) 异步I/O(asynchronous I/O) 阻塞式I/O:进程调用recvfrom,直到数据包到达且被复制到应用程序的缓冲区或发生错误才返回。最常见的错误是系统调用信号被中断。我们称进程在从调用recvfrom开始到返回的整段时间内是阻塞的。 非阻塞式I/O:进程轮询数据准备的状态,如果没准备好,则立即返回错误,如果准备好并且拷贝完成,则返回成功。 多路复用I/O:select/poll/epoll模型,进程调用select/poll,阻塞等待套接字变为可读。当select返回套接字可读这一条件时,进程调用recvfrom把所读数据复制到应用进程缓冲区。 信号驱动式I/O:进程向系统注册感兴趣的信号,并立即返回,当数据准备完成的信号触发时,系统通知进程,进程调用recvfrom把所读数据复制到应用程序缓冲区。 异步I/O:进程调用系统函数,并告诉内核当整个操作完成时如何通知进程。该系统调用立即返回,而且在等待I/O完成期间,进程不被阻塞。当数据准备好,并且复制到应用进程缓冲区后,内核才会产生这个通知。 可以用一个比方来更形象了解这几种模型: 有A,B,C,D四个人要吃麦当劳:A点完餐之后一直在窗口等,直到厨房做好汉堡后,拿到窗口来;B点完餐之后找了个位置坐,过一分钟问下服务员有没有做好,直到服务员说做好了,然后把汉堡拿到窗口来,B去窗口取;C是请客,由一个人在窗口等,点了很多份套餐,哪份好了就拿哪份;D是VIP,点完餐之后就在座位上等,汉堡做好后,服务员直接端到座位上来; IO模型的比较下图比较了5种基本I/O模型: 可以看到,尽管阻塞式I/O、非阻塞式I/O、多路复用I/O、信号驱动式I/O在第一阶段的处理不同,但在数据拷贝阶段都处于同步阻塞等待状态,因此可以看作是同步I/O的一种,这里的同步指的是recvfrom这个系统调用。 在实际应用中, 对于BIO,通过多线程提高并发能力,解决串行问题. 对于NIO,轮询占用CPU效率,一般很少直接使用这种模型,而是在其他I/O模型中使用非阻塞I/O这一特性。 对于信号驱动,在一个tcp连接的生命周期内,有大量的信号需要监听,并且信号目的难以区分,使得对于socket几乎无用,在udp服务程序中可用。 对于AIO,需要底层操作系统支持,而linux系统并不完全支持异步,windows提供了IOCP的接口支持异步。 对于IO多路复用,使用select函数进行I/O请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的I/O请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个I/O请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。 调用select/poll该方法由一个用户态线程负责轮询多个socket,直到某个阶段1的数据就绪,再通知实际的用户线程执行阶段2的拷贝。通过一个专职的用户态线程执行非阻塞I/O轮询,模拟实现了阶段一的异步化。 了解了不同I/O的内容以及特点,如何利用这些知识开发一个并发web服务呢?还需要了解开发服务前需要考虑的性能瓶颈。 并发性能瓶颈高并发就是要解决这样两个问题:如何提高并发连接数?如何处理更快?要解决这两个问题,必须了解在一个网络请求场景下,有哪些因素导致性能瓶颈。 如何更快?消减IO损耗对CPU的占用,高效利用CPU。 简单来说,一个网络请求中,包含了CPU的运算及IO读取,IO读取又包含了CPU缓存、内存、硬盘及网络的读取。在计算机中,CPU的运算可以忽略不计,网络读取的时间 >>>> 硬盘读取的时间 >>>> 内存 >> CPU缓存,同时CPU是时间片轮转的,如果一个CPU的任务等待网络读取,那么与正常情况下相比,性能损失是上亿倍的。 非阻塞IO与异步IO就实现了网络IO读取与CPU运算的低耦合,提高IO处理速度,从内核态的角度进行优化。 如何更多?合理的利用内存资源。 最简单的并发处理是一个请求对应一条处理线程。其中存在两个问题,一个是创建线程与销毁线程的开销是很大的,基本会大于线程处理本身的开销;另一个是系统会为每个线程分配内存资源,不可控的生产线程可能会耗尽系统内存资源,导致服务崩溃。代码示例1 更好的一种做法是使用线程池来管理线程的创建以及回收,由线程池分配线程,并复用线程,如此可以控制并发数量,同时也提高了并发数量,减少了线程创建及销毁的开销,从用户态的角度进行优化。代码示例2 但这个做法仍然会存在一个问题:线程池大小与实际情况所需线程数量的关系不好确定,线程池太大会造成线程资源的浪费,线程池过小,根据线程池机制不同,有可能会导致服务被拒绝。在Java的线程池中,有着比较优雅的处理方式。 还有没有更优雅的方式呢?答案是有的。 事件驱动式编程事件驱动式编程,是一种异步消息通知的机制,需要注册事件触发条件,需要一个事件循环监听事件,在图形化编程中用的很广泛,如MFC。 在网络I/O中,多线程的方式能够有效地利用多核CPU的计算资源,但同时也消耗着内存等其他资源,当并发数上升时,吞吐性能会显著下降,资源占有率会明显升高,常见的模型图如下图: 相比之下,事件驱动式编程也可以看作分治法的一种实践,将一个IO过程划分为不同的子任务,非阻塞的读写+事件触发器。事件驱动式编程可以有效降低资源占用率,更少的线程处理更多的连接,而且编程相对简单。但是事件驱动式编程不适于CPU密集型的操作,比如某个handler的处理会占用很长时间,那么将会阻塞整个进程,而且在并发量不大的情况下,性能未必会超过多线程的方式。 多路复用之select/pollselect/poll是Reactor设计模式的实现,见下图: 在Reactor设计模式中,由一个线程不断循环等待,负责接受所有handler的注册,并负责向操作系统查询IO是否就绪,如果就绪就调用handler,这个线程的角色就是Reactor,也可以称为Dispatcher。 在select/poll模型中,由select/poll负责监视文件描述符的状态,一旦某个文件描述符就绪(可读或可写),能够调用回调函数进行处理。在这个过程中,select的动作是阻塞的,但是模拟了异步查询。 select是操作系统底层实现的,具体的实现可以参考源码,下图展示了基本的原理: 其中,FD_SET是加入文件描述符至集合,FD_ZERO是集合清零,FD_ISSET是查询文件描述符是否存在,FD_CLR是移除某个文件描述符。 select/poll大大减少了系统在线程切换方面的开销,提高并发性,但仍有可以改进之处: 每次调用select,都要把fd_set从用户态拷贝到内核态,fd_set很大时这是费时操作 每次调用select,内核态都要遍历fd_set,fd_set很大时这是费时操作 select支持的文件描述符数量太小,默认是1024 多路复用之epollepoll出现在linux内核2.6中,是之前的select/poll增强版本,相比select/poll只提供一个select或poll函数,epoll提供了三个函数操作:epoll_create(创建一个epoll句柄), epoll_ctl(注册监听事件), epoll_wait(等待事件产生)。 123int epoll_create(int size);int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 对于第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。 对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用schedule_timeout()实现睡一会,判断一会的效果)。 对于第三个缺点,epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。 非阻塞异步模型多路复用是同步的,Proactor提供了一种真正意义上的异步操作,性能更高。在Reactor中,应用注册的是读写就绪事r件,而在Proactor中注册的是读写完成事件,由操作系统实现异步操作。但由于需要操作系统级别的支持,所以有一定的局限性。 案例分析Apache and NginxApache和Nginx是目前网络上最流行的两款web服务器,可以参考调查,图例如下: 不过由于Apache产生的较早,基本的IO模型是一个进程对应一个请求,即同步阻塞+多进程(线程),导致了在当前的web场景下,不能够满足高并发的应用场景,通常设置最大值为256。 Nginx采用了epoll/kqueue模型,通过事件驱动的架构提高了并发性能,最大可以支持50000个并发连接数的响应,而且只占用极低内存(Nginx保持10000个活动连接,内存只需2.5M)。 浅析Nginx的设计架构: Nginx由一个master process负责创建很多子进程,其中非常重要的一点是worker进程的数量与cpu核数相同,能够最大化调优系统资源利用率。 Nginx的worker内部工作原理: 阻塞式状态机: web服务器主进程在服务端口上监听新的连接(客户端发起的新游戏的请求)。 有新的游戏请求时,主进程创建子进程负责完成跟客户端的对弈。主进程继续监听服务端口。 当游戏结束时,子进程要么等待client开始新游戏(通过keepalive机制保活一段时间连接)要么退出(keepalive超时后)。 这种模型每玩一局server都要创建一个对应的进程来完成对弈。这种架构简单并且容易容易扩展新功能,但有些大炮打蚊子,杀鸡用牛刀的感觉。进程是个重器,系统开销比较大,而解决的问题是个轻量级的问题。容易编程实现但是浪费比较大。 Nginx状态机: worker进程等待listen和connection sockets的事件。(译注:listen socket就是server用来监听新建连接的socket,connection socket是accept系统调用返回的新建socket,详细可参见accept的手册) 事件发生后,worker进程来处理这些事件: listen socket的事件表示有新的客户端要开始新的游戏。worker通过accept()创建新的connection socket,并加入监听列表。 connection socket的事件表示客户端走了一步棋,worker进程可以做下一步应对。worker进程从不会在网络IO上阻塞,当它应对完客户端的走棋走出自己的一步后,可以马上应对下一个客户端的走棋或接收新的连接请求。 Nginx的worker进程很容易扩展支持数十万并发连接。每个新接入的连接只需要创建新的socket消耗少量的内存,每个连接的系统开销相对要比进程开销小很多。另外通过Nginx worker进程绑定CPU技术可以进一步减少上下文切换和cache失效等系统开销。而阻塞式每个进程服务一个连接的方式,每个连接都会消耗很多资源,而且进程切换比较频繁导致系统开销比较大。 性能测试【quiz】 相同环境下安装apache,nginx uname -a:查看内核版本 head -n 1 /etc/issue:查看操作系统版本 cat /proc/cpuinfo:查看cpu信息 cat /proc/meminfo:查看内存信息 centos 7.x系统根据官方指南进行安装: yum install httpd yum install nginx 查看server版本: rpm -qa | grep nginx:nginx-1.8.1-1.el7.ngx.x86_64 rpm -qa | grep apache:httpd-2.4.6-40.el7.centos.x86_64 配置apache,nginx,linux 配置nginx: 配置apache 测试工具选择,进行测试 webbench -c 连接数 -t 时间 地址 分析结果 linux系统调优: 文件描述符 tcp调优 估算并发连接数: 考虑网络带宽,硬件配置 Java IOJAVA提供了BIO、NIO、AIO三种编程API,JDK针对不同的操作系统实现方式不同,如在linux2.6以后NIO以epoll实现,AIO以epoll实现;在windows下NIO以select实现,AIO以IOCP实现,具体可以参考JDK源码。 传统流I/O是基于字节的,所有I/O都被视为单个字节的移动;而NIO是基于块的,NIO的性能肯定优于流I/O,要得益于其使用的结构更接近操作系统执行I/O的方式:通道和缓冲器。我们可以把它想象成一个煤矿,通道是一个包含煤层(数据)的矿藏,而缓冲器则是派送 到矿藏的卡车。卡车载满煤炭而归,我们再从卡车上获得煤炭。也就是说,我们并没有直接和通道交互;我们只是和缓冲器交互,并把缓冲器派送到通道。通道要么 从缓冲器获得数据,要么向缓冲器发送数据。 NIO能够显著地提高IO并发数,但是不意味着任何场景都应该使用NIO,因为缓冲区中的数据不读取出来就无法去判断内容,需要根据场景来判断。 JAVA NIO编程Java抽象提供了一套NIO编程API,包含四个核心API方面:Channel,Buffer,Selector,SelectionKey 12345678910public abstract class ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannelpublic abstract class SocketChannel extends AbstractSelectableChannel implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannelpublic abstract class ByteBuffer extends Buffer implements Comparable<ByteBuffer>public abstract class Selector extends Object implements Closeablepublic abstract class SelectionKey extends Object Channel和Buffer之间的关系如下图所示: Selector的工作机制参考下图: 同时需要理解Buffer的工作机制,参考下图: Java NIO api发布于jdk1.4,在最新的jdk1.8中,对charset和流式处理做了优化。 一个单线程的Reactor实现可以参考[代码示例3] 但是单线程的Reactor并不适用于多核cpu,那么就有了Reactor的多线程实现模式,其中一种是Worker Thread Pools参考[代码示例], JAVA AIO编程Java AIO api发布于jdk1.7,常用类包含AsynchronousServerSocketChannel, AsynchronousSocketChannel, AsynchronousChannelGroup, CompletionHandler,有两种方式实现异步: Future集合 examples:123456789101112ExecutorService exec = Executors.newCachedThreadPool();AsynchronousServerSocketChannel asynServerSocketChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(5000));while (true) { Future<AsynchronousSocketChannel> future = asynServerSocketChannel.accept(); AsynSocketChannel channels = future.get(); exec.exectur(new Runnable() { @public void run() { ...... } })} CompletionHandler(callback)注册 jdk example: 12345678910111213final AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(5000)); listener.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() { @Override public void completed(AsynchronousSocketChannel result,Void attachment) { listener.accept(null, this); handle(result); } @Override public void failed(Throwable exc, Void attachment) { ... } }); [代码示例4] mina/netty的IO模型[代码示例5,根据AIO/NIO抽象出简单的编程模型然后与netty框架进行比较] [代码示例6,Multiple Reactors模型] 123456789Selector[] selectors;int next = 0;class Acceptor { public void run() { Socket connection = serverSocket.accept(); if (connection != null) new Handler(selectors[next], connection); if (++next == selectors.length) next = 0; } mina框架简介: netty框架简介: 事件驱动的方式编写客户端使得Apache崩溃[quiz] 模拟开发一个抢红包的web服务据各家IT公司公布的数据,今年除夕全天微信用户红包发送总量达到80.9亿个,红包峰值收发量达到40.9万个/秒, 不涉及架构内容,纯IO层,IM服务器如何去分析一个web应用的性能,不断地进行修改优案例:1亿个客户,于晚上八点准时开始抢红包,模仿微信抢红包的架构方案 测试过程,调优过程,分析过程 [代码示例] 性能调优如果想提高系能的性能,首先需要如何定义系统的性能,正如之前的并发性能瓶颈中所说的包含两个点: 吞吐量(throughput),每秒钟可以处理的请求数 延迟(latency),系统处理一个任务的延迟 一个系统的性能受限于这两个因素,缺一不可,一般来说,吞吐量越大,延迟会越差,因为系统繁忙会造成响应速度降低;延迟越好,吞吐量越大,处理每个任务更快,就可以处理更多的请求。 其次,需要了解如何测试系统性能:压力测试工具,有很多可以选择,之前使用过HP的loadrunner,编写C语言的测试脚本,还有很多其他开源的测试工具,可以参见附录中的链接。 最后,如何系统地定位性能瓶颈: 查看操作系统负载,了解CPU利用率,了解IO状态,了解网络带宽使用情况,了解代码问题。 使用Profiler测试(分析器),主要是对代码进行调优。 总结本文中,首先了解了IO并发中相关的概念及模型,然后讨论了构建高并发IO需要分析的性能瓶颈,进而讨论了事件驱动式编程的IO模型具体设计方法,比较多个主流的高性能IO实现,分析其所运用的基本原理,并通过性能测试对其性能进行评估,最后举例Java中的API实际运用。 五种模型强调的是提高CPU的利用率,进程或线程的应用强调的是计算资源的分配,结合这两点才能构建好的web服务程序。 参考资料 关于如何提高Web服务端并发效率的异步编程技术 如何提高服务器并发处理能力 Nginx的IO模型 知乎-多线程有什么用 进程切换开销 Java I/O模型的演进 Linux IO模式及select、polle、poll详解 Netty源码解读 select、poll、epoll之间的区别总结 一秒3W次请求的支付订单 Java做大并发网站的底层架构 多线程编程与事件驱动编程对比 nodejs在双十一中的应用 Java AIO 从运行原理及使用场景看Apache和Nginx NGINX vs. Apache: Our View of a Decade-Old Question The architechture of Nginx 一 100万并发连接服务器笔记之准备篇 windows与linux的异步IO在设计上的差异 Java并发的四种风格 Nginx架构详解 BIO|NIO|AIO(Java版) 在 Java 7 中体会 NIO.2 异步执行的快乐 Java AIO编程 性能调优攻略 Nginx折腾记 MAC下性能测试客户端 Java Web高性能开发 Nginx使用线程池提高性能 Java NIO通信框架在电信领域的实践 理解Java NIO Java NIO概述 Five ways to maximize Java NIO and NIO.2 netty实现原理浅析 为什么事件驱动这么火 C10k问题 netty mina in depth 高并发Web服务的演变——节约系统内存和CPU Netty系列之Netty百万级推送服务设计要点 Netty系列之Netty高性能之道","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"java","slug":"java","permalink":"http://lpbobo.com/tags/java/"},{"name":"design","slug":"design","permalink":"http://lpbobo.com/tags/design/"}]},{"title":"java内存模型及GC算法","slug":"Java Memory Model & GC","date":"2016-03-05T13:00:00.000Z","updated":"2016-05-08T14:44:20.000Z","comments":true,"path":"2016/03/05/Java Memory Model & GC/","link":"","permalink":"http://lpbobo.com/2016/03/05/Java Memory Model & GC/","excerpt":"jvm是java的运行平台,管理java对象的生存周期,熟悉jvm有助于编写性能更优的代码,同时调优高性能应用。如果这没吸引力,那么groovy,scala听过吧,都是跑在jvm上,魅力大否?","text":"jvm是java的运行平台,管理java对象的生存周期,熟悉jvm有助于编写性能更优的代码,同时调优高性能应用。如果这没吸引力,那么groovy,scala听过吧,都是跑在jvm上,魅力大否? 注:本文中的主要内容均来自网络整理,详见附录。 jvmjvm运行时的内存结构如下图所示: java内存模型(Java Memory Model)对象和类分别存储在三个不同的区域:堆、方法区、本地区,如下图所示: 堆内存(Heap Space)存放对象、数组的数据;方法区(Method Area)存放类的结构信息(类名、方法、字段)、静态变量、编译器编译后的代码; 在加载阶段主要用到方法区 本地区(Native Area)存放线程栈、本地方法栈; 从内存分配的角度,JMM如下图所示: Eden区存放新建的或短期的对象;Survivor区存放幸存的或者中期对象;老年区存放始终存在或长期的对象; 实例分析12345678910111213141516import java.text.SimpleDateFormat;import java.util.Date;import org.apache.log4j.Logger;public class HelloWorld { private static Logger logger = Logger.getLogger(HelloWorld.getClass().getName()); public void sayHello(String message) { SimpleDateFormat formatter = new SimpleDateFormat(\"dd.MM.YYYY\"); String today = formatter.format(new Date()); logger.info(today + \" : \" + message); }} 堆:logger,formatter,today,HelloWorld 方法区:SimpleDateFormat:{},Logger:{},HelloWorld:{} 本地区-线程栈:ParameterReference:message, LocalVariableReference:formatter,todayLocalPrimitiveType:lineN0. 从字节码到JVM内存模型,浅析JVM类加载过程参考附录4[java类加载过程分析] GC算法mark-sweep:标记,回收 copying:新生代,分块复制,回收 mark-compact:老年代,移动分界,回收 OutofMemoryErrorsException in thread “main”:java.lang.OutOfMemoryError: Java heap space 原因:对象不能被分配到堆内存中; Exception in thread “main”:java.lang.OutOfMemoryError: PermGen space 原因:类或者方法不能被加载到老年代。它可能出现在一个程序加载很多类的时候,比如引用了很多第三方的库 Exception in thread “main”:java.lang.OutOfMemoryError: Requested array size exceeds VM limit 原因:创建的数组大于堆内存的空间 Exception in thread “main”:java.lang.OutOfMemoryError: request bytes for . Out of swap space? 原因:分配本地分配失败。JNI、本地库或者Java虚拟机都会从本地堆中分配内存空间 Exception in thread “main”:java.lang.OutOfMemoryError: (Native Method) 原因:同样是本地方法内存分配失败,只不过是JNI或者本地方法或者Java虚拟机发现 附录 并发编程网-Java的内存模型及结构 并发编程网-深入理解Java内存模型 深入理解JVM之JVM内存区域与内存分配 java类加载过程分析 JVM内幕:java虚拟机详解","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"java","slug":"java","permalink":"http://lpbobo.com/tags/java/"}]},{"title":"centos安装mysql-server-5.7.10","slug":"centos下安装mysql","date":"2016-03-05T11:00:00.000Z","updated":"2016-05-08T14:59:39.000Z","comments":true,"path":"2016/03/05/centos下安装mysql/","link":"","permalink":"http://lpbobo.com/2016/03/05/centos下安装mysql/","excerpt":"提供linux下mysql安装的思路,参照网络上的博客内容(打脸……)并不是一个好的方式官网才是解决问题的王道。","text":"提供linux下mysql安装的思路,参照网络上的博客内容(打脸……)并不是一个好的方式官网才是解决问题的王道。 查看系统环境cat /etc/redhat-release > CentOS Linux release 7.2.1511 (Core) uname -a > Linux host-192-157-1-20 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux 安装mysql 习惯性地在google上输入了”centos 安装 mysql5.7”,搜出来的都是博客教程,有用rpm安装的,有编译源码安装的,其实选择合适的教程,跟着一步步做是没有问题的,然而就怕半路出错,教程中往往缺少一步步验证的环节,也没有提供查错方法,照着博主的套路走,突然发现站在分叉口,又没有回头路,感觉分外不爽啊,解决半路问题的时间才是大头。 那么我就在自己的这篇博客心得里,一点点记录自己在安装mysql的过程中碰到什么问题,又是如何解决的吧: 跟着博客来这是一个看似快速实则慢吞吞的方法。 博客中描述的获取mysql源的方法不能用 mysql版本不够新 官网为王道 每个项目都有自己的主页,里面一般包括架构设计,文档,教程,问题,安装等材料,由于大多是外文的,所以一大部分的中文博客都是从项目主页翻译过来的,还不一定有没有错误。 官网的好处就是一脉相承,材料出自源头,能够保证正确性;访问者能够提出质疑;全面,一般包含各种环境下的说明。 每当我们想要更深入、更快速地研究一项技术时,官网绝对是最值得逛的地方,看看协议内容,看看官方的tutorial,看看API文档,物超所值,流连在网络上的一篇篇琐记中,达不到好的效果。 当然,有时遇到十分具体的问题,或者引出的技术,可以参考stackoverflow这样的地方,看别人的博客,重点还是看解决问题的过程吧。 在花费了半天的时间照着一个博客搭建不成功后,我就转到了mysql官方主页去查看,一步步找到了教程的地址: 纯净安装: http://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html#yum-repo-installing-mysql 升级安装: http://dev.mysql.com/doc/refman/5.7/en/updating-yum-repo.html 替换安装: http://dev.mysql.com/doc/refman/5.7/en/replace-third-party-yum.html 配置远程访问配置远程访问账号: mysql -u USER -pPASSWORD GRANT ALL PRIVILEGES ON *.* TO remote@"%" IDENTIFIED BY PASSWORD WITH GRANT OPTION; flush privileges; 开放3306端口: quit; vi /etc/sysconfig/iptables 添加一行: -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT 重启iptables: /etc/rc.d/init.d/iptables restart stackoverflow解决iptables的问题 远程测试(windows): cd mysql server\\bin mysql -u root -pPASSWORD -h SERVERIP -P PORT","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"java","slug":"java","permalink":"http://lpbobo.com/tags/java/"}]},{"title":"Java8新增特性","slug":"whats new in jdk8","date":"2016-03-02T13:00:00.000Z","updated":"2016-05-07T15:23:29.000Z","comments":true,"path":"2016/03/02/whats new in jdk8/","link":"","permalink":"http://lpbobo.com/2016/03/02/whats new in jdk8/","excerpt":"jdk8于2014年发布,之前经常会在网络上看到对Java不够简洁的批评,但其实Java也可以写出十分有优美的代码,看看jdk8都有哪些新增特性。","text":"jdk8于2014年发布,之前经常会在网络上看到对Java不够简洁的批评,但其实Java也可以写出十分有优美的代码,看看jdk8都有哪些新增特性。 lambda表达式 a function (or a subroutine) defined, and possibly called, without being bound to an identifier. 1Arrays.asList(\"a\", \"c\", \"b\").forEach( e -> System.out.println(e)); 函数接口使现有的功能与lambda表达式更好的结合: 函数接口是一种只有一个方法的接口,不包含静态方法和default方法,如果想要添加多个方法,则需要加上”@FunctionalInterface”注解 12345@FunctionalInterfacepublic interface Functional { void method(); default void method();} 可以参考:并发编程网 接口增强 接口中可以声明默认方法,默认方法可以不被实现类重载,也可以被重载,默认方法提供默认实现 123456789101112131415private interface Defaultable { default String notRequired() { return \"not required\"; }}private class DefaultableImpl1 implements Defaultable {}private class DefaultableImpl2 implements Defaultable { @override public String notRequired() { return \"implemented\"; }} 接口中可以声明静态方法 12345678910111213private interface DefaultableFactory { static Defaultable create(Supplier<Defaultable> supplier) { return supplier.get(); }}public static void main(String[] args) { Defaultable defaultable = DefaultableFactory.create(DefaultableImpl1::new); System.out.println(defaultable.notRequired()); defaultable = DefaultableFactory.create(DefaultableImpl2::new); System.out.println(defaultable.notRequired());} Stream API目的:为了弥补java函数式编程的缺陷,map/reduce内置。 流式操作,实现对集合的并行处理和函数式操作。流可以分为并行和串行两种,实现了过滤、排序、映射等功能。 创建流12345public static void main(Stringp[] args) { List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Stream<Integer> stream = numbers.stream(); stream.filter(x -> return x%2==0).map(x -> x*x).forEach(System.out::println);} 为什么用流 延迟计算,减少内存占用 迭代计算隐藏在map等操作中 使用流1234567891011121314151617class FibonacciSupplier implements Supplier<Long> { long a = 0, b = 1; @Override public long get() { long x = a + b; a = b; b = x; return a; }}public class FibonacciStream { public static void main(String[] args) { Stream<Long> fibonacci = Stream.generate(new FibonacciSupplier()); fibonacci.limit(10).forEach(System.out::println); }} 方法引用 方法引用提供了一个很有用的语义直接访问类或者对象的已经存在的方法或者构造方法,与lambda表达式配合使用,更简洁 1234567891011121314public class Car { public static Car Create(final Supplier<Car> supplier) { return supplier.get(); } public static void Collide(final Car car) { System.out.println(\"Collided\" + car.toString()); } public void repair() { System.out.println(\"Repaired\" + this.toString()); } public void follow(final Car car) { System.out.println(\"Followed\" + car.toString()); } } 构造方法引用 Class::new或Class::new 12final Car car = Car.create(Car::new);final List<Car> cars = Array.asList(car); 静态方法引用 Class::static_method,方法参数为Car 1cars.forEach(Car::collide); 类实例方法引用 Class::method,无方法参数 1cars.forEach(Car::repair); 引用特殊类方法 instance::method,方法参数为Car 12final Car police = Car.create(Car::new);cars.forEach(police::follow); 注解的更新:类型注解与重复注解重复注释本书需要被@Repeatable注释 安全性IO/NIO优化IO/NIO优化,改进编码、解码,流式操作,简化文本处理全球化功能(时间,unicode)工具包改进和增强","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"Java","slug":"Java","permalink":"http://lpbobo.com/tags/Java/"}]},{"title":"调查SocketServer拒绝客户端连接的问题","slug":"调查socketserver connection refused","date":"2016-02-05T08:20:00.000Z","updated":"2016-06-03T02:30:29.000Z","comments":true,"path":"2016/02/05/调查socketserver connection refused/","link":"","permalink":"http://lpbobo.com/2016/02/05/调查socketserver connection refused/","excerpt":"调查Socket server拒绝客户端连接的问题,server由Java Mina编写,深入tcp底层探索问题原因。","text":"调查Socket server拒绝客户端连接的问题,server由Java Mina编写,深入tcp底层探索问题原因。 问题描述: java开发的实时报表服务器,负责处理客户端的请求报文,采用Mina框架实现IO层。昨天客户端突然报来一个问题:多个页面实例对应多个客户端线程,同时去连接服务器,第一个请求之后的都会被拒绝,如果间隔500ms去连接,不会出现问题。 当时就分析了下客户端的日志,发现基本是相隔2ms就会发送一条xml报文。当时以为服务端的日志会报出异常,就邮件让客户取了回来,结果发现并没有,而客户端的open connection是必现的。客户比较紧急,就花时间仔细分析下问题,加强自己对tcp的理解,尽管花费几天,但最终问题还是解决了。 问题会在哪?客户端与服务端建立tcp的过程图如下所示: 从已有的知识储备,自己提出了几个疑点: 之前做过压力测试,并没有出现这种问题,会不会是客户端的原因,造成了open connection失败? server accept是会阻塞的,mina采用的是selector模型,在select时是会阻塞的。会不会是这个阻塞的时间超过了客户端多次连接的间隔,造成了客户端的连接被拒绝? 如果客户端没有问题的话,那么tcp连接建立过程还需要两个环节:host + server,host是windows server 2008, server就是我们的程序,会不会问题出现在系统的配置? 初步分析 tcp连接的四元组:源ip,源port,目的ip,目的port。socket是面向tcp的接口,服务端监听socket与accept产生的socket非同一个,如果服务端使用同一个socket实例,那么客户端再次连接时会报10056(socket is already connected)的错误。 如果可以重现问题的话,可以排除客户端程序的问题。 问题只会发生在ms间隔内产生多个连接时。 mina支持非阻塞IO,在三个客户端的情况下,select的阻塞也不至于产生连接被拒绝的问题。 那么问题是不是出现在服务器的配置呢,有什么参数能够影响到瞬时连接的个数呢? 重现问题为了能够观察到tcp连接的过程,重新问题出现的过程,我在自己的windows机器上搭建了socketserver的环境,同时编写客户端的测试程序,之前使用loadrunner写的c语言脚本,在自己的机器上,还是用python处理最快,最方便。 客户端请求的报文体类型为xml,报文头16个字节,内容为报文正文长度,十六进制表示。在编写python脚本的时候,需要设置十六进制的报文头,才能被server正确接收: 123456789# 设置十六进制报文头,python headerHexStr = \"35303100000000000000000000000000\"headerHex = \"\"while headerHexStr: hexStr = headerHexStr[0:2] s = int(hexStr, \"16\") headerHex += struct.pack(\"B\", s) headerHexStr = headerHexStr[2:]print headerHex python client完整程序: 123456789101112131415161718import socket, struct, threading def handler(message): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # serverip,port stands for the real value s.connect((\"serverip\", port)) s.send(message) s.recv(1024) s.close()body=\"<?xml version=\\\"1.0\\\" encoding=\\\"GB2312\\\"?><body></body>\"message = headerHex + body num = 0while num < 5: t = threading.Thread(target=handler, args=(message,)) t.start() num = num + 1 果然,运行这段脚本的时候,从客户端能够看到[Errno 111] Connect Refused错误,5个客户端连接只有第一个被连接。如果在每个线程启动前都增加5ms的超时时间,连接就会被处理。 此时,服务端明显暴露问题,但是在socket server的日志中没有发现任何异常,也就是说连接在host就被拒绝了,那么是不是host的配置问题呢? 纠察操作系统四种情况下模拟测试(W: windows 7,C:centos): W作为客户端,C作为服务端; W作为客户端,W作为服务端; C作为客户端,W作为服务端; C作为客户端,C作为服务端; C的机器性能要比W好一些,四种情况下只有第三种会出现Errno 111。 可能是最近受到《High Performance Browser Networking》这本书的影响,自然将注意力放到了windows机器上。 在客户端上加了些时间点,发现centos的客户端发送socket的请求速度比windows要快很多。是不是因为client发送socket请求过快,导致了windows的机器无法处理呢? 于是乎我在网上开始到处搜集windows系统下的tcp优化方案,集中在注册表的参数修改上,试了一些却依然没有效果。 那么问题到底在哪?看来还是需要抓包分析一下在tcp建立的过程中到底发生了什么。 抓包分析之前一直没有用过抓包工具,总觉得很神奇,有点打怵,实际用起来也还是很方便的。 抓包的结果见下图,132是客户端,136是服务端: [RST,ACK]包的具体内容见下图: 分析:第97行是第一个客户端发送的SYN,98行是服务端返回的[SYN,ACK],99行是第二个客户端发送的SYN,100行提示服务端返回[RST,ACK],重置连接,之后的三个连接也是如此。 服务端会在什么情况下收到SYN后返回[RST,ACK]呢? 遇到问题时,除了google,程序员还有另一项神奇:SO。 stackoverflow在网站上提了一个问题: Windows server 2008 send [RST, ACK] packets while several clients ask for tcp connections at the same time(less than 5ms) 13个小时以后就有人回了一条: The issue is that you have filled the backlog queue, whereupon Windows starts issuing resets to further incoming connection requests. This could be because you specified a small backlog value, but the more likely cause is that your server is simply not accepting connections fast enough: your accept loop is fiddling around doing other things, such as DNS calls or even I/O with the client, all of which should be done in the client’s thread. All the accept loop should do is accept sockets and start threads. 什么是backlog? backlog,主要是指当ServerSocket还没执行accept时,这个时候的请求会放在os层面的一个队列里,这个队列的大小即为backlog值,这个参数对于大量连接涌入的场景非常重要,例如服务端重启,所有客户端自动重连,瞬间就会涌入很多连接,如backlog不够大的话,可能会造成客户端接到连接失败的状况,再次重连,结果就会导致服务端一直处理不过来(当然,客户端重连最好是采用类似tcp的自动退让策略),backlog的默认值为os对应的net.core.somaxconn,调整backlog队列的大小一定要确认ulimit -n中允许打开的文件数是够的。 os上还提供了net.core.netdev_max_backlog和net.ipv4.tcp_max_syn_backlog来设置全局的backlog队列大小(一个是建立连接的queue总队列的大小,一个是等到客户端ACK的SYN队列的大小)。 [修改于2016-06-03日],也就是说,backlog形容的是Established队列的大小,是listen(socket, backlog)的第二个参数。[deprecated: 也就是说,backlog形容的是server在与客户端建立tcp连接的过程中,SYN队列的大小,在socket的listen接口中,一般第二个参数就是backlog的大小。] 在之前的优化windows系统tcp连接参数中,也看到过在注册表的AFD/parameters下设置tcp backlog参数,显然三个连接就被拒绝不是因为windows host的backlog过小导致的。 解决问题问题已经基本定位:server的backlog值过小。 查看mina的api文档,看到了SocketAcceptor有setbacklog()/getbacklog()的接口,在查看spring下的配置,果然发现了在acceptor的bean配置中,包含了backlog属性,而这个值就是1。 backlog=1,看到这,就知道问题的根本原因已经找到了。 总结解决这个问题前前后后一共花费了我4天的时间,恢复代码花了半天。尽管最后问题的产生的根本是来自一个配置项,但是举一反三,之后对server优化的思路更加明确了,会更加得心应手。 时间是长了一点,但是思维基本是明确的,有一段时间一直怀疑是windows的问题,对于server和host之间的微妙关系不太理解,花了好长的时间在优化注册表、重启机器、替换机器、重启…… 仔细想想,问题的导火索确实是client的多个tcp在5ms内进行连接,拒绝连接的实施者是windows。自己兜圈子的地方是拒绝连接的号令者:windows or server? 兜圈子的原因还是对tcp连接的过程不够熟悉,几遍三次握手也包含了很多细节的过程,想想自己看xmpp协议的过程,觉得有必要再从根本上啃一啃这块硬骨头。 生产过程中,经常会遇到很多紧急的问题,排除障眼法,直捣黄龙是需要经验和知识的积累的,keep on moving! 附录[Errno 111] Connection Refused.Use a packet sniffer like Wireshark to look at what happens. You need to see a SYN-flagged packet outgoing, a SYN+ACK-flagged incoming and then a ACK-flagged outgoing. After that, the port is considered open on the local side. If you only see the first packet and the error message comes after several seconds of waiting, the other side is not answering at all (like in: unplugged cable, overloaded server, misguided packet was discarded) and your local network stack aborts the connection attempt. If you see RST packets, the host actually denies the connection. If you see “ICMP Port unreachable” or host unreachable packets, a firewall or the target host inform you of the port actually being closed. Of course you cannot expect the service to be available at all times (consider all the points of failure in between you and the data), so you should try again later. window size scaling factor: -1(unknown) 通过wireshark抓到的[ACK, RST]响应报文中,有这样一个看起来很让人怀疑的提示window size scaling factor: -1(unknown) It means that the trace file does not contain the TCP three-way handshake, so Wireshark does not know whether window scaling is in use, and if it is, what the window scaling factor is. If Wireshark sees the three-way handshake, and window scaling is used, Wireshark will know what window scaling factor is used by each side. Wireshark will then calculate the true window size for you by multiplying the value in the window size field by the appropriate multiplier. If Wireshark does not see the three-way handshake, it will simply report the value of the window size field, which may or may not be the true window size, and indicate “[window size scaling factor -1 (unknown)]” See RFC 1323 for the specification of the TCP window scale option.","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"socket","slug":"socket","permalink":"http://lpbobo.com/tags/socket/"}]},{"title":"Java单例模式","slug":"Java单例模式","date":"2016-02-04T11:00:00.000Z","updated":"2016-05-12T03:06:02.000Z","comments":true,"path":"2016/02/04/Java单例模式/","link":"","permalink":"http://lpbobo.com/2016/02/04/Java单例模式/","excerpt":"单例模式应用在某个类只产生一个实例对象的情况,通常资源,如线程池、日志对象、打印机、显卡驱动被设计为单例,单例可以进行统一资源分配。","text":"单例模式应用在某个类只产生一个实例对象的情况,通常资源,如线程池、日志对象、打印机、显卡驱动被设计为单例,单例可以进行统一资源分配。 方法一public class Singleton() { private Singleton() {}; private static final Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } } 这种方法被称为饿汉式,在类创建时就已经产生了实例对象,因而线程安全。 方法二public class Singleton() { private Singleton() {}; private static Singleton instance = null; public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 这种方法被称为懒汉式单例,但是会出现线程不安全的问题,解决方法通常有以下几种: 方法三getInstance前加同步锁,但影响效率。 方法四双重检查锁定 方法五内部静态类,延迟加载","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"Java","slug":"Java","permalink":"http://lpbobo.com/tags/Java/"}]},{"title":"centos搭建git server","slug":"Git server","date":"2016-01-20T11:20:00.000Z","updated":"2016-05-07T15:17:21.000Z","comments":true,"path":"2016/01/20/Git server/","link":"","permalink":"http://lpbobo.com/2016/01/20/Git server/","excerpt":"centos7下搭建git server环境。","text":"centos7下搭建git server环境。 git的分布式、分支管理、高效比svn要更吸引人,公司的svn server已经第二次崩溃,果断使用git管理自己的本地代码。 检查环境:cat /etc/redhat-release> centos linux release 7.1.1503(core) git安装首先检查是否已经安装git: 1git version 若未安装,则需安装依赖包: 1yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-devel 从另一台机器上翻墙下载git tar包,然后上传至centos服务器: 1scp git-1.9.0-tar.gz root@SERVERIP:PATH 按照提示,输入密码。 然后在centos上cd进入PATH,编译git源码: 1234567891011tar -zxf git-1.9.0.tar.gzcd git-1.9.0make configure./configure --prefix=/usrmake all doc infosudo make install install-doc install-html install-info 安装完成后,检验: git version > git version 1.8.3.1 创建git用户123adduser gitpasswd git 手动管理登录证书客户端生成SSH Keys,创建公钥/私钥对,用于认证: 参见如何生成SSH keys指南 将public key上传至服务器: 1scp id_rsa.pub root@SERVERIP:PATH 服务端如果/home/git下没有.ssh目录,则新建一个 1mkdir .ssh 修改.ssh目录的权限 123chmod 700 .sshchown -R git:git .ssh 收集所有用户的公钥,即id_rsa.pub文件,将公钥导入/home/git/.ssh/authorized_keys文件中,一行一个 1cat id_rsa.pub > authorized_keys 修改authorized_keys权限 1chmod 644 authorized_keys 配置sshd参数 1vi /etc/ssh/sshd_config 修改以下项目: 12345RSAAuthentication yes PubkeyAuthentication yes StricModes no 重启sshd,使配置生效 1service sshd restart 初始化git仓库在git用户目录下初始化仓库 1234567mkdir repocd repo git init --bare PROJECT.gitchown -R git:git PROJECT.git 客户端克隆远程仓库1git clone git@SERVERIP:/home/git/repo/PROJECT.git 常见问题 客户端每次连接git服务器时都需要输入密码 permission denied 参考资料 git 廖雪峰的博客","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"git","slug":"git","permalink":"http://lpbobo.com/tags/git/"}]},{"title":"Https","slug":"https","date":"2015-11-23T09:00:00.000Z","updated":"2016-05-06T04:46:18.000Z","comments":true,"path":"2015/11/23/https/","link":"","permalink":"http://lpbobo.com/2015/11/23/https/","excerpt":"几句话说明白https的加密过程","text":"几句话说明白https的加密过程 做银行的信息系统,https加密无可厚非 1.从网络资源和公司的交流材料中研究https的基本原理,有一张图说的很对。 123456789在客户进行https访问时,提交的信息与返回的信息都是通过session key进行对称加密的。 session key需要客户端与服务端协商产生,这个过程就是握手。握手的过程是确保primary-master-key的安全性,客户端产生的随机数由服务端提供的公钥加密,服务端通过私钥解密。如何保证信息没有篡改,对端没有被顶替呢?公钥包含在可信的数字证书中,由CA颁发,用来保证对端可信。未被篡改是通过hash值校验进行的。 2.openssl heartbleeding openssl实现库的漏洞,危机使用openssl开源库的各个服务器提供者。 openssl的心跳机制可以被恶意利用,能够访问到服务器的内存。内存值会包含很多敏感信息,最恐怖的是包含服务器的私钥。。。。 3.参考资料 【1】SSL/TLS协议运行机制的概述【2】图解SSL/TLS协议【3】Https总结理解","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"Protocol","slug":"Protocol","permalink":"http://lpbobo.com/tags/Protocol/"}]},{"title":"Java开发WebService","slug":"Webservice","date":"2015-11-20T08:00:00.000Z","updated":"2016-05-07T15:22:13.000Z","comments":true,"path":"2015/11/20/Webservice/","link":"","permalink":"http://lpbobo.com/2015/11/20/Webservice/","excerpt":"通过Java开发WebService服务,实现方式有两种SOAP与REST,其中SOAP是基于XML的RPC解决方案,而REST是一种软件架构风格,描述了访问资源的方式。","text":"通过Java开发WebService服务,实现方式有两种SOAP与REST,其中SOAP是基于XML的RPC解决方案,而REST是一种软件架构风格,描述了访问资源的方式。 导语: Amazon是web服务的先驱,很早提出了web服务的概念,可以将亚马逊的数据和功能暴露给第三方的开发者.Webservice是基于web的远程服务调用,可以用来构建分布式的网络系统,使得“本地”服务能够以接口的形式发布在网络上被其他应用访问,使网络透明化。 WebService是一种抽象的远程方法调用的解决方案,在此之前已经存在RPC、CORBA、DCOM、RMI等手段: 1234* RPC(远程方法调用)* CORBA(公共对象请求代理体系结构)* DCOM(分布式组件对象模型)* Java RMI(Java远程方法调用) WebService的特点包含以下几个方面: 123* 标准化:使用http,json,xml等标准的协议和数据格式* 语言透明:客户端、Web服务可以使用不同语言来编写,Web服务独立于硬件平台以及操作系统* 模块化设计:小的模块可以组合成大的模块,大的模块可以细分为更小的模块 那么,目前webservice有哪些实现形式呢? 1 SOAP Simple Object Access Protocol,即简单对象访问协议 SOAP是一个开放协议,使用xml作为数据传输格式,使用http作为消息传输协议。 基于SOAP的Web服务必须为客户端提供wsdl文档,由请求者根据WSDL来调用Web服务。 WSDL: Web Services Description Language,即Web服务描述语言 WSDL文件示例 在本文中,通过实现同一个应用场景来展示不同Java WebService实现方式的特点。例子如下: 例子-需求描述: 一个在线用户管理模块,负责用户信息的创建,修改,删除,查询。用户的信息主要包括: 用户名(唯一ID) 邮箱 电话 例子-需求用例图: 例子-SOAP架构 所有的SOAP消息发送都使用HTTP POST方法,并且所有SOAP消息的URI都是相同的,这是基本特征。 SOAP客户端与服务端的实现# JAX-WS Java API for XML Web Services JAX-WS可以作为开发基于SOAP或REST服务的API,提供基于注解的标准模型简化服务端与客户端开发,是JavaEE6之后的版本必需部分。 JAX-WS的API主要提供两种注解:注解为@WebService的POJO类提供基于SOAP的服务,注解为@WebServiceProvider的POJO类通常提供一个REST式服务,但是也可以同时提供SOAP服务。 JAX-WS的实现框架有以下几种:GlassFish Metro,Apache Axis2,Apache CXF。其中,GlassFish Metro是JAX-WS的参考实现,Axis2和CXF为替代实现方案。但是不论哪种具体的实现方式,本质上都是基本相同的,精通一种便可举一反三。 # Metro代码示例1 Metro(@Version SOAP , Metro , Eclipse Kepler) 2 REST REpresentational State Transfer,即表征状态转移 REST是一种软件架构风格,不是一个具体的协议规范,它可以用于分布式超媒体系统,也可以用于以文字、图形、音频和其他媒体格式存储在网络,并通过超链接互联的系统中。 WWW不就是一个例子嘛? REST架构把HTTP作为APIREST式客户端通过指定以下两个内容来请求资源: URI 1234567在REST架构中,通过HTTP请求的内容统称为资源,即**URI**。URI包含两个子类型:URL和URN,其中URL是指指定的一个位置,URN是一个资源的名称。通常,在文档书写时,我们将URI定义成WebService的接口。[新浪微博开放平台](http://open.weibo.com/wiki/%E5%BE%AE%E5%8D%9AAPI)提供的微博URI示例:https://api.weibo.com/statuses/public_timelinehttps://api/weibo.com/2/statuses/showhttps://upload.api.weibo.com/2/statuses/upload 指定HTTP的动作(CRUD) 1在URI的基础上,指定http请求的动作,如创建(POST),读取(READ),更新(UPDATE),删除(DELETE)及参数,便可访问web资源,而请求结果包含在http响应中,包含MIME类型的资源和响应代码。 一个REST式客户端请求资源的过程示例如下: 发布WebService# 通过HttpServlet实现REST WebService HttpServlet HttpServlet扩展了GenericServlet类,从而实现了Servlet接口,被包含在Web容器提供的servlet-api.jar包中。 Servlet接口声明了5种方法,其中最重要的是Web容器在每次请求一个servlet时调用的service方法。service方法的参数包含一个ServletRequest和ServletResponse,分别包含客户的请求信息及应答信息。 HttpServlet重载了service方法,并提供特定的HTTP实现,其service方法包含的参数为HttpServletRequest和HttpServletResponse。 HttpServlet还具有与CRUD匹配的doGet, doPost, doPut, doDelete方法,由service负责将客户的HTTP请求动作分配到对应的方法中。 HttpServlet是实现REST式Web服务的重要方法,原因有以下两点: 与HTTP请求相近,包含CRUD的动作及状态响应码 在servlet容器中执行,容器充当了该servlet的应用程序代码与Web服务器之间的中间件,而Web容器可以提供很多通用服务,如:HTTPS传输,用户验证等 # Web容器发布WebServiceJava中常用的Web服务器有以下几种: 123456789轻量化的Web服务器: tomcat: servlet container Jetty: servlet container Resin: servlet containerJava应用服务器: GlassFish: EJB & servlet container JBoss: EJB container WebLogic: servlet container(not free) WebSphere: servlet container(not free) REST服务端的实现常见的四种API: HttpServlet及JSP JAX-RS Restlet JAX-WS @WebServiceProvider 例子-REST架构: 例子-REST API: 1234567GET /users 获取user列表GET /users/id 获取指定{id}的userGET /users/id/email 获取指定{id}的user的email信息POST /users 创建用户PUT /users/id/email 更新某个用户的emailDELETE /users/id 删除指定{id}的用户注: endpoint是相对于统一URL的:URL/v1 # HttpServlet代码示例2 HttpServlet(@Version Tomcat7.0.64, Eclipse Kepler) # JAX-RS Java ApI for RESTful Web Services JAX-RS的API定义于java.ws.rs包中,通过标注封装Web资源。标注包括: @Path @GET, @PUT, @POST, @DELETE @Produces @Consumes @PathParam, @QueryParam, @HeaderParam, @CookieParam, @MatrixParam,@FormParam JAX-RS的具体实现由第三方提供,如参考实现Jersey,Apache的CXF和Wink,JBOSS的RESTEasy。 代码示例3 Jersey(@Version Jersey2.14, Tomcat7.0.64, Eclipse Kepler) 代码示例4 Jersey+Spring(@Version Jersey2.14, Spring4.1.4.Release, Tomcat7.0.64, Eclipse Kepler) # Jax-WS @WebServiceProviderJAX-WS API提供的@WebServiceProvider提供的API相较其他方式更为低层,更贴近http和xml。 代码示例5 @WebServiceProvider(@Version Tomcat7.0.64, Eclipse Kepler) 如何设计Restful APIAPI很重要!好的API设计可以减少沟通的工作量,文档的工作量。 越容易使用的API,越会被使用。 在API的基础上,可以将一个个的服务逐步构建成大的平台。 RESTful API Design没有特定的规范要求,但一些设计者在经验的基础上提出了好的Restful API设计原则: 123456789- 抽象分离数据与业务逻辑:- 支持PUT,DELETE,POST,GET及PATCH动词- 包含版本信息- api子域- endpoint- 减少无谓的过滤器限制- 状态码- OAuth2.0授权协议- 内容类型 REST VS SOAP在上文中,针对同一个应用场景,分别给出了基于SOAP和REST的实现,便于比较两种实现方式的特点。 从以下几个方面比较: # 接口抽象RESTful WebService使用标准的 HTTP 方法 (GET/PUT/POST/DELETE)来抽象服务请求动作,而SOAP通过定义自己个性化的接口方法来抽象 Web 服务,这更像RPC。 RESTful WebService使用标准的HTTP API,结合其他的标准化技术,如 URI,HTML,XML 等,将会极大提高系统与系统之间整合的互操作能力。尤其在Web领域,RESTful WebService所表达的这种抽象能力更加贴近Web本身的工作方式,也更加自然。 同时,使用标准HTTP方法实现的RRESTful WebService也带来了HTTP方法本身的一些优势: 无状态性(Stateless) HTTP协议从本质上说是一种无状态的协议,客户端发出的 HTTP 请求之间可以相互隔离,不存在相互的状态依赖。基于HTTP的ROA,以非常自然的方式来实现无状态服务请求处理逻辑。对于分布式的应用而言,任意给定的两个服务请求Request 1与Request 2,由于它们之间并没有相互之间的状态依赖,就不需要对它们进行相互协作处理,其结果是:Request 1与 Request 2可以在任何的服务器上执行,这样的应用很容易在服务器端支持负载均衡(load-balance)。 安全操作与幂指相等(Safety/Idempotence) HTTP的GET、HEAD请求本质上应该是安全的调用,即:这些调用不会有任何的副作用,不会造成服务器端状态的改变。对于服务器来说,客户端对某一URI做n次的GET、HAED调用,其状态与没有做调用是一样的,不会发生任何的改变。HTTP的PUT、DELTE调用,具有幂指相等特性 , 即:客户端对某一 URI 做 n 次的 PUT、DELTE 调用,其效果与做一次的调用是一样的。HTTP 的 GET、HEAD 方法也具有幂指相等特性。HTTP 这些标准方法在原则上保证你的分布式系统具有这些特性,以帮助构建更加健壮的分布式系统。 # 安全控制为了说明问题,基于上面的在线用户管理系统,我们给定以下场景:参考一开始我们给出的用例图,对于客户端 Client2,我们只希望它能以只读的方式访问 User 和 User List 资源,而 Client1 具有访问所有资源的所有权限。 如何做这样的安全控制? 通行的做法是:所有从客户端 Client2 发出的 HTTP 请求都经过代理服务器 (Proxy Server)。代理服务器制定安全策略:所有经过该代理的访问 User 和 User List 资源的请求只具有读取权限,即:允许 GET/HEAD 操作,而像具有写权限的 PUT/DELTE 是不被允许的。如果对于 REST,我们看看这样的安全策略是如何部署的。如下图所示: 一般代理服务器的实现根据 (URI, HTTP Method) 两元组来决定 HTTP 请求的安全合法性。当发现类似于(http://localhost:8080/demo/v1/users/{id},DELETE)这样的请求时,予以拒绝。对于 SOAP,如果我们想借助于既有的代理服务器进行安全控制,会比较尴尬,如下图: 所有的 SOAP 消息经过代理服务器,只能看到(http://localhost:8182/v1/soap/servlet/messagerouter, HTTP POST)这样的信息,如果代理服务器想知道当前的 HTTP 请求具体做的是什么,必须对 SOAP 的消息体解码,这样的话,意味着要求第三方的代理服务器需要理解当前的 SOAP 消息语义,而这种 SOAP 应用与代理服务器之间的紧耦合关系是不合理的。 # 缓存众所周知,对于基于网络的分布式应用,网络传输是一个影响应用性能的重要因素。如何使用缓存来节省网络传输带来的开销,这是每一个构建分布式网络应用的开发人员必须考虑的问题。 HTTP 协议带条件的 HTTP GET 请求 (Conditional GET) 被设计用来节省客户端与服务器之间网络传输带来的开销,这也给客户端实现 Cache 机制 ( 包括在客户端与服务器之间的任何代理 ) 提供了可能。HTTP 协议通过 HTTP HEADER 域:If-Modified-Since/Last- Modified,If-None-Match/ETag 实现带条件的 GET 请求。 REST 的应用可以充分地挖掘 HTTP 协议对缓存支持的能力。当客户端第一次发送 HTTP GET 请求给服务器获得内容后,该内容可能被缓存服务器 (Cache Server) 缓存。当下一次客户端请求同样的资源时,缓存可以直接给出响应,而不需要请求远程的服务器获得。而这一切对客户端来说都是透明的。 而对于 SOAP,情况又是怎样的呢?使用 HTTP 协议的 SOAP,由于其设计原则上并不像 REST 那样强调与 Web 的工作方式相一致,所以,基于 SOAP 应用很难充分发挥 HTTP 本身的缓存能力。 两个因素决定了基于 SOAP 应用的缓存机制要远比 REST 复杂:其一、所有经过缓存服务器的 SOAP 消息总是 HTTP POST,缓存服务器如果不解码 SOAP 消息体,没法知道该 HTTP 请求是否是想从服务器获得数据。其二、SOAP 消息所使用的 URI 总是指向 SOAP 的服务器,如本文例子中的 http://localhost:8080/demo/v1/soap/servlet/messageroute,这并没有表达真实的资源 URI,其结果是缓存服务器根本不知道那个资源正在被请求,更不用谈进行缓存处理。 # 连接性一个纯的 SOAP 应用中,URI 本质上除了用来指示 SOAP 服务器外,本身没有任何意义。与 REST 的不同的是,无法通过 URI 驱动 SOAP 方法调用。例如在我们的例子中,当我们通过getUserList SOAP 消息获得所有的用户列表后,仍然无法通过既有的信息得到某个具体的用户信息。唯一的方法只有通过 WSDL 的指示,通过调用 getUserByName 获得,getUserList 与 getUserByName 是彼此孤立的。 而对于 REST,情况是完全不同的:通过 http://localhost:8080/demo/v1/users URI 获得用户列表,然后再通过用户列表中所提供的 LINK 属性,例如 http://localhost:8080/demo/v1/users/1获得"1“用户的用户信息。这样的工作方式,非常类似于在浏览器的某个页面上点击某个 hyperlink, 浏览器帮你自动定向到你想访问的页面,并不依赖任何第三方的信息。 # SOAP的优势?类似XMPP,可以支持任何标准的传输协议,不仅仅是Http/Https。 SOAP是一个标准协议,具备良好的协议规范,比较成熟,而REST是一套架构,没有标准规范,SOAP往往被用在大型企业和网络架构中。 支持WS-Security,增加了一些企业级的安全控制功能。 支持WS-AtomicTransaction,支持ACID事务操作。 支持WS-ReliableMessaging,支持可信通信。 总结起来, 123REST以资源为中心,适用场景包括:有限的带宽和资源,完全无状态操作,缓存,多种类型的数据格式。SOAP以操作为中心,适用于REST不适用的场景,包括:异步处理与调用,形式化契约,有状态的操作。 目前,WEB中REST已经基本取代了SOAP。 webservice接口安全基于WSDL的SOAP协议支持WS-Security安全规范进行认证、授权、身份管理。 RESTful Webservice呢? 主要在以下几个方面: 线路层的安全性 12345+ 客户端与服务端在传输层确保不与冒名顶替者通信+ 传输数据要加密,不能够被拦截器解密+ 保证发送端与接收端的消息一致解决方案:HTTPS 用户身份认证和授权+ 用户认证,用户向服务端提供凭据信息 + 角色授权,授权不用用户角色的资源访问范围 1示例:OAuth2.0 结语通过Webservice可以很方便得构建出一个Web服务接口层的框架,但如何使用框架并不是我们最关心的要点。我们的注意力应该集中在如何设计更好的API,如何抽象自己的服务,如何更深刻地理解HTTP,如何做更好的分布式网络架构。 附录 xml与json中国部分省市数据举例: 123456789101112131415161718192021222324252627282930313233**XML**:<?xml version=\"1.0\" encoding=\"utf-8\" ?><country> <name>中国</name> <province> <name>黑龙江</name> <citys> <city>哈尔滨</city> <city>大庆</city> </citys> </province> <province> <name>广东</name> <citys> <city>广州</city> <city>深圳</city> <city>珠海</city> </citys> </province> <province> <name>台湾</name> <citys> <city>台北</city> <city>高雄</city> </citys> </province> <province> <name>新疆</name> <citys> <city>乌鲁木齐</city> </citys> </province></country> 12345678910**JSON**:{ name: \"中国\", provinces: [ { name: \"黑龙江\", citys: { city: [\"哈尔滨\", \"大庆\"]} }, { name: \"广东\", citys: { city: [\"广州\", \"深圳\", \"珠海\"]} }, { name: \"台湾\", citys: { city: [\"台北\", \"高雄\"]} }, { name: \"新疆\", citys: { city: [\"乌鲁木齐\"]} } ] } json更适合机器阅读,Web应用广泛,轻量,清晰,冗余少 xml更适合人阅读,可读性更强,大型应用的配置文件 maven@Version maven3.2.5 基本功能: 1自动化构建 + 依赖管理 + 项目信息管理 POM.xml: 1通过<groupId>, <artifactId>, <packaging>, <version>标签唯一确定一个项目,也称作maven坐标 常用命令: 123456789mvn archetype:generate -DgroupId= -DartifactId= -DarchetypeArtifactId=mvn clean, install, compile mvn packagemvn eclipse:eclipsemvn eclipse:clean 仓库: 123local:本地文件路径./m2 central:maven repository(http://mvnrepository.com/) 标准的目录结构: 1234567891011project |--pom.xml |--src/main/java |--src/main/resource|--src/test/java|--src/test/resource 常见问题: dynamic web project 与 maven工程转换 缺少maven library maven与eclipse的关系 tomcat, glassfish等servlet容器三篇参考博文: Servlet工作原理解析 Tomcat系统架构与设计模式(1) Tomcat系统架构与设计模式(2) 参考内容 Web服务编程,REST与SOAP Java Web服务构建与运行(第2版) REST VS SOAP","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"Java","slug":"Java","permalink":"http://lpbobo.com/tags/Java/"},{"name":"Webserivce","slug":"Webserivce","permalink":"http://lpbobo.com/tags/Webserivce/"}]},{"title":"XMPP & BOSH (3)","slug":"Xmpp & Bosh (3)","date":"2015-11-03T12:00:00.000Z","updated":"2016-05-12T03:06:42.000Z","comments":true,"path":"2015/11/03/Xmpp & Bosh (3)/","link":"","permalink":"http://lpbobo.com/2015/11/03/Xmpp & Bosh (3)/","excerpt":"strophe,一个由JS实现的Xmpp库。","text":"strophe,一个由JS实现的Xmpp库。 XMPP客户端实现xmpp协议的基本是C/S架构,客户端负责的主要功能是与服务端建立tcp连接,实现TLS认证,SASL授权,之后便可以传输xml流。 从xmpp.org/clients的官网可以看到很多的开源的xmpp client的实现库(尽管不全),在我们的项目中,由于涉及到web、ios、android sdk开发,自然客户端的实现需要参考多个lib库,所以之前研究xmpp的协议机制还是有必要的,刨除语法糖,只需认识到xmpp的协议本质即可。 一个xmpp客户端需要实现的核心协议参考:RFC3920,RFC3921;需要实现的XEP参考:xmpp extensions。 strophestrophe是一个开源的、js实现的xmpp client library,最早是在图书馆的一本《XMPP高级编程 使用Javascript和JQuery》书中接触到。 strophe实现XMPP选用的底层通讯协议有两种:BOSH和WEBSOCKET,这两种协议都是标准的,分别定义在(XEP124和XEP206)和RFC7395中。 本文使用的是strophe1.2.3),服务器是Openfire3.10.2,操作系统是OS X Yosemite Version10.10.5。 源码简介strophe基本实现了哪些协议, 基本的代码结构 接口 HelloWorld实例构建首先,搭建openfire服务器()。 其次,构建HTML的应用程序。","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"xmpp","slug":"xmpp","permalink":"http://lpbobo.com/tags/xmpp/"}]},{"title":"以色列谷(Israel Vally)","slug":"Israel Vally","date":"2015-10-31T02:00:00.000Z","updated":"2016-05-06T04:46:16.000Z","comments":true,"path":"2015/10/31/Israel Vally/","link":"","permalink":"http://lpbobo.com/2015/10/31/Israel Vally/","excerpt":"一直以来,有三个国家的民族历史、精神文化、科技工业深深地吸引着我,今天算是一盘开胃菜,采摘《以色列谷》中的佳肴,分享,萃取。","text":"一直以来,有三个国家的民族历史、精神文化、科技工业深深地吸引着我,今天算是一盘开胃菜,采摘《以色列谷》中的佳肴,分享,萃取。 南山书城早读。 一直以来,有三个国家的民族历史、精神文化、科技工业深深地吸引着我,今天算是一盘开胃菜,采摘《以色列谷》中的佳肴,分享,萃取。 不要设定自己的极限,不断push自己,给自己压力,让自己忙碌,敢于冒险。 对其他领域产生兴趣,追寻新的学业,新的工作,新的领域,保持一颗求知心。 集群,创新谷,沃土,是关系、技术、研究、资本、基础设施、政策的网络交织。 Unistream,与商业世界的奥秘建立联系可以大大增加成功的概率。(让我想起了马太效应) 以色列人吸引投资者的要素是以色列的人力资源,以色列人面对危机的能力,面对挑战的反应力。 创新分为两种:颠覆或进步。 竞争情报收集,是以色列人的一种自发性的信息战略。收集陌生领域,创新的创业公司以及合作伙伴和竞争对手的思维模式。 以色列是花在社交网络上时间最长的国家:facebook,twitter,linkedin。 孵化器方向:软件,生命科学,医学设备,环境,水科学,信息和通信技术。孵化器构成:经验丰富的领导者,项目委员会,财务、技术、行政、法律、市场的支持,创业者(研发实力+出口潜力)。 清洁技术:避免荷兰症候群。 生命科学:梯瓦公司。 创新技术之盾: 12345+ 横向性:存在于原本相异的子集之间多个交集;+ 韧性:恢复力;+ 缘分:偶然的发现,编织网络;+ 决裂:与既定的框架决裂。铁笼决裂。需要根本性的技术创新,新的商业模式和新的价值网络;+ 协同效应:集群; 资源与技能关键 123+ 资源:教育-未来的关键价值,文化多样性,强制兵役;+ 技能:根据自身的资源(下游,贸易营销空间狭小)集中价值链(上游,研发创新设计); + 未来的产业:创新(联系的能力,超前的精神看待事物); 大卫之盾:人力,信息,创业,新型企业孵化,未来预测,国防科技。 谈起以色列谷,就会联想到硅谷,前沿产业的创新发动机。这种集群的产生源于多方面因素,地理环境,政治环境,经济环境,文化环境,但是一批又一批优秀的创业者、企业家不断投入自己的精力,去开创一片天,对年轻的后辈来说,无疑是一种激励。成功的充分因素可以多种多样,但是必要的因素却可以从榜样中提取。如何去突破自己?不安于现状,不被框架羁绊,不害怕失败。如何去创造未来?广阔的视野,合理的资源,坚持不懈的努力。 反思过去的自己,看齐明天更好的自己。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"Book","slug":"Book","permalink":"http://lpbobo.com/tags/Book/"}]},{"title":"XMPP & BOSH (2)","slug":"Xmpp & Bosh (2)","date":"2015-09-21T01:00:00.000Z","updated":"2016-05-08T15:01:09.000Z","comments":true,"path":"2015/09/21/Xmpp & Bosh (2)/","link":"","permalink":"http://lpbobo.com/2015/09/21/Xmpp & Bosh (2)/","excerpt":"BOSH: Bidirectional-streaming over synchronous HTTP","text":"BOSH: Bidirectional-streaming over synchronous HTTP BOSH Bidirectional-streaming over synchronous HTTP BOSH是一种通过HTTP模拟实现端与端之间TCP长连接的技术,简单说就是建立两个网络实体间的双向HTTP长连接。与基于HTTP的双向连接技术,包括comet,ajax轮询以及websocket相比较,BOSH是一种较早的实现,而且具有高效、低延迟的优势,能够适应具有较高实时性要求的应用。 BOSH是在XEP-0124扩展协议中被制订。 BOSH的设计能够满足以下几点应用的要求: 能够在受限的环境下,如移动设备、浏览器中运行; 兼容缓存部分HTTP应答的代理; 能够快速通过有HTTP应答时间限制的代理; 兼容HTTP/1.0;(comet不支持) 兼容受限的网络连接,如防火墙,代理,网管; 容错; 可扩展; 更小的带宽占用; 更快的响应速度; 支持轮询; 顺序提交数据; 防止非法的HTTP插入请求; 防止拒绝服务攻击; 多路复用的数据流; 设计架构123456789Server | | [unwrapped data streams] |HTTP CM | | [HTTP + <body/> wrapper] |Client 参考博文,在BOSH的设计框架中,HTTP连接管理器(CM)与Server之间是原始的数据流,而客户端与CM之间的是包裹在body节点下的HTTP数据流。 实现方式当客户端发送一个请求时,连接管理器不马上应答,而是保持当前的连接直到有数据可以返回。当客户端收到返回时,继续发送新的请求。 如果连接管理器保持当前的连接超时了,就会回给客户端一个空的body,出发客户端新的请求,这样可以保持连接激活,以免被中断,同时也可以检查连接状态。 当客户端与连接管理器支持持续连接时(如HTTP/1.0中的”Connection: keep-alive”,或者HTTP/1.1的默认项),不会重新建立socket,减少花销。 当客户在等待一个请求应答时,想发送新的请求,若不支持pipeline,会与连接管理器建立新的连接。此时,连接管理器会立刻返回上个请求的应答,保持当前的请求。 XMPP Over BOSH那么XMPP是如何利用BOSH来传输XML流的呢? 答案是HTTP绑定。 XEP-0206在BOSH协议的基础上制定了XMPP相关的接口,从而在一些tcp连接不适用的情况下(如手机上),可以通过BOSH实现实时通讯。","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"xmpp","slug":"xmpp","permalink":"http://lpbobo.com/tags/xmpp/"}]},{"title":"XMPP & BOSH (1)","slug":"Xmpp & Bosh (1)","date":"2015-09-20T01:00:00.000Z","updated":"2016-05-07T15:24:24.000Z","comments":true,"path":"2015/09/20/Xmpp & Bosh (1)/","link":"","permalink":"http://lpbobo.com/2015/09/20/Xmpp & Bosh (1)/","excerpt":"XMPP is the Extensible Messaging and Presence Protocol, a set of open technologies for instant messaging, presence, mulity-party chat, voice and video calls, collaboration, lightweight middleware, content syndication, and generalized routing of XML data.","text":"XMPP is the Extensible Messaging and Presence Protocol, a set of open technologies for instant messaging, presence, mulity-party chat, voice and video calls, collaboration, lightweight middleware, content syndication, and generalized routing of XML data. 近期在做一个呼叫中心项目,需要通过平台的BOSH服务器开发即时通讯功能,连接Agent与Client。其中,Agent是构建在java服务器上的web坐席,而Client是swift实现的IOS客户端。Agent可以调用平台封装的xmpp js库,客户端需要自己实现功能。 本着不局限于集成开发的态度,督促自己深入了解了xmpp相关的知识,同时也因为一直想做社交IM相关的产品,就认真研究了xmpp协议。 参考xmpp官网,熟悉协议;参考Blog资源,整理思路;参考两本书籍:《Xmpp - The Definitive Guide》和《Professional Xmpp Programming with Javascript and Jquey》,补充内容,最终成文。 XMPP官方定义: XMPP is the Extensible Messaging and Presence Protocol, a set of open technologies for instant messaging, presence, mulity-party chat, voice and video calls, collaboration, lightweight middleware, content syndication, and generalized routing of XML data. The Extensible Messaging and Presence Protocol(XMPP) is an application of the Extensible Markup Language(XML) that enables the near-real-time exchange of structured yet extensible data between two or more network entities.(RFC 6120) xmpp定义了在两个或多个通讯实体之间传递小型的结构化数据所采用的协议,在此基础上可以用来构建大规模即时通信系统、协作系统以及语音和视频会议。 xmpp交换的数据格式为xml,通用,便于扩展。 发展历史xmpp的前身是诞生于1999年的jabber。类似于很多开放的协议,在此之前是群雄混战的时代,各家自扫门前雪。很多公司开发的IM应用程序绑定各自的协议和网络,这使得第三方开发人员集成不同的应用代价很高。 开放、去中心化的IM网络和协议促使了jabber的出现。 伴随着jabber社区的健壮,jabber不断吸收新的想法,衍生出多种多样的客户端实现,在2000年得以稳定,并被正式发布。 Jabber Software Foundation于2001年成立,并在2002年向IETF标准化进程提交了核心协议。IETF在2004年的RFC3920与RFC3921中发布了XMPP协议,并在之后陆续发布了XEP(xmpp extension proposal)扩展协议(官方链接)。 特点xmpp协议的优点主要在以下几个方面: open: 开放,xmpp协议是免费的,公开的,社区资源很丰富 Standard: 标准,由IETF标准化过程正式发布 Proven: 实用,Google Talk等大型应用由此构建 Decentralized: 去中心化,类似email,支持server2server,面向客户本身,而非面向资源(关于去中心化,可以参考英雄帖) Secure: 安全,内置TLS以及SASL加密 Extensible: 易扩展,xml显神威 Flexible: 灵活,支持的应用场景丰富 Diverse: 多样,后宫强大 核心 RFC6120: The purpose of XMPP is to enable the exchange “XML stanzas” over a network between two or more entities. xmpp协议的核心技术包括以下几点:XML数据流层,TLS加密传输,SASL安全验证,utf-8编码,状态描述,状态订阅,花名册管理。 一个完整的xmpp连接生命周期包括以下几个部分: Client-Server架构 1234567891. 解析服务端的地址及端口2. 与服务端建立TCP连接3. xml流初始化4. TLS信道加密5. SASL授权6. XML流绑定本地资源7. 开始数据交换8. 关闭XML流9. 关闭TCP Server-Server架构 123456781. 解析服务端的地址及端口2. 建立TCP连接3. xml流初始化4. TLS信道加密5. SASL授权6. 直接开始数据交换,或者作为代理进行7. 关闭XML流8. 关闭TCP JID 任何的xmpp实体都会在网络上注册一个名字,俗称JID,格式为:localpart@domainpart/resourcepart,可以通过DNS解析。 其中:123domainpart -> Server address: 形如im.example.com localpart -> Server Account Address: 形如host@im.example.comresourcepart -> Resource Address: 形如host@im.example.com/resource 逻辑上来说,xmpp实体在网络上的对应关系为peer-to-peer,实际来说,是client-to-server-to-server-to-client的关系。 注意,对于同一个client,resource name不同,就可以建立多个连接。 TCP连接限制client与server需要建立tcp长连接。 在XEP中规定了xml流可以不绑定在tcp协议上,也可以绑定在如http协议上。 域名解析方法:DNS-SRV 重连策略: 重连超时时间设置为0-60s 在连续的重连过程中,不断增长尝试的间隔 建议使用TLS session resumption进行重连 可靠性:XEP-0198中解决了如何解决tcp长连接可靠性的问题 XML流基础XML Stream表示数据交换的容器,声明周期在中。 XML Stanza是一级节点,包括:message,presence,iq(Info/Query)。节点的namespace属性值:jabber:client 或者 jabber: server。 123<message>: a "push" mechanism for generalized messaging;<presence>: a specialized "publish-subscribe" mechanism for broadcasting information about network availability<iq>: a "request-response" mechanism for more structured exchange of data. #### 过程 交换stream头 1234567891011121314151617181920请求: <xml version='1.0'?><stream:stream from='juliet@im.example.com' to='im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>应答:<xml version='1.0'><stream:stream from='im.example.com' id='++TR84Sm6A3hnt3Q065SnAbbk3Y=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> stream negotiation 就是服务端向客户端声明面试过程(tls,sasl..),而且面试过程是有先后顺序的,面试题目包裹在< stream:features>节点下。 closing a stream xml流可以随时被关闭,形式为: directionality 不同的使用情况下可以在同一个tcp连接上建立不同数量的xml流 handling of silent peers 异常处理的情况:tcp失效,xml流堵塞,对端空闲 use of checking methods 建议根据实际网络环境确定检查连接的时间间隔,推荐至少5分钟 stream attributes ‘from’:发送方的JID ‘to’:接收方的JID ‘id’:当前流的唯一标示符,server端必须在开始时包含 ‘xml:lang’:默认语言 ‘version’:标识协议版本,1.0+ xml namespaces 约束命名空间 stream errors 参考协议内容,寻找错误原因 STARTTLS Negotiation该协议是TLS协议的扩展协议,主要防止链路被干扰、监听。 SASL Negotiation简单验证安全层,为基于连接的协议增加认证能力。xmpp提供的xml命名空间描述遵守sasl的描述规范。 Resource Binding在JID中有一项就是resource,是同一用户多处同时登陆的基础。在每次建立连接后,都是在某一resource上进行通信。 xmpp RFC6120一共描述了16章节的内容,上文只简单概括了前7章的大致内容,至此client与server端可以开始进行数据交换,后续的主要是对xml stanza的具体处理。这里面的内容太多了,而且没有代码说起来不是在,还是在遇到问题的时候,开发过程中逐渐熟悉吧。 单纯地阅读协议还是无法感受到xmpp是如何发展起来的,我在xmpp系列的第七篇博客里再横向比较吧。","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"xmpp","slug":"xmpp","permalink":"http://lpbobo.com/tags/xmpp/"}]},{"title":"盐","slug":"trip","date":"2015-09-16T08:06:00.000Z","updated":"2016-05-26T15:14:25.000Z","comments":true,"path":"2015/09/16/trip/","link":"","permalink":"http://lpbobo.com/2015/09/16/trip/","excerpt":"","text":"18岁就开始飘荡的我们,一路向南,一直在旅途上。 两个人相伴,时间长了,就要去看看外面的世界,一起踏上旅途,经历新鲜的感觉,享受最真实的现在,品尝最美好的回忆。","categories":[{"name":"Trip","slug":"Trip","permalink":"http://lpbobo.com/categories/Trip/"}],"tags":[{"name":"trip","slug":"trip","permalink":"http://lpbobo.com/tags/trip/"}]},{"title":"油","slug":"art","date":"2015-09-16T08:03:00.000Z","updated":"2016-05-26T15:14:23.000Z","comments":true,"path":"2015/09/16/art/","link":"","permalink":"http://lpbobo.com/2015/09/16/art/","excerpt":"","text":"普通的我们过着不平凡的生活,热爱自然的真善美,聆听美丽的音符。","categories":[{"name":"Art","slug":"Art","permalink":"http://lpbobo.com/categories/Art/"}],"tags":[{"name":"art","slug":"art","permalink":"http://lpbobo.com/tags/art/"}]},{"title":"米","slug":"love","date":"2015-09-16T08:00:00.000Z","updated":"2016-05-26T15:13:40.000Z","comments":true,"path":"2015/09/16/love/","link":"","permalink":"http://lpbobo.com/2015/09/16/love/","excerpt":"","text":"有人说世界上没有爱情,两个人热恋的时候是激情,结婚之后是亲情,哪里有爱情。 哪怕一瞬间,虽然我们无法证明爱的存在,但我们仍可以坚信她的存在,大声对彼此说“我爱你”。","categories":[{"name":"Love","slug":"Love","permalink":"http://lpbobo.com/categories/Love/"}],"tags":[{"name":"love","slug":"love","permalink":"http://lpbobo.com/tags/love/"}]},{"title":"柴","slug":"hello-world","date":"2015-06-29T16:00:00.000Z","updated":"2016-05-26T15:14:15.000Z","comments":true,"path":"2015/06/30/hello-world/","link":"","permalink":"http://lpbobo.com/2015/06/30/hello-world/","excerpt":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","categories":[{"name":"Science","slug":"Science","permalink":"http://lpbobo.com/categories/Science/"}],"tags":[{"name":"hexo","slug":"hexo","permalink":"http://lpbobo.com/tags/hexo/"}]}]}