平凡的世界(三) 第21章
????
当秋日金色的阳光从田家圪崂那边漫过公路,漫过东拉河,斑斑驳驳照亮金家湾的那阵儿,就到了庄稼人吃早饭的时辰。在此之前,人们已经在山里干了好长时间活,肚子饿得贴到了后脊梁上。现在,他们迈开懒洋洋的步子,走回了自己的院落。
早熟的秋田作物已经开始收割。禾场上,硷畔上,院子里,到处都堆起了干枯的豆蔓,金黄的玉米棒。地里的南瓜卸光了,用不了几天,就得动镰割縻子。红薯和土豆胀破了地皮。远山浮现出大块的斑黄。
在庙坪三角洲那里,黄绿相间的树叶间垂挂着红艳艳的枣子。早晨的阳光渐渐抹去灰淡的薄雾,草叶上滚动着白花花的露水珠。放学的孩子们唱着歌在哭咽河的小桥乱了队形,纷纷四散开奔回了家。炊烟从各家窑顶袅袅升起,象蓝色的绸带在晨光中飘曳……金俊武把一捆豆蔓扔在院子里,象往常那样坐到院子外的小石凳上,带着一丝满足的神色点起了一锅旱烟。不多时分,他老婆李玉玲就麻利的把饭菜端到他面前的小石桌上。夫妻俩面对面坐下吃起来。他们的两个孩子,一个在原西上高中,一个在石圪节上初中,除过星期天,家里就他们两个人。金俊武四十八岁,额头和眼角有了很深的皱纹。不过,那对铜铃大眼依然光气逼人。
看得出来,他还是双水村的一条汉子。
这几年,俊武没去闹腾生意,一心都扑在了土地上,按他的精明,本来是块做买卖的材料。但金俊武有金俊武的想法。做买卖要资本,那就得去贷款。再说一个土包子农民,很难摸来行情(如今叫什么“信息”)。一旦赔了,就没个抓挖处。前不久孙少安砖场的倒塌就是明证。
在金俊武看来,土地上做文章最保险。就是有个天灾,赔进去的也只是自己的力气。当然,他现在不会再按老古板种地,他一直和石圪节农技站“挂钩”,照科学方法拨弄庄稼。因此同样大小的地块,他总能比别人多收近一倍的粮食。
金俊武眼下的光景,并不比村里其他能人们差。粮食大宗卖过之后,仍然是村中存粮最多的家户。现在,除过一孔住宿的窑洞,其它两孔窑全部塞满了粮食。就这样还盛不下,他不得不又在院子里搭起一个专门存放玉米的棚子。
金俊武和他老婆李玉玲一边吃饭,一边合计着准备雇用几个人帮助他们收秋。今年雨水充足,秋庄稼格外厚实,光他们两个无力收割完这么多的庄稼。他们种地也种的太贪心了!瞧,连硷畔边的一点零散地都种了荞麦。现在,这荞麦正在开花,他们饭桌周围象落了一层白粉粉的雪,勤劳的俊武从哭咽河沟道把家搬到这里的那年,就在院子内外栽了不少果树。桃三杏四,枣圪蹴五。如今,那些枣树的枝头开始缀上了红艳艳的大枣。他的玉玲和他一样精明而能干,四十几岁的人,看起来就象三十出头的小媳妇那般俊俏,走起路来刮风似的轻快。无论是光景还是年龄,金俊武夫妇都处于他们的辉煌年代。
两口子正边吃饭边商量收秋的事,他们的邻居金光亮手里端个茶缸子,一路巴咂着嘴喝蜂蜜水,笑嘻嘻地走过来,坐在旁边的小石凳上。
金俊武夫妇赶忙敬让着叫前地主的大儿子吃饭。
但金光亮笑着摇摇头,说他吃过了。他抿了一口自己的蜂蜜水,香得张开嘴“哈”地一声,眯住眼陶醉地说:“好东西啊!再好的饭也比不上这蜂糖。怪不得丸药都用蜂糖做哩,十全大补嘛!过去咱们谁知道外国还有蜂?我这蜂是意大利的!听说光明是走后门才给我买了两箱……”每过几天,金光亮就情不自禁要到这个饭桌前来能一能他的“意大利”蜂。就目前而言,金光亮也许是全双水村最为得意的公民。地主成份的愁帽刚摘不久,二小子就当了中国人民解放军。紧接着,门外工作的大弟弟又给他捎回来两箱子“意大利”蜂。除过冬大,他一年三季动不动就到石圪节或米家镇卖蜂蜜。票子虽不是大把抓,也足让双水村大部分人家眼热。今年以来,他也不再出山劳动,整天和他的蜂为伍。山里的庄稼有他的大锤和三锤耕种。这人轻闲得三天两天就赶集上会,又喝的是蜂蜜水,光景日月绿格铮铮,他不能叫谁能哩?
金光亮这样得意洋洋地说话的时候,他的“意大利”蜂就在旁边金俊武家的养麦花上嗡嗡嘤嘤地采蜜。并且不时吟唱着从三个人之间穿过,象是进行飞行表演。
精人金俊武只好对浅薄的金光亮微笑着点头,表示对他和他的“意大利”蜂心怀敬意。但他老婆李玉玲却气得把脸迈向一边,给金光亮个后脑勺。
在李玉玲的想象中,金光亮的这些“毛老子”在她家的果树和荞麦花上采蜜,很可能把里面最好的养料都采光了,因此对这蜂充满了仇恨。而更使她气愤的是,老东西金光亮还常跑来能他的这群毛老子哩!
李玉玲曾几次给丈夫建议,在自家的果树上喷些“六六六”,把这该死的“意大利”蜂都毒死,让老地主的儿子再能!但金俊武坚决地阻挡了她这危险想法。俊武虽然个性强,可他从来不做这种短事。采就采去吧,能就能去吧,这金光亮几十年抬不起头,快六十岁的人了,也让他张狂上几天……金光亮这时又抿一口蜂蜜水,正准备继续夸耀他的意大利蜂,却突然象蜂在屁股上蛰了一下,一闪身站起来,慌乱地说:“看我这忘性!我得要挪一下蜂箱子哩!”他话音未落,便端着茶缸子急忙回家去了。
????
俊武和玉玲扭头一看,见光辉的媳妇马来花提着个大竹篮子,从坡底下走上来。
这夫妻俩忍不住笑起来。
马来花和她大哥金光亮是一对冤家,尽管她丈夫和光亮是亲兄弟,但来花一直和大哥不和,尤其是二哥金光明给大哥家捎回两箱子“外国蜂”后,来花不仅更敌视金光亮,连光明当教师的媳妇姚淑芳也不搭理了。她认为,有工作的老二两口子在偏爱老大一家而歧视他们。为此,急得姚淑芳给铜城的丈夫写了好几封信,数落他不该光给大哥家买那两箱该死的蜂——这蜂已经把弟兄三家的关系搅得一烂包!马来花是双水村有名的泼辣女人。她在金家湾这面说话,河对面田家圪崂的人也能听见。别人都是男人做生意,来花却让丈夫光辉安份守己劳动,她自己在村子公路边上卖起了茶饭,一天下来,收入也相当不错,村里的女人指教丈夫的时候,常常说:“你还算个男人?你连人家马来花的脚后跟都拾不上!”而男人们却又顶嘴说:“我有个马来花当老婆,也就能过好光景!”
马来花最出名的还是她那张嘴。嘻笑怒骂,威震全村。特别是金光亮,只要一听见她的声音,就象听见老虎的声音,常常吓得落荒而逃。马来花却专意把那些最难听的话往她大哥耳朵里送。
唉,狗不和鸡斗,男不和女斗,再说,又是自己的弟媳妇,金光亮挨了骂也只能装个没听见……这阵儿,来花上了硷畔,凑到俊武家的饭桌前,大声嚷嚷着说:“又给你们能他那群毛老子来了?什么时候,蜂糖总把他噎得不出气呀!”
俊武夫妻不吭声,只是个笑。
马来花坐在这饭桌前,扯开大嗓门指桑骂槐乱吼了一通,直到她丈夫金光辉来才把她硬拉回了家。光辉也管不住自己的女人和她那张不饶人的辣子嘴,只能常常在大哥和老婆之间扮演一个尴尬角色。
具有戏剧性的是,当年被田福堂用革命行动从哭咽河赶到这里的两大户人家,而今的关系呈现出一种新的组合。俊武夫妻和大哥俊文一家人不和睦,而和隔墙的金光辉一家倒很亲密。相反,金光亮一家和金俊文一家却相处融洽。那边老二家光明在门外工作,媳妇姚淑芳本人是公派教师,不参与两个农民弟兄的矛盾,这边老三家的俊斌早已亡故,改嫁的王彩娥走了石圪节,虽然有个院落,但已经“黑门”;院子里蒿草一人高,门上的铁锁都生锈了。
生活使弟兄妯娌们发生龃龆,却分别和外人结成了友好联盟。
这四家的光景都很殷实,但发达的途径却各有不同。当然,富中之富,首推金俊文一家;我们已经知道,他们是靠金富的“三只手”发了大财……吃完饭,李玉玲把碗筷一收拾,就转回家去了。俊武点着一锅旱烟,有滋有味地抽着。这时候,他看见金俊山吆着他那头黑白大花奶牛从硷畔下面的小路上走过来。双水村的这位*自从新添了这头奶牛,似乎又年轻了好几岁,他现在既养奶羊又养奶牛,牛羊奶增加了大笔收入,同时也把自己喝的红光满面。
金俊山让他的宝贝奶牛独个儿回家去,自己径直从俊武家的土坡小路转上来。金俊武看出,俊山是找他来拉话的。他同时发现,俊山哥竟然用大红布给他的奶牛做了两个乳罩,便忍不住笑了,这金俊山真有意思!他把奶牛打扮成了个婆姨!
金俊山在小石凳上坐下后,俊武喊叫让玉玲端出一杯茶来。金俊山不抽烟,但有茶瘾。
俊山喝了一口茶水,对俊武说:“我前几天就想找你……”
“什么事?”俊武问。
“唉,你又不是不知道。咱们学校的窑洞,那年炸山打坝后,就震坏了。如今,缝子越裂越大,娃娃们怕都怕得不敢进教室。听我金成说,他头天给裂缝上贴根纸条,第二天就又裂开了。看来,这窑洞十分危险,不敢再让娃娃们在里面上课。我给福堂说过几次,他说他不管……”
金俊山的话又自然勾起了金俊武对往事的回忆。
????
他一想起当年田福堂逼他们搬家的情景,就压抑不住满腔愤怒。他骂道:“田福堂龟子孙为了扬名,造下的孽太深了。你不要管!这是他屙下的,叫他自己去拾掇!”“唉,那人如今身体也垮了。再说,咱们总不能眼看着让村里的娃娃压死在窑洞里;出了事,可就不得了呀!”金俊山抱着现实主义态度说。
在我们的印象中,从过去到现在,金俊山在双水村似乎永远扮演一个收拾残局的角色。
“那你找我有什么办法?”金俊武的脸色仍然不好看。“我想找你商量一下,把二队原来那两孔公窑腾出来,先让娃娃们搬进去凑合着上课。”金俊山说。
“里面那些乱七八糟的公物往哪里搁?”
“搁在原来的饲养室。”
看来这事金俊山早已谋划好了。俊武想了想,觉得俊山哥是好意。要不,学校窑真的塌了,出个人命事,也的确不是玩的。他于是就同意了金俊山的建议。
一两天后,在村民委员会主任金俊山的主持下,双水村小学从岌岌可危的原址搬到了金家湾二队的公窑里。这次学校的搬迁实际上是对田福堂和孙玉亭的一次公民声讨。世事再不同往年,如今人们破口大骂这两个“革命家”造下的罪孽。那时叱咤风云的福堂是打着为全村人谋福的旗号在哭咽河上炸山打坝的。现在,那个早已豁口的废坝和这个搬空的破学校,为田福堂的历史留下两座耻辱的纪念碑。金俊山和金俊武利用搬迁学校这一机会,巧妙地提高了他们在村民中的威望。不用说,田福堂在双水村的权势又下跌了一截。正当某些户族观念甚强的金姓人家借机抱着恶意的态度,嘲笑败落的田福堂和孙玉亭的时候,金家户族里却暴发了最不光彩的丑事——金富和他父母亲一齐被县*局拘留了!
????
这是一个天刚麻麻亮的早晨,一辆警车突然停在村子的公路边上。车里跳下来一些身穿法衣、腰里别着手枪的人,他们迅速过了东拉河的列石,一直向金俊文家院子走去。
村中倒尿盆的女人们首先看到了这情景。消息立刻传到了家家户户。人们拖拉着鞋,一边穿衣服,一边往村中跑。当大伙跑到公路上的警车旁时,就见*人员已经把金富和他爸他妈从家里拉出来了。一家三口人头垂到胸前,手上都戴着明晃晃的手铐。他们被押过东拉河,来到公路上的警车旁。警察把围观的村民豁开,将三个犯人塞进了警车。警车一声长嚎,车顶上旋转起红灯,便刮风一般扬着黄尘朝县城方向开走了……
警车一走,村民们才如梦初醒,纷纷议论起来,虽然抓的是别人,但这阵势把大伙都吓得脸色煞白。双水村大人娃娃几乎全聚集在了公路上。
人们在这个时候,才开始直言不讳地谈起了他们村的这窝窃贼。在此之前的几年里,金俊文一家为了堵村里人的口,不时分别给众人一点小恩小惠,使得大家只能在背后议论他们,而不好意思在公众场所扬他们的贼名。
有人立刻告诉公路上议论成一窝蜂的村民,现在,金俊文家除过二小子金强住的一孔窑洞。其它两孔窑里,还留几个民警在抄点他们的赃物哩!听说光票子就抄出来四五万块!啊啊,偷下那么多?
人们马上前呼后拥淌过东拉河,向金俊文家院子赶去,不多时分,那院里院外就挤下黑鸦鸦一大片人。
*人员正把金俊文家里的布匹、衣服和其它东西,一件件造册登记,然后分门别类摞在炕上。
人们怀着极大的好奇心,轮流挤到两孔窑的门口,探着脖子观看里面的景致。
所有看罢的人都纷纷议论说,比石圪节供销社的货物都丰富!
这一天,双水村的大部分人都推迟了出山。直等到*人员拿封条把金俊文家的两个窑门封住后,人们才散开了。
当天,金富一家老小三口被捕的消息,就传遍了整个石圪节乡。几年来,这家人的名声早已扬遍周围村社;石圪节乡没有人不知道双水村有个大名鼎鼎的金富!
两天以后,又从原西县城传回更惊人的消息:金富一案共逮捕了十七个人,有的还是从外县捉回来的。据说,这是一个大盗窃团伙,首领就是金富,贼娃子们称他为“老板”。同时,石圪节乡*也贴出告示,说在后天的集市上,县法院要专门把金富一家拉到这里来公开宣判……
上一篇: 随机生成常用汉字(改进版)
下一篇: 秋寒
推荐阅读
-
腾讯首位产品经理韩宇宙:云鱼--虚拟与现实嫁接的第三世界
-
读完世界三大奇观,你就看到了地球的真相
-
2018-08-28《平凡的世界》第三部分第21章至第24章
-
平凡的世界(三) 第21章
-
epoll简介及触发模式(accept、read、send)-epoll的简单介绍 epoll在LT和ET模式下的读写方式 一、epoll的接口非常简单,一共就三个函数:1. int epoll_create(int size);创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close关闭,否则可能导致fd被耗尽。2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);epoll的事件注册函数,它不同与select是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create的返回值,第二个参数表示动作,用三个宏来表示:EPOLL_CTL_ADD:注册新的fd到epfd中;EPOLL_CTL_MOD:修改已经注册的fd的监听事件;EPOLL_CTL_DEL:从epfd中删除一个fd;第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */};events可以是以下几个宏的集合:EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭); EPOLLIN事件:EPOLLIN事件则只有当对端有数据写入时才会触发,所以触发一次后需要不断读取所有数据直到读完EAGAIN为止。否则剩下的数据只有在下次对端有写入时才能一起取出来了。现在明白为什么说epoll必须要求异步socket了吧?如果同步socket,而且要求读完所有数据,那么最终就会在堵死在阻塞里。 EPOLLOUT:表示对应的文件描述符可以写; EPOLLOUT事件:EPOLLOUT事件只有在连接时触发一次,表示可写,其他时候想要触发,那要先准备好下面条件:1.某次write,写满了发送缓冲区,返回错误码为EAGAIN。2.对端读取了一些数据,又重新可写了,此时会触发EPOLLOUT。简单地说:EPOLLOUT事件只有在不可写到可写的转变时刻,才会触发一次,所以叫边缘触发,这叫法没错的!其实,如果真的想强制触发一次,也是有办法的,直接调用epoll_ctl重新设置一下event就可以了,event跟原来的设置一模一样都行(但必须包含EPOLLOUT),关键是重新设置,就会马上触发一次EPOLLOUT事件。1. 缓冲区由满变空.2.同时注册EPOLLIN | EPOLLOUT事件,也会触发一次EPOLLOUT事件这个两个也会触发EPOLLOUT事件 EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);EPOLLERR:表示对应的文件描述符发生错误;EPOLLHUP:表示对应的文件描述符被挂断;EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);等待事件的产生,类似于select调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。-------------------------------------------------------------------------------------------- 从man手册中,得到ET和LT的具体描述如下EPOLL事件有两种模型:Edge Triggered (ET)Level Triggered (LT)假如有这样一个例子:1. 我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符2. 这个时候从管道的另一端被写入了2KB的数据3. 调用epoll_wait(2),并且它会返回RFD,说明它已经准备好读取操作4. 然后我们读取了1KB的数据5. 调用epoll_wait(2)......Edge Triggered 工作模式:如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用 epoll_wait(2)完成后,是否挂起是不确定的。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。 i 基于非阻塞文件句柄 ii 只有当read(2)或者write(2)返回EAGAIN时才需要挂起,等待。但这并不是说每次read时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。Level Triggered 工作模式相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。调用者可以设定EPOLLONESHOT标志,在 epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。因此当EPOLLONESHOT设定后,使用带有 EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。然后详细解释ET, LT:LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认(这句话不理解)。在许多测试中我们会看到如果没有大量的idle -connection或者dead-connection,epoll的效率并不会比select/poll高很多,但是当我们遇到大量的idle- connection(例如WAN环境中存在大量的慢速连接),就会发现epoll的效率大大高于select/poll。(未测试)另外,当使用epoll的ET模型来工作时,当产生了一个EPOLLIN事件后,读数据的时候需要考虑的是当recv返回的大小如果等于请求的大小,那么很有可能是缓冲区还有数据未读完,也意味着该次事件还没有处理完,所以还需要再次读取: 这里只是说明思路(参考《UNIX网络编程》) while(rs) {buflen = recv(activeevents[i].data.fd, buf, sizeof(buf), 0);if(buflen < 0){// 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读// 在这里就当作是该次事件已处理处.if(errno == EAGAIN)break; else return; }else if(buflen == 0) { // 这里表示对端的socket已正常关闭. } if(buflen == sizeof(buf) rs = 1; // 需要再次读取 else rs = 0; } 还有,假如发送端流量大于接收端的流量(意思是epoll所在的程序读比转发的socket要快),由于是非阻塞的socket,那么send函数虽然返回,但实际缓冲区的数据并未真正发给接收端,这样不断的读和发,当缓冲区满后会产生EAGAIN错误(参考man send),同时,不理会这次请求发送的数据.所以,需要封装socket_send的函数用来处理这种情况,该函数会尽量将数据写完再返回,返回-1表示出错。在socket_send内部,当写缓冲已满(send返回-1,且errno为EAGAIN),那么会等待后再重试.这种方式并不很完美,在理论上可能会长时间的阻塞在socket_send内部,但暂没有更好的办法. ssize_t socket_send(int sockfd, const char* buffer, size_t buflen) { ssize_t tmp; size_t total = buflen; const char *p = buffer; while(1) { tmp = send(sockfd, p, total, 0); if(tmp < 0) { // 当send收到信号时,可以继续写,但这里返回-1. if(errno == EINTR) return -1; // 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满, // 在这里做延时后再重试. if(errno == EAGAIN) { usleep(1000); continue; } return -1; } if((size_t)tmp == total) return buflen; total -= tmp; p += tmp; } return tmp; } 二、epoll在LT和ET模式下的读写方式 在一个非阻塞的socket上调用read/write函数, 返回EAGAIN或者EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 从字面上看, 意思是: * EAGAIN: 再试一次 * EWOULDBLOCK: 如果这是一个阻塞socket, 操作将被block * perror输出: Resource temporarily unavailable 总结: 这个错误表示资源暂时不够, 可能read时, 读缓冲区没有数据, 或者, write时,写缓冲区满了 。 遇到这种情况, 如果是阻塞socket, read/write就要阻塞掉。 而如果是非阻塞socket, read/write立即返回-1, 同 时errno设置为EAGAIN. 所以, 对于阻塞socket, read/write返回-1代表网络出错了. 但对于非阻塞socket, read/write返回-1不一定网络真的出错了. 可能是Resource temporarily unavailable. 这时你应该再试, 直到Resource available. 综上, 对于non-blocking的socket, 正确的读写操作为: 读: 忽略掉errno = EAGAIN的错误, 下次继续读 写: 忽略掉errno = EAGAIN的错误, 下次继续写 对于select和epoll的LT模式, 这种读写方式是没有问题的. 但对于epoll的ET模式, 这种方式还有漏洞. epoll的两种模式 LT 和 ET
-
信息科学中的 "三个世界 "模型初探
-
三维世界中的阴影--阴影图原理分析
-
第 4 章 小世界网络上的游戏
-
气泡排序(超级详细)--升序",从小到大;另一种是 "降序",从大到小。该主题可抽象为 "按升序对 n 个数字排序 "的一般形式。 排序是一种重要的基本算法。排序的方法有很多种,但在本题中我们将使用冒泡排序法。 冒泡法的基本思想 冒泡法的基本思想是,每次比较相邻的两个数字时,较小的那个会被移到前面。如果有 5 个数字9,8,5,2,0,第一次将前两个数字 8 和 9 互换。第二次将第二个和第三个数字(9 和 5)对调......这样一共对调 4 次,得到 8-5-2-0-9 的顺序,可以看到:最大的数字 9 一直在 "下沉",成为最下面的一个数字,而小的数字 "上升" 最小的数字 "上升"。最小的数字 0 已经向上 "浮 "了一个位置。经过第一次比较(共 4 次比较和交换),得到了最大的数字 9。 然后进行第二趟比较,对剩下的前 4 个数字(8、5、2、0)进行新一轮比较,这样第二个最大的数字就 "沉到了底部"。同样,按照上述方法进行第二轮比较。经过 3 次比较和交换,我们得到了第二大数 8。 按照这个规律,我们可以推断出,比较 5 个数字需要 4 次旅行,才能将 5 个数字从小到大排列起来。在第一次旅行中,两个数字之间进行了 4 次比较,在第二次旅行中,进行了 3 次比较......在第四次旅行中,只进行了一次比较。 思路总结 总结:如果有 n 个数字,那么要进行 n-1 次比较。在第一次行程中进行 n-1 次比较,在第 i 次行程中进行 n-i 次比较。
-
财务*的三个世界和 PDCA