[Mina2.0源码](六)服务端、客户端读数据

服务端建立请求后,就阻塞在NioProcessor父类AbstractPollingIoProcessor的内部类Processor.run()中的int selected = select(SELECT_TIMEOUT);等待OP_READ事件。

当客户端往通道中写数据后,就唤醒往下执行。

            if (selected > 0) {
                //LOG.debug("Processing ..."); // This log hurts one of the MDCFilter test...
                process();
            }
process()
private void process() throws Exception {
    for (Iterator<S> i = selectedSessions(); i.hasNext();) {
        S session = i.next();
        process(session);
        i.remove();
    }
}
process(session);
private void process(S session) {
	// Process Reads
	if (isReadable(session) && !session.isReadSuspended()) {
	    read(session);
	}

	// Process writes
	if (isWritable(session) && !session.isWriteSuspended()) {
	    // add the session to the queue, if it's not already there
        if (session.setScheduledForFlush(true)) {
            flushingSessions.add(session);
        }
    }
}
read()
private void read(S session) {
    IoSessionConfig config = session.getConfig();
    int bufferSize = config.getReadBufferSize();
    IoBuffer buf = IoBuffer.allocate(bufferSize);

    final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();

    try {
        int readBytes = 0;
        int ret;

        try {
            if (hasFragmentation) {
            	
                while ((ret = read(session, buf)) > 0) {
                    readBytes += ret;

                    if (!buf.hasRemaining()) {
                        break;
                    }
                }
            } else {
                ret = read(session, buf);

                if (ret > 0) {
                    readBytes = ret;
                }
            }
        } finally {
            buf.flip();
        }

        if (readBytes > 0) {
            IoFilterChain filterChain = session.getFilterChain();
            filterChain.fireMessageReceived(buf);
            buf = null;

            if (hasFragmentation) {
                if (readBytes << 1 < config.getReadBufferSize()) {
                    session.decreaseReadBufferSize();
                } else if (readBytes == config.getReadBufferSize()) {
                    session.increaseReadBufferSize();
                }
            }
        }

        if (ret < 0) {
            scheduleRemove(session);
        }
    } catch (Throwable e) {
        if (e instanceof IOException) {
            if (!(e instanceof PortUnreachableException)
                    || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
                    || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) {
                scheduleRemove(session);
            }
        }

        IoFilterChain filterChain = session.getFilterChain();
        filterChain.fireExceptionCaught(e);
    }
}

1、read(session, buf)

protected int read(NioSession session, IoBuffer buf) throws Exception {
    ByteChannel channel = session.getChannel();

    return channel.read(buf.buf());
}
2、filterChain.fireMessageReceived(buf);DefaultIoFilterChain类中的方法。过滤器链的设置和客户端设置的一致,不再累述。

public void fireMessageReceived(Object message) {
    if (message instanceof IoBuffer) {
        session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());
    }

    Entry head = this.head;
    callNextMessageReceived(head, session, message);
}
read数据的时候从过滤器链首位过滤器开始往后执行,和write数据的时候刚好相反。

callNextMessageReceived()

private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
    try {
        IoFilter filter = entry.getFilter();
        NextFilter nextFilter = entry.getNextFilter();
        filter.messageReceived(nextFilter, session, message);
    } catch (Throwable e) {
        fireExceptionCaught(e);
    }
}
那么filter.messageReceived(nextFilter, session, message);调用HeadFilter父类IoFilterAdapter的方法

其他业务系统定义的过滤器,其过滤的逻辑是卸载此方法中的。

public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
    nextFilter.messageReceived(session, message);
}
EntryImpl内部类NextFilter,取过滤器链的下一个过滤器执行。

public void messageReceived(IoSession session, Object message) {
    Entry nextEntry = EntryImpl.this.nextEntry;
    callNextMessageReceived(nextEntry, session, message);
}
最后会执行末位过滤器EntryImpl对象tail的方法

public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
    AbstractIoSession s = (AbstractIoSession) session;
    if (!(message instanceof IoBuffer)) {
        s.increaseReadMessages(System.currentTimeMillis());
    } else if (!((IoBuffer) message).hasRemaining()) {
        s.increaseReadMessages(System.currentTimeMillis());
    }

    try {
        session.getHandler().messageReceived(s, message);
    } finally {
        if (s.getConfig().isUseReadOperation()) {
            s.offerReadFuture(message);
        }
    }
}
session.getHandler().messageReceived(s, message);调用服务启动时设置的handler,将读到的数据交由业务系统处理。

服务端读到数据后处理完业务,如果有数据返回也会使用session.write(Object object);和客户端写数据一样,先走一遍过滤器,再往通道中写。

而客户端读到数据,也和上面一样,先走一遍过滤器,不过略有区别的是,我们的客户端没有使用handler(客户端没有handler不会报异常。服务端是一定要的,在bind方法回去判断是否为空)。直接用session.read()方法死等:ReadFuture rf = session.read().awaitUninterruptibly();awaitUninterruptibly()在建立客户端的时候类似。等一会儿判断开关ready是否true,没有再等一会儿,而read的开关并非在初始化session的时候打开的。

从头捋一捋,客户端也是NioProcessor监听OP_READ,收到数据后进入过滤器链,到末位过滤器tail后,也就是上面那段代码,因为客户端设置了connector.getSessionConfig().setUseReadOperation(true);所以会执行finally中的s.offerReadFuture(message);AbstractIoSession类

public final void offerReadFuture(Object message) {
    newReadFuture().setRead(message);
}
private ReadFuture newReadFuture() {
    Queue<ReadFuture> readyReadFutures = getReadyReadFutures();
    Queue<ReadFuture> waitingReadFutures = getWaitingReadFutures();
    ReadFuture future;
    synchronized (readyReadFutures) {
        future = waitingReadFutures.poll();
        if (future == null) {
            future = new DefaultReadFuture(this);
            readyReadFutures.offer(future);
        }
    }
    return future;
}

取一个future,没有就创建一个DefaultReadFuture对象。

public void setRead(Object message) {
    if (message == null) {
        throw new IllegalArgumentException("message");
    }
    setValue(message);
}
public void setValue(Object newValue) {
    synchronized (lock) {
        // Allow only once.
        if (ready) {
            return;
        }

        result = newValue;
        ready = true;
        if (waiters > 0) {
            lock.notifyAll();
        }
    }

    notifyListeners();
}
这个开关到这里就打开了,而这个result就是服务端写入的数据,接下来的DefaultReadFuture.getMessage()取得就是这个值。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值