apache mina: 写数据过程
来源:互联网 发布:58端口多少钱一个月 编辑:程序博客网 时间:2024/05/21 22:20
NioSocketSession(AbstractIoSession).write(Object)
调用IoSession.write(Object)方法向应用层中写入数据。
// Now, we can write the message. First, create a future
WriteFuture writeFuture = new DefaultWriteFuture(this);
WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);
public class DefaultWriteRequest implements WriteRequest {
/** An empty message */
public static final byte[] EMPTY_MESSAGE = new byte[] {};
private final Object message;
private final WriteFuture future;
private final SocketAddress destination;
}
然后创建一个WriteRequest 请求. WriteRequest 里面包括要写出的数据message ,写出数据的结果future 以及写出数据的目的地。
public void write(S session, WriteRequest writeRequest)
{
WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
writeRequestQueue.offer(session, writeRequest);
if (!session.isWriteSuspended()) {
this.flush(session);
}
}
在HeadFilter中,会获取IoSession与之相关的 WriteRequestQueue 队列,作为应用层写出数据缓冲区。 把写出的WriteRequest放到写出缓冲区队列中。
因为apache mina 是按照SEDA架构设计,同时把要写出数据的IoSession放在 flushingSessions 队列中等待写出数据。
private class HeadFilter extends IoFilterAdapter { @SuppressWarnings("unchecked") @Override public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception { AbstractIoSession s = (AbstractIoSession) session; // Maintain counters. if (writeRequest.getMessage() instanceof IoBuffer) { IoBuffer buffer = (IoBuffer) writeRequest.getMessage(); // I/O processor implementation will call buffer.reset() // it after the write operation is finished, because // the buffer will be specified with messageSent event. buffer.mark(); int remaining = buffer.remaining(); if (remaining > 0) { s.increaseScheduledWriteBytes(remaining); } } else { s.increaseScheduledWriteMessages(); } WriteRequestQueue writeRequestQueue = s.getWriteRequestQueue(); if (!s.isWriteSuspended()) { if (writeRequestQueue.isEmpty(session)) { // We can write directly the message s.getProcessor().write(s, writeRequest); } else { s.getWriteRequestQueue().offer(s, writeRequest); s.getProcessor().flush(s); } } else { s.getWriteRequestQueue().offer(s, writeRequest); } } @SuppressWarnings("unchecked") @Override public void filterClose(NextFilter nextFilter, IoSession session) throws Exception { ((AbstractIoSession) session).getProcessor().remove(session); } }
然后在Processor线程的run()方法中,来轮询flushIoSession队列。
// Write the pending requests
long currentTime = System.currentTimeMillis();
flush(currentTime);
在NioProcessor(AbstractPollingIoProcessor<S>).flushNow(S, long) 方法中,依次把同一个IoSession中的writeRequest 请求写入到系统缓冲区。
private boolean flushNow(S session, long currentTime) { if (!session.isConnected()) { scheduleRemove(session); return false; } final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation(); //获取与IoSession相关联的写队列 final WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); // 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 writtenBytes = 0; WriteRequest req = null; try { // Clear OP_WRITE setInterestedInWrite(session, false); //并检查写请求 do { // Check for pending writes. req = session.getCurrentWriteRequest(); if (req == null) { req = writeRequestQueue.poll(session); if (req == null) { break; } session.setCurrentWriteRequest(req); } 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?"); } //当内核 缓存buff已经满的时候,继续设置写操作 if (localWrittenBytes == 0) { // Kernel buffer is full. setInterestedInWrite(session, true); return false; } writtenBytes += localWrittenBytes; if (writtenBytes >= maxWrittenBytes) { // Wrote too much scheduleFlush(session); return false; } if (message instanceof IoBuffer) { ((IoBuffer) message).free(); } } while (writtenBytes < maxWrittenBytes); } catch (Exception e) { if (req != null) { req.getFuture().setException(e); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); return false; } return true; }
/** * Closes this session immediately or after all queued write requests * are flushed. This operation is asynchronous. Wait for the returned * {@link CloseFuture} if you want to wait for the session actually closed. * * @param immediately {@code true} to close this session immediately * . The pending write requests * will simply be discarded. * {@code false} to close this session after all queued * write requests are flushed (i.e. {@link #close()}). */ CloseFuture close(boolean immediately);
private final CloseFuture closeOnFlush() {
getWriteRequestQueue().offer(this, CLOSE_REQUEST);
getProcessor().flush(this);
return closeFuture;
}
/**
* An internal write request object that triggers session close.
*
* @see #writeRequestQueue
*/
private static final WriteRequest CLOSE_REQUEST = new DefaultWriteRequest(new Object());
public synchronized WriteRequest poll(IoSession session) {
WriteRequest answer = queue.poll(session);
if (answer == CLOSE_REQUEST) {
AbstractIoSession.this.close();
dispose(session);
answer = null;
}
return answer;
}
当IoSessioni.close(flase) 调用时, 创建了一个CLOSE_Request请求,当轮询flushIosession时,调用了close()方法。因为IoSession.close(flase) 也是一个写请求队列,所以在处理CLOSE_REQUEST请求时,之前的应用层缓冲区数据已经写入到系统缓冲区中。
private class HeadFilter extends IoFilterAdapter {
public void filterClose(NextFilter nextFilter, IoSession session) throws Exception {
((AbstractIoSession) session).getProcessor().remove(session);
}
}
/** A queue used to store the sessions to be removed */
private final Queue<S> removingSessions = new ConcurrentLinkedQueue<S>();
在HeadFilter处理时,把IoSession加入到removingSessions队列中等待处理。
NioProcessor(AbstractPollingIoProcessor<S>).removeSessions()
AbstractPollingIoProcessor<S>.access$12(AbstractPollingIoProcessor)
AbstractPollingIoProcessor$Processor.run()
Processor线程在循环run()方法中处理等待被删除的IoSession.
private int removeSessions() { int removedSessions = 0; for (S session = removingSessions.poll(); session != null; session = removingSessions.poll()) { SessionState state = getState(session); // Now deal with the removal accordingly to the session's state switch (state) { case OPENED: // Try to remove this session if (removeNow(session)) { removedSessions++; } break; case CLOSING: // Skip if channel is already closed break; case OPENING: // Remove session from the newSessions queue and // remove it newSessions.remove(session); if (removeNow(session)) { removedSessions++; } break; default: throw new IllegalStateException(String.valueOf(state)); } } return removedSessions; }
如果在IoSession真正关闭时,有数据尚未写入到系统缓冲区,将会有异常抛出。
private void clearWriteRequestQueue(S session) { WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); WriteRequest req; List<WriteRequest> failedRequests = new ArrayList<WriteRequest>(); if ((req = writeRequestQueue.poll(session)) != null) { Object message = req.getMessage(); if (message instanceof IoBuffer) { IoBuffer buf = (IoBuffer) message; // The first unwritten empty buffer must be // forwarded to the filter chain. if (buf.hasRemaining()) { buf.reset(); failedRequests.add(req); } else { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageSent(req); } } else { failedRequests.add(req); } // Discard others. while ((req = writeRequestQueue.poll(session)) != null) { failedRequests.add(req); } } // Create an exception and notify. if (!failedRequests.isEmpty()) { WriteToClosedSessionException cause = new WriteToClosedSessionException(failedRequests); for (WriteRequest r : failedRequests) { session.decreaseScheduledBytesAndMessages(r); r.getFuture().setException(cause); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(cause); } }
- apache mina: 写数据过程
- apache mina中写的过程分析
- apache mina : 用户自定义数据存储
- Apache Mina
- Apache Mina
- Apache Mina
- Apache Mina
- apache mina
- Apache Mina
- apache mina
- Apache MINA
- Apache mina
- Apache Mina
- Apache Mina
- Apache Mina
- Apache Mina 源码再读 1 Bind过程以及DefaultIoFuture源码
- Apache Mina 源码再读2 IoSession创建过程源代码剖析
- Apache MINA - Mina 特性说明
- XML xml spy 5.0 注册码
- hrbust 哈理工oj1490 咒语【基础并查集】
- [BZOJ1011][HNOI2008]遥远的行星
- 理解activity的生命周期
- 文本文件与二进制的区别
- apache mina: 写数据过程
- 利用 Bootstrap 进行快速 Web 开发
- 3种PHP连接MYSQL数据库的常用方法
- 设置npm安装程序时的默认目录
- 1003. Emergency (25)
- Android基础——TabHost使用(自定义按钮菜单)
- Reverse Bits-位反转
- 数论 随记
- 配分函数