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 阅读(267) | 评论 (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 阅读(4385) | 评论 (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 阅读(539) | 评论 (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 阅读(1348) | 评论 (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 阅读(327) | 评论 (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 阅读(864) | 评论 (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 阅读(3257) | 评论 (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 阅读(1145) | 评论 (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 阅读(1262) | 评论 (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 阅读(2074) | 评论 (0)编辑 收藏


仅列出标题  

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

Copyright © alex_zheng