2011年12月24日

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

          1. 只做需要做的工作 

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


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

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

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

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

          5. 集中注意力 

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

          6. 盡早并且經常性地進行代碼重構 

          有時,你不得不放棄漂亮的代碼轉而去尋找真正對項目有用的代碼,但沒關系,如果你的現有項目中有這樣的代碼,最好的方式便是不要看它,并重構。 

          7. 只管去做 

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

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

          高效開發者喜歡用文本編輯器勝過IDE編輯器,因為這樣可以學到更多東西。無論什么情況,盡量使用鍵盤快捷鍵,因為熟練使用一件工具的前提是熟悉它。 

          在選擇編輯器時,認真考慮并挑選最好的(Emacs或Vim),因為它們是通用的。其次,挑選你的首選平臺最支持的。使用宏,不斷地寫代碼;使用Mac上的TextExpander為整個段落創建快捷方式;使用Visual Studio或SublimeText的自動補齊功能;使用支持按行/列分割窗口的編輯器,這樣你便能同時看到單元測試和代碼(或模型、視圖)。 

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

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

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

          10. 潛意識是強大的工具 

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

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

          11. 推動自身和團隊進步 

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

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

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


          2011年3月30日

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

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


          2011年2月22日

          有時候,我們希望用一個字段保存對象的所屬狀態或分類,當這個值存在多種組合的時候,我們就可以使用位運算來表示組合后的值。
          先定義類型A=1,B=2,C=4,D=8,E=16等2的倍數,
          那么objectA即屬于A又屬于C,其值為A|C,添加類型使用|(或)運算,移除類型使用^(異或)運算,判斷是否屬于某個類型使用&運算。
          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 閱讀(578) | 評論 (0)編輯 收藏


          2011年1月17日

          轉自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 對話框中選擇或輸入以下內容:
                  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 對話框中選擇或輸入以下內容:
                  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 閱讀(1370) | 評論 (0)編輯 收藏


          2010年12月14日

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

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


          2010年12月9日

          先看下netty的channel對象關聯關系。channel是由channelfactory來創建的,channelfactory又分為client和server兩種。
          channelfuture負責channel的所處狀態,一個channle中關聯來channelpipeline,channelpipeline則由pipelinefactory創建,
          在channelpipeline中有內部類channelhandlercontext,保存channelhandler的鏈式結構,由channelhandler來傳遞channelevent,
          channelevent分別有open,bind,connected,close,messagereceived等。

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


          2010年12月6日

          在看完了server端的啟動,再來看client端的啟動過程是怎么進行的。例子是TelentServer對應的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構造函數中會觸發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);
              }
          然后執行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方法對該事件不做處理,往上傳遞該事件,執行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);
                      }
                  }
          執行NioClientSocketPipelineSink.eventSunk,其中會執行
           private void connect(
                      
          final NioClientSocketChannel channel, final ChannelFuture cf,
                      SocketAddress remoteAddress) {
                  
          try {
                      
          //如果返回true,調用nioworker.register,開始啟動nioworker線程處理該channel的讀寫
                      
          //否則,交給boss.register方法,在boss線程中完成連接
                      if (channel.socket.connect(remoteAddress)) {
                          channel.worker.register(channel, cf);
                      } 
          else {
                          
          //為當前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));
                  }
              }

          執行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里執行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線程來進行數據的發送和接收了。

          posted @ 2010-12-06 16:59 alex_zheng 閱讀(3276) | 評論 (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 閱讀(1165) | 評論 (0)編輯 收藏


          2010年12月4日

          上一篇分析了服務器端讀取客戶發送的數據,這篇來看服務器端如何發送數據給客戶端,服務器往外發送數據是通過downstreamhandler從下到上執行
          發送從ChannelFuture future = e.getChannel().write(response)開始執行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,最后執行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數據,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 {
                              
          //因為stringencoder是唯一一個downstreamhandler,這里執行NioServerSocketPipelineSink.eventSunk
                              getSink().eventSunk(DefaultChannelPipeline.this, e);
                          } 
          catch (Throwable t) {
                              notifyHandlerException(e, t);
                          }
                      } 
          else {
                          DefaultChannelPipeline.
          this.sendDownstream(prev, e);
                      }
                  }
          eventSunk方法會執行
          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;
                      
          //執行nioworker的writeFromUserCode,之后執行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;
                  //默認嘗試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 --) {
                                  
          //發送數據給客戶端,執行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;
                  }
                  
          //觸發寫完成事件,執行的是DefaultChannelPipeline的sendUpstream,最后調用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 閱讀(1286) | 評論 (0)編輯 收藏


          2010年12月3日

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

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

                  
          int ret = 0;
                  
          int readBytes = 0;
                  
          boolean failure = true;
                  
          //分配連續的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);

                      
          //觸發消息接收事件,根據pipeline中upstreamhandler由上到下的順序,調用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;
              }
          會調用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 {
                      
          //這里調用子類的decode方法
                      callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
                      
          if (input.readable()) {
                          cumulation.writeBytes(input);
                      }
                  }
              }

           //在這個upstreamhandler中,會一直讀取數據,直到遇到協議約定的結束標志才將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是如何判斷數據讀取完畢
          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,表明客戶端數據發送完畢
                  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) {
                          
          //這里讀取全部數據
                          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;
                  }
              }
          因為unfold默認是false,會執行,調用下一個upstreamhandler,這里是stringdecoder,通過stringdecoder,將channelbuffer中的數據轉為string
          然后再觸發下一個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);
                  }
              }

          數據讀取分析完畢,接著繼續分析服務器端數據的發送


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


          僅列出標題  

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

          Copyright © alex_zheng

          主站蜘蛛池模板: 资溪县| 天祝| 梁河县| 怀集县| 布拖县| 石门县| 左云县| 枣阳市| 波密县| 惠安县| 资阳市| 铜川市| 南郑县| 延边| 方城县| 新安县| 武冈市| 浦北县| 奉节县| 威海市| 遂昌县| 阿荣旗| 海林市| 鸡西市| 申扎县| 福贡县| 修水县| 霍邱县| 杨浦区| 化隆| 阳新县| 报价| 淅川县| 波密县| 新巴尔虎左旗| 柳江县| 宣武区| 交城县| 达州市| 突泉县| 洞头县|