日期:2014-05-17  浏览次数:20982 次

Apache mina设置写(write)buffer以及原理
对于我前一篇论述mina的read buffer大小设置以及mina对其自动控制的奥秘http://414149609.iteye.com/admin/blogs/1185777
本文重点论述一下mina发送端都发送分包的奥秘进行论述,还是以前篇(上面链接)所在的服务器客户端作为原型,可以进入链接查看。


mina的把需要发送的数据(包括对象,字节等数据)都转换为IoBuffer的子类,IoBuffer其实就是原来jdk中提供nio实现的Buffer的包装类。

也就是说最后的数据会转换为字节通过socket建立的channel发送出去的。

与前篇文章想对等,write和read的动作都在org.apache.mina.transport.socket.nio.NioProcessor
实现。请看代码
    @Override
    protected int write(NioSession session, IoBuffer buf, int length) throws Exception {
        if (buf.remaining() <= length) {
            return session.getChannel().write(buf.buf());
        }
        
        int oldLimit = buf.limit();
        buf.limit(buf.position() + length);
        try {
            return session.getChannel().write(buf.buf());
        } finally {
            buf.limit(oldLimit);
        }
    }




而每次发送的的报文大小由org.apache.mina.core.polling.AbstractPollingIoProcessor<T>
类中的flushNow决定,也是他调起write这个方法
        // Set limitation for the number of written bytes for read-write
        // fairness.  I used maxReadBufferSize * 3 / 2, which yields best
        // performance in my experience while not breaking fairness much.
        final int maxWrittenBytes = session.getConfig().getMaxReadBufferSize()
                + (session.getConfig().getMaxReadBufferSize() >>> 1);




                int localWrittenBytes = 0;
                Object message = req.getMessage();
                if (message instanceof IoBuffer) {
                    localWrittenBytes = writeBuffer(session, req,
                            hasFragmentation, maxWrittenBytes - writtenBytes,
                            currentTime);
                    if (localWrittenBytes > 0
                            && ((IoBuffer) message).hasRemaining()) {
                        // the buffer isn't empty, we re-interest it in writing 
                        writtenBytes += localWrittenBytes;
                        setInterestedInWrite(session, true);
                        return false;
                    }
                } else if (message instanceof FileRegion) {
                    localWrittenBytes = writeFile(session, req,
                            hasFragmentation, maxWrittenBytes - writtenBytes,
                            currentTime);

                    // Fix for Java bug on Linux http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103988
                    // If there's still data to be written in the FileRegion, return 0 indicating that we need
                    // to pause until writing may resume.
                    if (localWrittenBytes > 0
                            && ((FileRegion) message).getRemainingBytes() > 0) {
                        writtenBytes += localWrittenBytes;
                        setInterestedInWrite(session, true);
                        return false;
                    }
                } else {
                    throw new IllegalStateException(
                            "Don't know how to handle message of type '"
                                    + message.getClass().getName()
                                    + "'.  Are you missing a protocol encoder?");
                }


默认一次发送报文大小为MaxReadBufferSize+MaxReadBufferSize/2=98304

flushNow方法对于应用上端发送的数据作两类分支操作FileRegion以及IoBuffer
如果是FileRegion,NioProcessor会采用以下方式发送File
    @Override
    protected int transferFile(NioSession session, FileRegion region, int length) throws Exception {
        try {
            return (int) region.getFileChannel().transferTo(region.getPosition(), length, session.getChannel());
        } catch (IOException e) {
            // Check to see if the IOException is being thrown due to
            // http://bugs.su