<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    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 閱讀(286) | 評論 (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 閱讀(4424) | 評論 (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 閱讀(570) | 評論 (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 閱讀(1364) | 評論 (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 閱讀(336) | 評論 (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 閱讀(876) | 評論 (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 閱讀(3271) | 評論 (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日

    上一篇分析了服務器端讀取客戶發送的數據,這篇來看服務器端如何發送數據給客戶端,服務器往外發送數據是通過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 閱讀(1280) | 評論 (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 閱讀(2090) | 評論 (0)編輯 收藏


    僅列出標題  

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

    Copyright © alex_zheng

    主站蜘蛛池模板: 亚洲娇小性色xxxx| 成人AV免费网址在线观看| 亚洲最大中文字幕无码网站| 亚洲啪啪AV无码片| 妞干网免费观看视频| 四虎成人精品永久免费AV| 免费国产va视频永久在线观看| 亚洲伊人久久大香线蕉AV| 91亚洲导航深夜福利| 久久精品国产亚洲综合色| 亚洲福利在线播放| 四虎影视免费永久在线观看| 一个人在线观看视频免费| 99re在线这里只有精品免费| 成人无码WWW免费视频| 亚洲视频在线免费| 特级毛片在线大全免费播放| 亚洲国产精品美女久久久久| 亚洲成A∨人片在线观看无码| 亚洲天天在线日亚洲洲精| 国产成人无码综合亚洲日韩| 夜夜春亚洲嫩草影院| 国产精品亚洲二区在线观看| 国产成人啪精品视频免费网| 女人18毛片a级毛片免费视频| 天天操夜夜操免费视频| 最新中文字幕免费视频| 午夜男人一级毛片免费| 成人片黄网站色大片免费| 成人午夜18免费看| 天堂在线免费观看中文版| 日本免费观看网站| 四虎影视永久免费观看地址| 内射无码专区久久亚洲| 亚洲AV无码成H人在线观看| 亚洲情a成黄在线观看| 国产亚洲精品资在线| 精品亚洲综合久久中文字幕| 久久久久亚洲?V成人无码| 亚洲日韩国产精品第一页一区| 在线播放亚洲第一字幕|