首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 服务器 > Apache >

Apache mina设立写(write)buffer以及原理

2012-07-29 
Apache mina设置写(write)buffer以及原理对于我前一篇论述mina的read buffer大小设置以及mina对其自动控制

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.sun.com/bugdatabase/view_bug.do?bug_id=5103988            String message = e.getMessage();            if (message != null && message.contains("temporarily unavailable")) {                return 0;            }                        throw e;        }    }


也就是说会开一个FileChannel进行文件传递,最后通过rt.jar提供的sun.nio.ch.FileChannelImpl
   public abstract long transferTo(long position, long count,    WritableByteChannel target)

方法进行发送.

该方法解析如下

transferTo
public abstract long transferTo(long position,
                                long count,
                                WritableByteChannel target)
                         throws IOException将字节从此通道的文件传输到给定的可写入字节通道。
试图读取从此通道的文件中给定 position 处开始的 count 个字节,并将其写入目标通道。此方法的调用不一定传输所有请求的字节;是否传输取决于通道的性质和状态。如果此通道的文件从给定的 position 处开始所包含的字节数小于 count 个字节,或者如果目标通道是非阻塞的并且其输出缓冲区中的自由空间少于 count 个字节,则所传输的字节数要小于请求的字节数。

此方法不修改此通道的位置。如果给定的位置大于该文件的当前大小,则不传输任何字节。如果目标通道中有该位置,则从该位置开始写入各字节,然后将该位置增加写入的字节数。

与从此通道读取并将内容写入目标通道的简单循环语句相比,此方法可能高效得多。很多操作系统可将字节直接从文件系统缓存传输到目标通道,而无需实际复制各字节。


参数:
position - 文件中的位置,从此位置开始传输;必须为非负数
count - 要传输的最大字节数;必须为非负数
target - 目标通道
返回:
实际已传输的字节数,可能为零

热点排行