无论你相不相信,每一个程序的日志都记录了一个完整的故事,一个由代码和数据相互交谈而产生的故事。就像大家人类的故事同样,这里面既有平常杂事,又有奇事趣闻,天然也少不了各类喜怒哀乐。只要你仔细聆听,就必定可以听懂。程序员
请注意,当我在说这些话的时候,我并非在打一个比喻,而是在描述确凿的事实,就像太阳的东升西落那样无可置疑。每一个日志中记录的故事,在那个世界都曾经真切的发生过。若是你仍是不相信,请阅读下面这个故事,它是个人一段亲身经历。这个故事就记录在一个程序日志里,而这个日志文件至今还躺在主人的笔记本电脑中的某个位置,随时供人查阅。算法
哦,对了,你还不知道我是谁?其实跟故事自己比起来,这并不那么重要。我只是数字空间(Cyberspace)里一个普通的字节(Byte)。我能够随身携带8个比特(Bit)的信息,请叫我0x30。数据库
按照大家人类的说法,我是个男生。为了叙述方便,姑且按照这样的方式来定义吧——奇数值的字节是女生,偶数值的字节是男生。这样说的话,如今紧挨着我坐一块儿的这两位,0x35和0x32,一位是女生,而另外一位就是男生喽。一样是为了叙述方便,下面我给他们各起一我的类的名字,0x35叫小丽,0x32叫小明。而我呢,若是大家愿意,能够叫我小白。编程
在咱们三个碰到一块儿以前,咱们已经在数据库里睡了几个世纪之久(固然是按照数字空间的时间单位)。多半是由于受到某个网络请求的触发,咱们被加载到了内存里。此刻,咱们位于一个很庞大的对象实例的内部。我粗略估算了一下,同咱们一块儿被加载进来的,大概还有几千个字节,他们大部分都存储在这个对象内部的一个List中。c#
等了一会,负责执行CPU指令的进程老大跑过来告诉咱们,“你们注意,大家立刻就要被发送到一条TCP长链接上去,对方正在等待大家所携带的信息。因为这是一个串行的通道,因此,大家所在的整个对象首先要被序列化(Serialization)。”安全
我正在困惑之际,没想到小丽率先替我问出了心中的疑问:服务器
“序列化?那是什么意思啊?”网络
她说话的声音很好听,就像某个电台的女主播。我不由有些恍惚。分布式
“序列化就是按字节前后排成一队,就好像回龙观西大街上的汽车要通过北郊农场桥,全部车最后都必须并到一个车道上去。”进程老大耐心地向咱们解释道。工具
而后,咱们按照一种被称为protobuf的数据格式完成了序列化。听说,这种数据格式是由一个「不存在」的国际化大公司设计出来的。无论那么多了,如今重要的是,咱们原来在同一个对象实例内部的全部字节被排成了长长的一队,并且我发现,队伍中还插入了一些额外的字节。最后队伍的总长度达到了3400个字节。
在序列化以后的队伍中,小丽,小明,和我,咱们三个仍然挨在一块儿。我排在第1461个字节位置,而他们俩都在我前面。也就是说,小丽排在第1459个字节位置,小明排在第1460个字节位置。
算法小哥告诫咱们,队伍一旦排好,顺序就绝对不能再变了,并且全部字节一个都不能少。不然,到了接收端,咱们将没法被反序列化(Deserialization)。这固然也包括新插入的那些字节,好比站在队头的那几个,他们携带着整个队伍的长度信息,相当重要。
“伙计们,如今大家已经组成一个完整的消息(Message)了。一帆风顺!”说完,进程老大就将咱们由字节组成的整个消息队伍扔到了协议栈的buffer之中。
协议栈的buffer就像一间很大的候车大厅,咱们并排坐在里面,当心地保持着原来的次序。
负责维护协议栈的内核程序告诉咱们,TCP通道上正在进行流量控制(Flow Control),缘由是TCP另外一端的接收窗口目前不容许咱们发送。因此,须要咱们耐心等待。
为了打发无聊的时间,我就跟前面的小丽和小明他们攀谈了起来。聊了一阵子,小明忽然提议说:“反正也闲得无聊,要不咱们一块儿玩个游戏?”
“好啊好啊,真心话大冒险怎么样?”我赶忙附和,并用眼角的余光扫了一下小丽。
小丽迟疑了一下,“这个有点太刺激了,要不咱们仍是来个文艺点的吧。每一个人讲一个故事如何?看谁讲的故事精彩!”
对于女人的建议,我和小明天然都欣然采纳,“那就这样,按顺序来,女士优先吧。”
小明又补充道:“毕竟咱们都生活在数字空间,并且,大家知道吗——咱们的听众基本上都是程序员。因此我建议,故事最好要跟程序员或编程有关。”
小丽听完白了他一眼,不置能否。
接下来,小丽用她凄婉的语调讲述了一个令咱们全部人都感动不已的故事。
窗外是淅淅沥沥的小雨,而她的心情也跌落到了谷底。她想象着那些冰冷的雨滴,滴答滴答,落在肌肤上,浸透她的全身。
古灵儿躺在床上,睁着大眼睛瞪着天花板。她从药瓶中又倒出了一粒药片,动做娴熟地一口吞进了肚子里。已是第十粒安定片了,却了无睡意。她如今有点怀疑网上的说法,安眠药吃到100片真的能致人死命吗?
她如今还有最后一件事要作,这也是她最后的一点但愿了。她把已经关机了好几天的手机从新拿出来,开机,而后把卸载掉的各类社交软件也从新安装了回来。
除了那些讨债的人,没有任何人联系她。她的爱人没有任何消息,没有短信,没有留言,没有未接电话。
那些上门讨债的人曾经告诉过她,她的老公携款潜逃了,带走了他们的血汗钱。直到如今,古灵儿也都不相信,那个深爱她的男人会抛下她无论。但事实彷佛无可争辩,她老公的朋友圈最后一次更新仍是在两个月前,也就是他忽然消失不见的前几天。
最近这些日子,是她人生中最痛苦的一段经历。为了躲避那些上门讨债的人,她搬了好几回住处,卸掉了全部的社交软件,甚至不少时候不得不把手机关掉,但手机号却一直坚持没换,由于她怕老公联系不到她。至今她仍然心存幻想,幻想着忽然收到他的消息,而后他会向她解释全部这一切。
其实她对最近发生的事情一直都很迷惑。他老公的公司经营得一直还算顺利,甚至在他消失的前不久,他还踌躇满志地告诉她公司立刻就要进入下一轮融资了。直到两个月前,一群人忽然闯进她们的家里,宣称她老公的公司产生了上亿的坏帐,并要求她替丈夫还债。而她居然也真的联系不到他了。
如今她知道了,幻想终归是幻想,她的心从新变得冰冷。她又拿出药瓶,吞下一粒。此刻,她头脑中只剩下一个念头,就这么吃下去,直到永远睡去。
忽然,「叮」的一声,手机收到了一条推送。她一把抓过手机,居然是来自她已经好久不玩的一款App——名字叫「微爱」的情侣软件。那是好久好久以前,她和她的前男朋友,也是她的初恋,一块儿在「微爱」上开通的私有空间。本是小孩子的把戏,两我的天天坚持浇灌一棵虚拟的爱情树。早在两年前他们分手以后,她就再也不玩了。没想到,那个像傻瓜同样的他却还在坚持。手机推送告诉她,对方已经连续浇水超过2000天了,他们的爱情树又升到了一个新的等级。
思绪如快速生长的草木通常,触及到了一段尘封的记忆。
两年前,那也是一个雨天,五月的一个雨天。天气本应是温暖宜人的,但那天却格外阴冷。就像今天同样。
“咱们仍是分手吧。”有多少次想说,却始终没法开口。终于,古灵儿仍是把那个句子吐了出来。
苏秦表情木然地站在那里,本来就黯淡无光的眼睛完全蒙上了一层灰纱。
再也不有悲伤和争吵。该吵的,该闹的,该哭泣的,都已通过去了。在一块儿三年多了,两我的之间细小的战役也断断续续地持续了三年。
该走的终会走。
这并不能怪古灵儿。整日面对这样一个吊儿郎当的男人,哪一个女人又会有安全感呢?提及来有点讽刺,苏秦,跟古代那个「头悬梁,锥刺股」的苏秦是同一个名字,可怎么就没有一点相像呢?那时,他毕业后干程序员这一行也好几年了,不只没得到任何升职机会,甚至工资都没涨过太多。他这性格从上大学那会就一直这样,平日里嘻嘻哈哈,东游西逛,历来不会认认真真地钻研点东西,还常常花大把的时间打游戏。干程序员这一行的,本应是个高薪行业,他周围的不少同窗早就买房买车了。
而古灵儿的家里人一直对她的婚事催个不停。稍微有点理智的女人,都会像她这样选择的。跟苏秦相比,她后来的丈夫无论哪一点,都要强上一万倍。没想到......
一样没想到的是,在这样晦暗的时刻,他又以另外的一种方式出如今她的面前。她忽然想起了他过去全部的好,想起了他骑着自行车带着她游遍了北京城的每个角落,想起了那一天,当她最后转身离开的时候,苏秦向着她在雨中的背影大声地喊:“灵儿,我会等你回来的!”
古灵儿从床上爬起来,走到穿衣镜前。她缓缓地脱去身上的睡衣,扔在一边,镜中出现了她憔悴的面容、赤裸而日渐瘦弱的身体。一股巨大的悲伤感向她袭来,如汹涌的波涛通常。她再也控制不住本身,两行热泪夺眶而出。
她蹲在卧室的地上哭了半个小时。最后,她拿起手机,从通信簿中找到了苏秦的号码。
“讲完了?”
面对我和小明的问题,小丽点了点头。
“你这故事跟程序员一点关系也没有啊!”小明提醒她。
“怎么没有?那个前男朋友就是个程序员呢!”小丽反驳说。
“但故事情节跟程序员不要紧啊......”小明大概是感受有点说不清楚,换了个问法,“那他会写复杂的程序吗?他是个技术高手吗?”
“不是。这根本不重要!”小丽一脸不耐烦地回答。
“你这故事是真的吗?”我问小丽。
“固然了!我就曾参与过那次关键的推送,我是那条推送消息里的一个字节。”小丽回答问题的同时,也说出了本身的来历。
“后来他们怎么样了呢?”我继续追问。
“她和苏秦吗?固然是幸福地在一块儿了啊。”
“那古灵儿的老公欠的的那些债务呢?最后怎么解决的呢?”
小丽对这个问题彷佛也不太感兴趣,“我也不清楚了。估计苏秦会帮她打官司吧。她应该没有义务承担这笔债务吧。”
正在这时,协议栈的内核程序忽然又跑过来,向咱们喊道,“快点准备!立刻要出发了!对方的TCP接收窗口已经打开。”说着,他打量了一下全部这3400个字节,补充道,“如今buffer里字节太多,对方的接收窗口一会儿装不下。这样吧,前面2000个字节先走!”
紧接着,协议栈各个协议层的子程序又在咱们这2000个字节的最前面加上了20个字节的TCP头,而后又在前面增长了20个字节的IP头,最后,又在这2040个字节的前面和后面都增长了链路层的帧头和帧尾。
咱们从内网上行路由器的一个出口出来,进入了一条光纤通道。路由器上的路由程序告诉咱们,下一站是广州的一个节点。
“咱们这一站要走3000多千米啊!”
“可不是嘛!”
咱们三个又开始闲聊起来。
小丽感到很困惑,“咱们的出发地点和目的地好像都在北京,为何要先到广州走一圈呢?”
“这多是一种路由策略。我猜多是网络运营商在南方的线路资源比较便宜,才会给出这样的路由。也多是一种配置错误。”我根据我仅有的一点网络知识,向小丽解释。
“对咱们会有什么影响吗?”小丽不无担忧的问。
“咱们中间会通过更多的路由节点,延迟会高一些。若是跳转节点过多,而咱们的IP包头的TTL (Time To Live)又被耗尽的话,咱们可能被总体丢弃掉。”我忽然意识到把问题说得太严重了,赶忙又补充了一句,“不过这种丢弃的状况不多见啦。”
虽然嘴上这样说,但我内心却产生了一股不祥的预感。多是惧怕的缘由,小丽也有些脸色发白。
小明忍不住插嘴道,“你说大家俩,说这些没用的干吗呢?咱们又控制不了。这不是本身吓本身吗?”
“是啊是啊。”我随声附和,“反正这一趟路途遥远,咱们有的是时间,那咱们继续以前讲故事的游戏好了。第二个谁讲呢?”
“我讲我讲!”小明抢着说,“我此次要讲一个真正的跟程序员有关的故事。主人公但是个顶级的技术高手!”
我要讲的这个故事啊,可跟个人亲身经历有关。故事的主人公,是一名身怀绝技的网络黑客。他的黑客技术登峰造极,只要动动手指就能让几千个节点的网络瘫痪!他的程序可以穿透各类防火墙,到达别人根本没法到达的地方。
小明神秘的语气吸引了咱们。我和小丽聚精会神地听着。
黑客就像网络世界的一个侠盗,他游历世界,劫富济贫,专门收拾那些为富不仁的有钱人。
有一天,黑客在海边度假的时候,碰到了一个女孩。他深深地爱上了她。
哦,对了,我开头忘了介绍,咱们的这位黑客主人公虽然技术高超,但表达能力欠缺,并且有严重的社交恐惧症。他好几年都独来独往,从不与外人接触,整日都泡在网络上。他大概没有勇气向女孩当面表达他的爱意。因此,他开始用本身的方式去接触她。
他入侵了女孩的家庭网络,潜伏在她的我的电脑里面,注视着她的一举一动。令他灰心丧气的是,女孩的生活中原来有另一个男人,那多是她的男友或者丈夫。黑客感受到自尊心受到了伤害,他顺藤摸瓜,很快黑进了那个男人所在公司的网络。
随后的发现令他大吃一惊。那是一个作互联网金融业务的公司,那个男人是公司的老板。黑客发现公司的帐目存在严重的问题,公司非法集资,帐目混乱,仿佛在故意掩盖着一个阴谋。他想亲口去告诉那个女孩,但好几回他又退却了。女孩怎么可能会相信他呢?
如今,对于咱们的黑客来讲,这已经不是一个私人恩怨的问题了,这涉及到不少人的财产安全。这是一个社会正义的问题!因而,黑客利用那家公司服务器的一个「SQL注入」的漏洞,让公司服务器集体瘫痪,再也没法启动,同时又将隐藏的公司帐目提取了出来,并公开发布在了网上。
“知道吗?我,就是这名黑客的工具程序中携带的某个字节。我还亲自参与了那次的入侵行动!”
对于他的身世来历,小明提及来一脸的自豪。
“那最后黑客跟那个女孩在一块儿了吗?”小丽问。
“可能在一块儿了吧。不过这根本不重要!”此次轮到小明不耐烦了。
如今,咱们已经通过了许多中途的路由器节点。在每个节点上,路由程序都会根据20个字节的IP头中的目的地址去查阅路由表,决定下一跳把咱们发送到哪里。眼看着离目的地愈来愈接近了。
这时,咱们来到了一个新的路由节点。路由程序告诉咱们一个很差的消息,前面的路线要通过一个以太局域网,这个局域网的MTU (Maximum Transmission Unit,最大传输单元) 是1500字节。因此,咱们这2000个字节要被分红两部分分别发送。路由程序解释说,在IP协议里,这叫分片(Fragmentation),并详细解释了分片的过程。
具体的分片过程稍微有点复杂。首先,分片是IP层的策略,所以它不识别TCP层的封装。也就是说,20个字节的TCP头加上原来2000个字节的数据,这总共2020个字节,在IP层协议执行分片的时候都当作数据。前面的1480个字节分到第一个数据片,他们这一队前面加上20个字节的IP头,成为1500个字节的新IP包,刚好能够经过MTU的限制。而从第1481个字节开始,后面的540个字节,将分到第二个数据片。这个数据片一样在前面加上20个字节的IP头,成为一个560字节长度的IP包。
我忽然意识到,第1481个字节位置,因为里面多算了20个字节的TCP头,因此在原来的数据中其实是第1461个字节。而我不就正好排在第1461个字节位置吗?这就是说,我将被分到第二个数据片,而小明和小丽在第一个数据片!
真是糟糕透了。
当我把这个分片的结果告诉他们的时候,我确信我看到了小丽眼中现出担心的神色。
“那咱们还会再见面吗?”小丽问。
“固然会了。两个数据片分头到达目的主机以后,还会在协议栈里重组(Reassembly)的。”我故做轻松地解释,但心中不安的感受却愈来愈强。
“真惋惜!咱们还没听到你讲的故事呢。”小明开玩笑地说。
“等重组以后,我立刻讲给大家。”
我刚说完,分片操做就已经完成。载着小明和小丽的数据片「嗖」地一声被发射出去。而我仍站在原来的buffer中,向他们挥手告别。
我在第二个数据片中,紧跟在20个字节的IP头后面,排在数据的第1个位置。一路上,我陷入了沉思。
咱们又通过了几个路由节点,慢慢地靠近了目的主机。
“停!”忽然有人大喊一声。原来是目的主机上的防火墙程序,他要求咱们停下来接受检查。
“不对啊,大家这个数据包的目的端口没有在白名单内!”最后,防火墙程序下告终论。
“什么!”几乎数据片内的全部字节都喊了起来。
防火墙程序无奈地摊开双手,“真是抱歉。但规则就是规则。大家只能被丢弃掉!”
我所在的数据片内一片骚乱。
“等一下!”排在第1个数据位置的我大喊一声。此刻我忽然冷静了下来,看来面前是个工做在四层的防火墙程序。我彷佛明白怎么回事了,“请听我说!并非目的端口不对,而是根本没有目的端口。咱们是IP分片以后的第二个数据片,只有IP头,没有TCP头。你要看的目的端口号应该在TCP头内部,但咱们这里根本没有。”
防火墙程序狐疑地看了我一眼,“那你说怎么办?”
“若是我没猜错的话,咱们的第一个数据片在以前已经经过了你这里。你能够去查查记录,看有没有一个已经经过的数据包,具备跟咱们彻底相同的一个Identification字段(注:是IP头用于分片和重组的一个字段)。若是有的话,咱们就应该也能经过。”
“好,大家等着,我去查一下。”
时间仿佛过了一个世纪之久。看来这个防火墙在处理分片状况下的过滤算法效率并不高。
我心中那种不安的感受彷佛又逐渐升腾起来。没错,若是幸运的话,小明和小丽他们应该已经经过了这里,但若是咱们倒是先他们一步到达的话......后果然是不堪设想!
还好,防火墙程序最后终于从新返回,对咱们点了点头,“大家能够经过了。”
咱们在目的主机的IP层成功完成了重组 (Reassembly),从新变成了2020个字节的队伍(包括20字节的TCP头)。
我又从新和小丽、小明他们挨在了一块儿。一切仿佛一如从前,但又变得有点不一样。
小丽和小明如今手拉着手,亲密地偎依在一块儿。他们见到我,微笑着同我打招呼:“你怎么这么慢啊!终于又见到你了!”
我胸中涌起了一股相似嫉妒的情绪。
忽然间,我彻底明白了,从头到尾。
“我如今就给大家讲第三个故事。”我顿了一顿,“很凑巧,故事的男主人公也叫苏秦,而女主人公也叫古灵儿。”
他们吃惊地瞪大了眼睛。
苏秦是计算机系毕业的,毕业后作了程序员的工做。可是,他知道本身并不擅长作这份工做,因此一直没有信心。
他和古灵儿在毕业以前就开始恋爱了,那是一份纯粹的爱情。然而,毕业以后他慢慢地发现,随着生活而来的物质压力却愈来愈大,让他喘不过气来。他当心翼翼地维系着这份感情,但终于她仍是离他而去了。
苏秦今后暗下决心,他发誓必定要把失去的再从新找回来。他今后奋发图强,真能够说是「头悬梁,锥刺股」了。他用了差很少两年的时间,阅读了大量的技术书籍,在工做中也不遗余力,终于成长成了一名真正的技术高手。升职,加薪,一切彷佛都唾手可及。可是,这时候古灵儿早已步入了别人的婚姻殿堂。原来一切都已不可挽回。
苏秦白天上班,晚上则摇身一变,成为一名网络黑客。他对古灵儿仍然没有死心。他入侵了她的家庭网络,又入侵了她老公的公司网络。她老公确实是个有钱人,但却在用人上目光短浅。多是为了压低成本,他们公司几乎只招一些工资低的程序员,结果作出来的产品漏洞百出。苏秦根据这些漏洞泄露出来的数据,发现了公司的帐目问题。
他也说不清本身到底是出于何种动机,也没仔细想过这样作的后果,总之他出手了。他选了一个好日子,对古灵儿他老公的公司网络发动了致命的一击。
结果公司倒闭了,老板作贼心虚,居然本身跑路了。那个男人果真是个靠不住的人。苏秦没想到这件事给古灵儿带来了无尽的麻烦,但她把社交软件都删掉了,并且搬了住处,他一时竟也找不到她。
直到有一天,他接到了古灵儿的来电。
“因此说,大家俩讲的,其实只是一个故事的两个部分!”我大声地向小丽和小明宣布道。
这时,协议栈的内核程序刚刚剥掉了TCP头,咱们又从新变成了2000个字节的数据。紧接着,一个中断产生,咱们被从内核态抛到了应用层,等待应用层程序的进一步处理。
他们两个吃惊地说不出话来。看到他们的样子,我心里竟浮起一丝复仇的快感。我脸一红,赶忙压制住了这种情绪。
“你——说的都是真的?”小明惊得说话都有些结巴了。
我慢条斯理的开始分析,“知道为何咱们三个会碰到一块儿吗?这并非凑巧。由于咱们三个都和苏秦有关!”
“那你呢?你和苏秦又是什么关系呢?”
“我属于苏秦调试程序的时候使用的一份测试数据。”我指了指由全部这2000个字节组成的字节队列,补充道,“准确地说,咱们都属于这份测试数据。他应该正在测试大数据包的状况下究竟会发生什么。”
此时,应用层的程序发现了咱们的到达,正准备调用protobuf的反解子例程执行反序列化操做。
“什么?你是说咱们几个之因此在这儿,只是在进行一次调试?”小明和小丽表示都不太相信。
“没错。并且咱们立刻就会知道结果了。”我观察了下周围的执行环境,更加确信了我推测的正确。
他们俩面面相觑。
没错!就是如今了!我大声地冲他们喊道:“知道着这意味着什么吗?”
“什么?”
“这意味着正在调试的程序还不太稳定!”
一瞬间,进程抛出的异常有如原子弹爆炸。刺眼的白光照亮了支离破碎的整个内存空间。全部的东西在一点点消失,操做系统开始回收异常发生后的现场。
“到底发生了什么?”就在咱们你们被完全地从内存中抹掉以前,小明竭嘶底里地大喊。
“这个接收程序忘了进行「粘包」处理!”我想起了咱们出发时由3400个字节组成的完整消息,直到如今,后面仍有1400个字节没有到达。
在一片白光之中,世界从新归于一片寂静。
咱们虽然已再也不存在于这片内存之中,但程序的日志早已把这发生的一切都记录了下来。此刻,日志文件正静静地躺在世界的某个角落,等待着喜欢听故事的你来随时查阅。
(完)
最后的彩蛋
应该不少同窗已经猜到了,故事中这三个字节的取值并非随意选的。它们要表达的意思你看出来了吗?
另外,对作技术开发工做的同窗来讲,文中出现的技术描述细节中,最有实用价值的实际上是应用层的「粘包」处理问题。文中解释了它出现的缘由,你看懂了吗?
其它精选文章: