2011年12月24日

          原文鏈接
          Brad Feld的一篇文章
          The Rise of Developeronomics中提到了“10倍效率的開發(fā)者(10x developer)”的概念(偉大的開發(fā)者的效率往往比一般的開發(fā)者高很多,而不只是一點(diǎn)點(diǎn)),Adam Loving在讀了之后受到啟發(fā),并向多位大牛(Ben Sharpe、Collin Watson和Jonathan Locke)詢問如何成為“10倍效率的開發(fā)者”,最后得到了以下的答案。 

          1. 只做需要做的工作 

          • 使用敏捷方法;
          • 全心全意做UX設(shè)計;
          • 溝通第一;
          • 編碼也許不是解決問題的辦法;
          • 過早的優(yōu)化是一切罪惡的根源;
          • 選擇最簡單的解決方案。
          2. 站在巨人的肩膀上 


          • 使用開源框架;
          • 使用簡潔語言(如HAML、Jade、Coffeescript);
          • 不要做重復(fù)的事情(不要重新發(fā)明輪子);
          • 利用包管理器來進(jìn)行公共和私有代碼分配;
          • 不要任憑巨頭(如微軟)的擺布而修復(fù)庫中的一個Bug;
          • 不要讓你的雇主逼你學(xué)習(xí);
          • 自主學(xué)習(xí)并為自己設(shè)定新的目標(biāo)。
          3. 了解數(shù)據(jù)結(jié)構(gòu)和算法 

          如果你不知道什么時候應(yīng)該使用快速排序、不懂辨認(rèn)O(n2)程序、不會寫遞歸函數(shù),你將無法成為10倍效率的開發(fā)者。使用多種語言你才能清楚不同的框架是如何解決相同問題的。盡可能去了解底層命令(plumbing),以便能夠作出明智的決定(Web框架是怎么存儲session狀態(tài)的?Cookie到底是什么?)。 

          4. 不要怕買工具,它可以節(jié)省你的時間 

          Ben說:“昨天我花50美元買了一個位圖字體工具,它幫我節(jié)省的時間成本絕對超過200元。” 

          5. 集中注意力 

          不要整天開著你的電子郵件、Twitter、Facebook等,在工作時將它們最小化或關(guān)掉它們,戴上耳機(jī)。Tiny hack說:“即使不聽音樂我也戴著耳機(jī)工作,這樣便不會有人打擾到我。” 

          6. 盡早并且經(jīng)常性地進(jìn)行代碼重構(gòu) 

          有時,你不得不放棄漂亮的代碼轉(zhuǎn)而去尋找真正對項目有用的代碼,但沒關(guān)系,如果你的現(xiàn)有項目中有這樣的代碼,最好的方式便是不要看它,并重構(gòu)。 

          7. 只管去做 

          將你的業(yè)余項目分享到Startup Weekend中。在我開始轉(zhuǎn)到Unix和Ruby on Rails上之前,我買了一臺Mac,使用Windows虛擬機(jī)花了一年時間做.NET項目。 

          8. 挑選一個編輯器,并掌握它 

          高效開發(fā)者喜歡用文本編輯器勝過IDE編輯器,因?yàn)檫@樣可以學(xué)到更多東西。無論什么情況,盡量使用鍵盤快捷鍵,因?yàn)槭炀毷褂靡患ぞ叩那疤崾鞘煜に?nbsp;

          在選擇編輯器時,認(rèn)真考慮并挑選最好的(Emacs或Vim),因?yàn)樗鼈兪峭ㄓ玫摹F浯危暨x你的首選平臺最支持的。使用宏,不斷地寫代碼;使用Mac上的TextExpander為整個段落創(chuàng)建快捷方式;使用Visual Studio或SublimeText的自動補(bǔ)齊功能;使用支持按行/列分割窗口的編輯器,這樣你便能同時看到單元測試和代碼(或模型、視圖)。 

          一定要想清楚后再寫代碼。Adam說,“我有朋友在一個大項目組里工作,他們組里最高效的程序員是一個高位截癱用嘴叼著棍子敲代碼的人,他總是在寫代碼之前想得很仔細(xì)且很少出錯。” 

          9. 整潔的代碼勝過巧妙的代碼 

          要想讓其他人能夠讀懂你的代碼,盡量使用最少的代碼來完成任務(wù)。遵循DRY(Don't repeat yourself)的原則,使用明確定義的對象和庫,將任務(wù)分解成小而簡單的代碼段。 

          10. 潛意識是強(qiáng)大的工具 

          離開10分鐘往往就可以解決一個問題。控制編程時間,給自己一個多姿多彩的生活,勞逸結(jié)合能讓你在工作時更高效、更愉悅。當(dāng)然,即便是上了年紀(jì)的程序員也知道,以最少的時間完成最高效的工作是成為10倍效率開發(fā)者的必要條件。 

          作為一個程序員,我覺得在職業(yè)生涯中最好的一件事兒就是從電腦前站起來,去拜訪那些在某一領(lǐng)域有所建樹的人們。 

          11. 推動自身和團(tuán)隊進(jìn)步 

          重視批評,以包容的態(tài)度接受批評并提升自己是非常重要的事情。沒有這個基礎(chǔ),你不可能成為一個高效的開發(fā)者。一位智者曾經(jīng)說過:“聰明的人善于從自己的錯誤中學(xué)習(xí),而智慧的人善于從別人的錯誤中學(xué)習(xí)。” 

          英文原文:http://adamloving.com/internet-programming/10x-developers

          posted @ 2011-12-24 21:33 alex_zheng 閱讀(287) | 評論 (0)編輯 收藏


          2011年3月30日

          今天有個需求,需要限制圖片中的style屬性,只能是width,height,float屬性,可以通過正則表達(dá)式來解決,只匹配這個三個屬性中的一個或多個
          ^(((width|height)\s*:\s*\d+(px|%)[;]?)|\s|(float:(left|right)[;]?))+$
          這里沒有對重復(fù)定義做處理

          posted @ 2011-03-30 10:22 alex_zheng 閱讀(4426) | 評論 (0)編輯 收藏


          2011年2月22日

          有時候,我們希望用一個字段保存對象的所屬狀態(tài)或分類,當(dāng)這個值存在多種組合的時候,我們就可以使用位運(yùn)算來表示組合后的值。
          先定義類型A=1,B=2,C=4,D=8,E=16等2的倍數(shù),
          那么objectA即屬于A又屬于C,其值為A|C,添加類型使用|(或)運(yùn)算,移除類型使用^(異或)運(yùn)算,判斷是否屬于某個類型使用&運(yùn)算。
          A=00000001
          B=00000010
          C=00000100
          D=00001000
          E=00010000

          objectA = (A|B|C = 00000111)
          去除B類型 00000111
                        ^00000010
          -------------------------
                           00000101=(A|C)

          判斷是否是A,00000101&00000001 = 00000001



          posted @ 2011-02-22 11:07 alex_zheng 閱讀(572) | 評論 (0)編輯 收藏


          2011年1月17日

          轉(zhuǎn)自http://hi.baidu.com/2wiki/blog/item/2cc40a3f2b7ef2c97c1e7127.html
          DTD 類型約束文件
              1. Window->Preferences->XML->XML Catalog->User Specified Entries窗口中,選擇Add 按紐
                 
              2.在Add XML Catalog Entry 對話框中選擇或輸入以下內(nèi)容:
                  Location: F:\soft\programmingSoft\Framework\Ibatis\sql-map-config-2.dtd
                  Key Type: URI
                  KEY: http://ibatis.apache.org/dtd/sql-map-config-2.dtd
                 
          XSD 類型約束文件

              1. Window->Preferences->XML->XML Catalog->User Specified Entries窗口中,選擇Add 按紐
                 
              2.在Add XML Catalog Entry 對話框中選擇或輸入以下內(nèi)容:
                  Location: F:\soft\programmingSoft\Framework\Spring\spring-framework-2.5.6.SEC01-with-dependencies\spring-framework-2.5.6.SEC01\dist\resources\spring-beans-2.5.xsd
                  Key Type: Schema Location
                  KEY: http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

          posted @ 2011-01-17 09:31 alex_zheng 閱讀(1364) | 評論 (0)編輯 收藏


          2010年12月14日

          這里演示的是hibernate3.5.6,anltr版本是2.7.6
          首先將antlr.jar包復(fù)制到hibernate-distribution-3.5.6-Final/project/core/src/main/antlr,這里hibernate-distribution-3.5.6-Final是你的解壓路徑
          然后依次執(zhí)行java -classpath antlr-2.7.6.jar antlr.Tool hql.g等,最后將生成的java文件復(fù)制到相應(yīng)包

          posted @ 2010-12-14 14:23 alex_zheng 閱讀(337) | 評論 (0)編輯 收藏


          2010年12月9日

          先看下netty的channel對象關(guān)聯(lián)關(guān)系。channel是由channelfactory來創(chuàng)建的,channelfactory又分為client和server兩種。
          channelfuture負(fù)責(zé)channel的所處狀態(tài),一個channle中關(guān)聯(lián)來channelpipeline,channelpipeline則由pipelinefactory創(chuàng)建,
          在channelpipeline中有內(nèi)部類channelhandlercontext,保存channelhandler的鏈?zhǔn)浇Y(jié)構(gòu),由channelhandler來傳遞channelevent,
          channelevent分別有open,bind,connected,close,messagereceived等。

          posted @ 2010-12-09 16:46 alex_zheng 閱讀(878) | 評論 (0)編輯 收藏


          2010年12月6日

          在看完了server端的啟動,再來看client端的啟動過程是怎么進(jìn)行的。例子是TelentServer對應(yīng)的TelentClient
          public class TelnetClient {

              
          public static void main(String[] args) throws Exception {
                  
                  ClientBootstrap bootstrap 
          = new ClientBootstrap(
                          
          new NioClientSocketChannelFactory(
                                  Executors.newCachedThreadPool(),
                                  Executors.newCachedThreadPool()));

                  
          // Configure the pipeline factory.
                  bootstrap.setPipelineFactory(new TelnetClientPipelineFactory());

                  
          // Start the connection attempt.
                  ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));

                  
          // Wait until the connection attempt succeeds or fails.
                  Channel channel = future.awaitUninterruptibly().getChannel();
                  
          if (!future.isSuccess()) {
                      future.getCause().printStackTrace();
                      bootstrap.releaseExternalResources();
                      
          return;
                  }

                  
              }
          }
          直接看connect方法
          public ChannelFuture connect(final SocketAddress remoteAddress, final SocketAddress localAddress) {

                  
          if (remoteAddress == null) {
                      
          throw new NullPointerException("remoteAddress");
                  }

                  ChannelPipeline pipeline;
                  
          try {
                      pipeline 
          = getPipelineFactory().getPipeline();
                  } 
          catch (Exception e) {
                      
          throw new ChannelPipelineException("Failed to initialize a pipeline.", e);
                  }

                  
          // Set the options.
                  
          //NioClientSocketChannel構(gòu)造函數(shù)中會觸發(fā)channelopen
                  
          //TelnetClientPipelineFactory中的upstreamhandler沒有重寫channelOpen,這里只是一直往下傳遞該事件
                  Channel ch = getFactory().newChannel(pipeline);
                  ch.getConfig().setOptions(getOptions());

                  
          // Bind.
                  if (localAddress != null) {
                      ch.bind(localAddress);
                  }

                  
          // Connect.
                  return ch.connect(remoteAddress);
              }
          然后執(zhí)行ch.connect(remoteAddress);
          這里是NioClientSocketChannel-->NioSocketChannel-->AbstractChannel
          public ChannelFuture connect(SocketAddress remoteAddress) {
                 
          return Channels.connect(this, remoteAddress);
          }

          public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) {
                  
          if (remoteAddress == null) {
                      
          throw new NullPointerException("remoteAddress");
                  }
                  ChannelFuture future 
          = future(channel, true);
                  channel.getPipeline().sendDownstream(
          new DownstreamChannelStateEvent(
                          channel, future, ChannelState.CONNECTED, remoteAddress));
                  
          return future;
          }

          從TelnetClientPipelineFactory的pipeline中由下往上傳遞CONNECTED事件,這里只有一個StringEncoder-->OneToOneEncoder,其
          handleDownstream方法對該事件不做處理,往上傳遞該事件,執(zhí)行DefaultChannelHandlerContext.sendDownstream
          public void sendDownstream(ChannelEvent e) {
                      
          //在StringEncoder之前再沒有downstreamhandler
                      DefaultChannelHandlerContext prev = getActualDownstreamContext(this.prev);
                      
          if (prev == null) {
                          
          try {
                              getSink().eventSunk(DefaultChannelPipeline.
          this, e);
                          } 
          catch (Throwable t) {
                              notifyHandlerException(e, t);
                          }
                      } 
          else {
                          DefaultChannelPipeline.
          this.sendDownstream(prev, e);
                      }
                  }
          執(zhí)行NioClientSocketPipelineSink.eventSunk,其中會執(zhí)行
           private void connect(
                      
          final NioClientSocketChannel channel, final ChannelFuture cf,
                      SocketAddress remoteAddress) {
                  
          try {
                      
          //如果返回true,調(diào)用nioworker.register,開始啟動nioworker線程處理該channel的讀寫
                      
          //否則,交給boss.register方法,在boss線程中完成連接
                      if (channel.socket.connect(remoteAddress)) {
                          channel.worker.register(channel, cf);
                      } 
          else {
                          
          //為當(dāng)前clientsocketchannel添加closed的listener
                          channel.getCloseFuture().addListener(new ChannelFutureListener() {
                              
          public void operationComplete(ChannelFuture f)
                                      
          throws Exception {
                                  
          if (!cf.isDone()) {
                                      cf.setFailure(
          new ClosedChannelException());
                                  }
                              }
                          });
                          cf.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                          channel.connectFuture 
          = cf;
                          
                          boss.register(channel);
                      }

                  } 
          catch (Throwable t) {
                      cf.setFailure(t);
                      fireExceptionCaught(channel, t);
                      channel.worker.close(channel, succeededFuture(channel));
                  }
              }

          執(zhí)行boss.register,在boss線程中確保該channel連接成功,這里會啟動boss線程
          void register(NioClientSocketChannel channel) {
                      
          //在RegisterTask的run方法里注冊SelectionKey.OP_CONNECT
                      Runnable registerTask = new RegisterTask(this, channel);
                      
                          
          boolean offered = registerTaskQueue.offer(registerTask);
                          
          assert offered;
                      }

                      
          if (wakenUp.compareAndSet(falsetrue)) {
                          selector.wakeup();
                      }
                  }
          最后啟動boss.run,其中processSelectedKeys里執(zhí)行connect
          private void connect(SelectionKey k) {
                      NioClientSocketChannel ch 
          = (NioClientSocketChannel) k.attachment();
                      
          try {
                          
          if (ch.socket.finishConnect()) {
                              k.cancel();
                              
          //連接成功,才在nioworker中啟動一個新線程來處理該socketchannel的讀寫
                              ch.worker.register(ch, ch.connectFuture);
                          }
                      } 
          catch (Throwable t) {
                          ch.connectFuture.setFailure(t);
                          fireExceptionCaught(ch, t);
                          ch.worker.close(ch, succeededFuture(ch));
                      }
                  }

          之后就是交給nioworker線程來進(jìn)行數(shù)據(jù)的發(fā)送和接收了。

          posted @ 2010-12-06 16:59 alex_zheng 閱讀(3272) | 評論 (0)編輯 收藏


          2010年12月5日

               摘要: 上周去一家公司面試,其中一個面試題是這樣的,判斷下面程序輸出,本人很杯具的寫了"changed" Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->public class StringArgTest ...  閱讀全文

          posted @ 2010-12-05 16:27 alex_zheng 閱讀(1159) | 評論 (0)編輯 收藏


          2010年12月4日

          上一篇分析了服務(wù)器端讀取客戶發(fā)送的數(shù)據(jù),這篇來看服務(wù)器端如何發(fā)送數(shù)據(jù)給客戶端,服務(wù)器往外發(fā)送數(shù)據(jù)是通過downstreamhandler從下到上執(zhí)行
          發(fā)送從ChannelFuture future = e.getChannel().write(response)開始執(zhí)行Channels下的
          public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) {
                  ChannelFuture future 
          = future(channel);
                  channel.getPipeline().sendDownstream(
                          
          new DownstreamMessageEvent(channel, future, message, remoteAddress));
                  
          return future;
           }

          telentpipeline中最下面一個downstreamhandler是stringencoder,最后執(zhí)行OneToOneEncoder的handleDownstream
          public void handleDownstream(
                      ChannelHandlerContext ctx, ChannelEvent evt) 
          throws Exception {
                  
          if (!(evt instanceof MessageEvent)) {
                      ctx.sendDownstream(evt);
                      
          return;
                  }

                  MessageEvent e 
          = (MessageEvent) evt;
                  Object originalMessage 
          = e.getMessage();
                  Object encodedMessage 
          = encode(ctx, e.getChannel(), originalMessage);
                  
          if (originalMessage == encodedMessage) {
                      ctx.sendDownstream(evt);
                  } 
          else if (encodedMessage != null) {
                      
          //這里寫encode數(shù)據(jù),DefaultChannelPipeline的sendDownstream
                      write(ctx, e.getFuture(), encodedMessage, e.getRemoteAddress());
                  }
              }
          DefaultChannelPipeline的sendDownstream方法
          public void sendDownstream(ChannelEvent e) {
                      DefaultChannelHandlerContext prev 
          = getActualDownstreamContext(this.prev);
                      
          if (prev == null) {
                          
          try {
                              
          //因?yàn)閟tringencoder是唯一一個downstreamhandler,這里執(zhí)行NioServerSocketPipelineSink.eventSunk
                              getSink().eventSunk(DefaultChannelPipeline.this, e);
                          } 
          catch (Throwable t) {
                              notifyHandlerException(e, t);
                          }
                      } 
          else {
                          DefaultChannelPipeline.
          this.sendDownstream(prev, e);
                      }
                  }
          eventSunk方法會執(zhí)行
          private void handleAcceptedSocket(ChannelEvent e) {
                  
          if (e instanceof ChannelStateEvent) {
                      ChannelStateEvent event 
          = (ChannelStateEvent) e;
                      NioSocketChannel channel 
          = (NioSocketChannel) event.getChannel();
                      ChannelFuture future 
          = event.getFuture();
                      ChannelState state 
          = event.getState();
                      Object value 
          = event.getValue();

                      
          switch (state) {
                      
          case OPEN:
                          
          if (Boolean.FALSE.equals(value)) {
                              channel.worker.close(channel, future);
                          }
                          
          break;
                      
          case BOUND:
                      
          case CONNECTED:
                          
          if (value == null) {
                              channel.worker.close(channel, future);
                          }
                          
          break;
                      
          case INTEREST_OPS:
                          channel.worker.setInterestOps(channel, future, ((Integer) value).intValue());
                          
          break;
                      }
                  } 
          else if (e instanceof MessageEvent) {
                      MessageEvent event 
          = (MessageEvent) e;
                      NioSocketChannel channel 
          = (NioSocketChannel) event.getChannel();
                      
          //放入writerequestqueue隊列
                      boolean offered = channel.writeBuffer.offer(event);
                      
          assert offered;
                      
          //執(zhí)行nioworker的writeFromUserCode,之后執(zhí)行write0方法
                      channel.worker.writeFromUserCode(channel);
                  }
              }

          private void write0(NioSocketChannel channel) {
                  
          boolean open = true;
                  
          boolean addOpWrite = false;
                  
          boolean removeOpWrite = false;

                  
          long writtenBytes = 0;

                  
          final SocketSendBufferPool sendBufferPool = this.sendBufferPool;
                  
          final SocketChannel ch = channel.socket;
                  
          //之前將channel放到了該隊列
                  final Queue<MessageEvent> writeBuffer = channel.writeBuffer;
                  //默認(rèn)嘗試16次寫
                  
          final int writeSpinCount = channel.getConfig().getWriteSpinCount();
                  
          synchronized (channel.writeLock) {
                      channel.inWriteNowLoop 
          = true;
                      
          for (;;) {
                          MessageEvent evt 
          = channel.currentWriteEvent;
                          SendBuffer buf;
                          
          if (evt == null) {
                      
          //從writebuffer中獲得一個writeevent
                              if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) {
                                  removeOpWrite 
          = true;
                                  channel.writeSuspended 
          = false;
                                  
          break;
                              }
                              
                              channel.currentWriteBuffer 
          = buf = sendBufferPool.acquire(evt.getMessage());
                          } 
          else {
                              buf 
          = channel.currentWriteBuffer;
                          }

                          ChannelFuture future 
          = evt.getFuture();
                          
          try {
                              
          long localWrittenBytes = 0;
                              
          for (int i = writeSpinCount; i > 0; i --) {
                                  
          //發(fā)送數(shù)據(jù)給客戶端,執(zhí)行PooledSendBuffer.transferTo
                                  localWrittenBytes = buf.transferTo(ch);
                                  
          if (localWrittenBytes != 0) {
                                      writtenBytes 
          += localWrittenBytes;
                                      
          break;
                                  }
                                  
          if (buf.finished()) {
                                      
          break;
                                  }
                              }

                              
          if (buf.finished()) {
                                  
          // Successful write - proceed to the next message.
                                  buf.release();
                                  channel.currentWriteEvent 
          = null;
                                  channel.currentWriteBuffer 
          = null;
                                  evt 
          = null;
                                  buf 
          = null;
                                  future.setSuccess();
                              } 
          else {
                                  
          // Not written fully - perhaps the kernel buffer is full.
                                  addOpWrite = true;
                                  channel.writeSuspended 
          = true;

                                  
          if (localWrittenBytes > 0) {
                                      
          // Notify progress listeners if necessary.
                                      future.setProgress(
                                              localWrittenBytes,
                                              buf.writtenBytes(), buf.totalBytes());
                                  }
                                  
          break;
                              }
                          } 
          catch (AsynchronousCloseException e) {
                              
          // Doesn't need a user attention - ignore.
                          } catch (Throwable t) {
                              buf.release();
                              channel.currentWriteEvent 
          = null;
                              channel.currentWriteBuffer 
          = null;
                              buf 
          = null;
                              evt 
          = null;
                              future.setFailure(t);
                              fireExceptionCaught(channel, t);
                              
          if (t instanceof IOException) {
                                  open 
          = false;
                                  close(channel, succeededFuture(channel));
                              }
                          }
                      }
                      channel.inWriteNowLoop 
          = false;
                  }
                  
          //觸發(fā)寫完成事件,執(zhí)行的是DefaultChannelPipeline的sendUpstream,最后調(diào)用SimpleChannelUpstreamHandler.writeComplete
                  
          //pipeline中的upstreamhandler的writeComplete都未重寫,所以只是簡單的傳遞該事件
                  fireWriteComplete(channel, writtenBytes);

                  
          if (open) {
                      
          if (addOpWrite) {
                          setOpWrite(channel);
                      } 
          else if (removeOpWrite) {
                          clearOpWrite(channel);
                      }
                  }
              }

          posted @ 2010-12-04 14:54 alex_zheng 閱讀(1281) | 評論 (0)編輯 收藏


          2010年12月3日

          上一篇分析了serverboostrap的啟動,接下來分析netty的數(shù)據(jù)讀取。
          在nioworker的,負(fù)責(zé)讀取操作是由,在該方法中,如果當(dāng)前channel的(readyOps & SelectionKey.OP_READ) != 0 || readyOps == 0,且此時
          ch.read(buff)<0,則判斷客戶端已經(jīng)斷開連接
          private boolean read(SelectionKey k) {
                  
          final SocketChannel ch = (SocketChannel) k.channel();
                  
          final NioSocketChannel channel = (NioSocketChannel) k.attachment();

                  
          final ReceiveBufferSizePredictor predictor =
                      channel.getConfig().getReceiveBufferSizePredictor();
                  
          //默認(rèn)1024個字節(jié)空間
                  final int predictedRecvBufSize = predictor.nextReceiveBufferSize();

                  
          int ret = 0;
                  
          int readBytes = 0;
                  
          boolean failure = true;
                  
          //分配連續(xù)的1024個byte空間
                  ByteBuffer bb = recvBufferPool.acquire(predictedRecvBufSize);
                  
          try {
                      
          while ((ret = ch.read(bb)) > 0) {
                          readBytes 
          += ret;
                          
          if (!bb.hasRemaining()) {
                              
          break;
                          }
                      }
                      failure 
          = false;
                  } 
          catch (ClosedChannelException e) {
                      
          // Can happen, and does not need a user attention.
                  } catch (Throwable t) {
                      fireExceptionCaught(channel, t);
                  }

                  
          if (readBytes > 0) {
                      bb.flip();

                      
          final ChannelBufferFactory bufferFactory =
                          channel.getConfig().getBufferFactory();
                      
          final ChannelBuffer buffer = bufferFactory.getBuffer(readBytes);
                      buffer.setBytes(
          0, bb);
                      buffer.writerIndex(readBytes);

                      recvBufferPool.release(bb);

                      
          // Update the predictor.
                      predictor.previousReceiveBufferSize(readBytes);

                      
          //觸發(fā)消息接收事件,根據(jù)pipeline中upstreamhandler由上到下的順序,調(diào)用messageReceived方法
                      fireMessageReceived(channel, buffer);
                  } 
          else {
                      recvBufferPool.release(bb);
                  }

                  
          if (ret < 0 || failure) {
                      close(channel, succeededFuture(channel));
                      
          return false;
                  }

                  
          return true;
              }
              

          在pipelinefactory中的第一個upstreamhandler為DelimiterBasedFrameDecoder,繼承自FrameDecoder
          public ChannelPipeline getPipeline() throws Exception {
                  
          // Create a default pipeline implementation.
                  ChannelPipeline pipeline = pipeline();

                  
          // Add the text line codec combination first,
                  pipeline.addLast("framer"new DelimiterBasedFrameDecoder(
                          
          8192, Delimiters.lineDelimiter()));
                  pipeline.addLast(
          "decoder"new StringDecoder());
                  pipeline.addLast(
          "encoder"new StringEncoder());

                  
          // and then business logic.
                  pipeline.addLast("handler"new TelnetServerHandler());

                  
          return pipeline;
              }
          會調(diào)用FrameDecoder的messageReceived
           
          public void messageReceived(
                      ChannelHandlerContext ctx, MessageEvent e) 
          throws Exception {

                  Object m 
          = e.getMessage();
                  
          if (!(m instanceof ChannelBuffer)) {
                      ctx.sendUpstream(e);
                      
          return;
                  }

                  ChannelBuffer input 
          = (ChannelBuffer) m;
                  
          if (!input.readable()) {
                      
          return;
                  }

                  ChannelBuffer cumulation 
          = cumulation(ctx);
                  
          if (cumulation.readable()) {
                      cumulation.discardReadBytes();
                      cumulation.writeBytes(input);
                      callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress());
                  } 
          else {
                      
          //這里調(diào)用子類的decode方法
                      callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
                      
          if (input.readable()) {
                          cumulation.writeBytes(input);
                      }
                  }
              }

           //在這個upstreamhandler中,會一直讀取數(shù)據(jù),直到遇到協(xié)議約定的結(jié)束標(biāo)志才將messagereceived事件傳給下一個
           
          private void callDecode(
                      ChannelHandlerContext context, Channel channel,
                      ChannelBuffer cumulation, SocketAddress remoteAddress) 
          throws Exception {

                  
          while (cumulation.readable()) {
                      
          int oldReaderIndex = cumulation.readerIndex();
                      Object frame 
          = decode(context, channel, cumulation);
                      
          if (frame == null) {
                          
          if (oldReaderIndex == cumulation.readerIndex()) {
                              
          // Seems like more data is required.
                              
          // Let us wait for the next notification.
                              break;
                          } 
          else {
                              
          // Previous data has been discarded.
                              
          // Probably it is reading on.
                              continue;
                          }
                      } 
          else if (oldReaderIndex == cumulation.readerIndex()) {
                          
          throw new IllegalStateException(
                                  
          "decode() method must read at least one byte " +
                                  
          "if it returned a frame (caused by: " + getClass() + ")");
                      }
                      
          //將messagereceive事件傳給下個upstreamhandler
                      unfoldAndFireMessageReceived(context, remoteAddress, frame);
                  }
              }
          看子類的decode是如何判斷數(shù)據(jù)讀取完畢
          protected Object decode(
                      ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) 
          throws Exception {
                  
          // Try all delimiters and choose the delimiter which yields the shortest frame.
                  int minFrameLength = Integer.MAX_VALUE;
                  ChannelBuffer minDelim 
          = null;
                  
          //獲取\r\n的位置
                  for (ChannelBuffer delim: delimiters) {
                      
          int frameLength = indexOf(buffer, delim);
                      
          if (frameLength >= 0 && frameLength < minFrameLength) {
                          minFrameLength 
          = frameLength;
                          minDelim 
          = delim;
                      }
                  }
                  
          //如果找到\r\n,表明客戶端數(shù)據(jù)發(fā)送完畢
                  if (minDelim != null) {
                      
          int minDelimLength = minDelim.capacity();
                      ChannelBuffer frame;

                      
          if (discardingTooLongFrame) {
                          
          // We've just finished discarding a very large frame.
                          
          // Go back to the initial state.
                          discardingTooLongFrame = false;
                          buffer.skipBytes(minFrameLength 
          + minDelimLength);

                          
          // TODO Let user choose when the exception should be raised - early or late?
                          
          //      If early, fail() should be called when discardingTooLongFrame is set to true.
                          int tooLongFrameLength = this.tooLongFrameLength;
                          
          this.tooLongFrameLength = 0;
                          fail(ctx, tooLongFrameLength);
                          
          return null;
                      }

                      
          if (minFrameLength > maxFrameLength) {
                          
          // Discard read frame.
                          buffer.skipBytes(minFrameLength + minDelimLength);
                          fail(ctx, minFrameLength);
                          
          return null;
                      }

                      
          if (stripDelimiter) {
                          
          //這里讀取全部數(shù)據(jù)
                          frame = buffer.readBytes(minFrameLength);
                          buffer.skipBytes(minDelimLength);
                      } 
          else {
                          frame 
          = buffer.readBytes(minFrameLength + minDelimLength);
                      }

                      
          return frame;
                  } 
          else {
                      
          if (!discardingTooLongFrame) {
                          
          if (buffer.readableBytes() > maxFrameLength) {
                              
          // Discard the content of the buffer until a delimiter is found.
                              tooLongFrameLength = buffer.readableBytes();
                              buffer.skipBytes(buffer.readableBytes());
                              discardingTooLongFrame 
          = true;
                          }
                      } 
          else {
                          
          // Still discarding the buffer since a delimiter is not found.
                          tooLongFrameLength += buffer.readableBytes();
                          buffer.skipBytes(buffer.readableBytes());
                      }
                      
          return null;
                  }
              }
          因?yàn)閡nfold默認(rèn)是false,會執(zhí)行,調(diào)用下一個upstreamhandler,這里是stringdecoder,通過stringdecoder,將channelbuffer中的數(shù)據(jù)轉(zhuǎn)為string
          然后再觸發(fā)下一個upstreamhandler的messagereceive,這里是TelnetServerHandler
          public void messageReceived(
                      ChannelHandlerContext ctx, MessageEvent e) {

                  
          // Cast to a String first.
                  
          // We know it is a String because we put some codec in TelnetPipelineFactory.
                  String request = (String) e.getMessage();

                  
          // Generate and write a response.
                  String response;
                  
          boolean close = false;
                  
          if (request.length() == 0) {
                      response 
          = "Please type something."r"n";
                  } 
          else if (request.toLowerCase().equals("bye")) {
                      response 
          = "Have a good day!"r"n";
                      close 
          = true;
                  } 
          else {
                      response 
          = "Did you say '" + request + "'?"r"n";
                  }

                  
          // We do not need to write a ChannelBuffer here.
                  
          // We know the encoder inserted at TelnetPipelineFactory will do the conversion.
                  ChannelFuture future = e.getChannel().write(response);

                  
          // Close the connection after sending 'Have a good day!'
                  
          // if the client has sent 'bye'.
                  if (close) {
                      future.addListener(ChannelFutureListener.CLOSE);
                  }
              }

          數(shù)據(jù)讀取分析完畢,接著繼續(xù)分析服務(wù)器端數(shù)據(jù)的發(fā)送


          posted @ 2010-12-03 21:26 alex_zheng 閱讀(2090) | 評論 (0)編輯 收藏


          僅列出標(biāo)題  

          posts - 10, comments - 9, trackbacks - 0, articles - 15

          Copyright © alex_zheng

          主站蜘蛛池模板: 黑河市| 康马县| 田东县| 林口县| 通化市| 长阳| 西贡区| 定日县| 东明县| 禹州市| 扬州市| 岢岚县| 台湾省| 合山市| 车致| 元阳县| 化德县| 涿州市| 巍山| 德化县| 阿拉尔市| 雷山县| 辛集市| 库伦旗| 莱西市| 方城县| 墨竹工卡县| 余干县| 高唐县| 南漳县| 江津市| 宣恩县| 独山县| 中山市| 泗水县| 南乐县| 牙克石市| 沙河市| 莎车县| 古丈县| 诏安县|