我们接着上一篇继续分析;
在addNow方法执行结束之后,我们已经为当前NioProcessor里面所有的NioSocketSession对应的SocketChannel注册了OP_READ事件,接下来继续查看Processor的run方法,源码在上一篇中有,执行到第49行,判断如果selected大于0执行第52行的process方法,selected的值其实就是Selector的select方法返回值,表示客户端存在和服务端交互的请求,那么我们看看process做了些什么事:
AbstractPollingIoProcessor$process()
- private void process() throws Exception {
- for (Iterator<S> i = selectedSessions(); i.hasNext();) {
- S session = i.next();
- process(session);
- i.remove();
- }
- }
AbstractPollingIoProcessor$process()
- 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);
- }
- }
- }
AbstractPollingIoProcessor$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);
- IoFilterChain filterChain = session.getFilterChain();
- filterChain.fireInputClosed();
- }
- } catch (Exception 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);
- }
- }
这部分代码比较长,我们了解主干就可以了;
首先第4行创建了一个IoBuffer对象,其实这就是我们java NIO中的Buffer角色,接着看到调用了read(session, buf)方法,这个方法返回值大于0表示读取数据成功,具体这个方法里面执行了些什么我们可以到NioProcessor里面的read方法看看:
- protected int read(NioSession session, IoBuffer buf) throws Exception {
- ByteChannel channel = session.getChannel();
- return channel.read(buf.buf());
- }
如果我们读取到了数据,就会执行第33行的if语句,在if语句块中会执行IoFilterChain的fireMessageReceived方法,其实呢,IoFilterChain就是我们的责任链,前面分析源码的过程中我们知道在创建NioSocketSession的时候会创建一个DefaultIoFilterChain出来,并且会在它里面创建一个EntryImpl链,默认情况下会创建一个HeadFilter链头和TailFilter链尾,那么这里的IoFilterChain其实就是对DefaultIoFilterChain进行转换过来的,默认情况下也就值存在链头和链尾了,我们在使用MINA的时候可以通过NioSocketAcceptor的getFilterChain获得其对应的IoFilterChain,其实getFilterChain的真正实现是在AbstarctIoService里面的,有了这个IoFilterChain之后,我们可以调用他的addLast方法为其添加我们自定义或者MINA自带的Filter对象,addLast的真正实现是在DefaultIoFilterChain里面的,我们可以看看:
- public synchronized void addLast(String name, IoFilter filter) {
- checkAddable(name);
- register(tail.prevEntry, name, filter);
- }
- private void register(EntryImpl prevEntry, String name, IoFilter filter) {
- EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);
- try {
- filter.onPreAdd(this, name, newEntry.getNextFilter());
- } catch (Exception e) {
- throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e);
- }
- prevEntry.nextEntry.prevEntry = newEntry;
- prevEntry.nextEntry = newEntry;
- name2entry.put(name, newEntry);
- try {
- filter.onPostAdd(this, name, newEntry.getNextFilter());
- } catch (Exception e) {
- deregister0(newEntry);
- throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e);
- }
- }
他是DefaultIoFilterChain的静态内部类,代码比较长,我就截取两个方法,其他的方法类似啦:
- private static class TailFilter extends IoFilterAdapter {
- @Override
- public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
- try {
- session.getHandler().sessionCreated(session);
- } finally {
- // Notify the related future.
- ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE);
- if (future != null) {
- future.setSession(session);
- }
- }
- }
- @Override
- public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
- session.getHandler().sessionOpened(session);
- }
好了,扯得有点远了,继续回到我们的AbstractPollingIoProcessor里面的read方法,第33行在我们获取到数据之后首先会获得我们的DefaultIoFilterChain责任链,并且调用fireMessageReceived方法,我们来看看fireMessageReceived方法:
这个方法位于DefaultIoFilterChain中
- public void fireMessageReceived(Object message) {
- if (message instanceof IoBuffer) {
- session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());
- }
- callNextMessageReceived(head, session, message);
- }
- private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
- try {
- IoFilter filter = entry.getFilter();
- NextFilter nextFilter = entry.getNextFilter();
- filter.messageReceived(nextFilter, session, message);
- } catch (Exception e) {
- fireExceptionCaught(e);
- } catch (Error e) {
- fireExceptionCaught(e);
- throw e;
- }
- }
- public void messageReceived(IoSession session, Object message) {
- Entry nextEntry = EntryImpl.this.nextEntry;
- callNextMessageReceived(nextEntry, session, message);
- }
接下来分析下write过程,如果我们想要给服务端发送消息内容的话,首先我们需要获取到IoSession对象,这里我们以NioSocketSession为例,发送消息调用的将是他的write方法,查看NioSocketSession发现他里面没有write方法,到他的父类NioSession查看也不存在,最后在AbstractIoSession找到啦;
AbstractIoSession$write()
- public WriteFuture write(Object message) {
- return write(message, null);
- }
- public WriteFuture write(Object message, SocketAddress remoteAddress) {
- if (message == null) {
- throw new IllegalArgumentException("Trying to write a null message : not allowed");
- }
- // We can't send a message to a connected session if we don't have
- // the remote address
- if (!getTransportMetadata().isConnectionless() && (remoteAddress != null)) {
- throw new UnsupportedOperationException();
- }
- // If the session has been closed or is closing, we can't either
- // send a message to the remote side. We generate a future
- // containing an exception.
- if (isClosing() || !isConnected()) {
- WriteFuture future = new DefaultWriteFuture(this);
- WriteRequest request = new DefaultWriteRequest(message, future, remoteAddress);
- WriteException writeException = new WriteToClosedSessionException(request);
- future.setException(writeException);
- return future;
- }
- FileChannel openedFileChannel = null;
- // TODO: remove this code as soon as we use InputStream
- // instead of Object for the message.
- try {
- if ((message instanceof IoBuffer) && !((IoBuffer) message).hasRemaining()) {
- // Nothing to write : probably an error in the user code
- throw new IllegalArgumentException("message is empty. Forgot to call flip()?");
- } else if (message instanceof FileChannel) {
- FileChannel fileChannel = (FileChannel) message;
- message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());
- } else if (message instanceof File) {
- File file = (File) message;
- openedFileChannel = new FileInputStream(file).getChannel();
- message = new FilenameFileRegion(file, openedFileChannel, 0, openedFileChannel.size());
- }
- } catch (IOException e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- return DefaultWriteFuture.newNotWrittenFuture(this, e);
- }
- // Now, we can write the message. First, create a future
- WriteFuture writeFuture = new DefaultWriteFuture(this);
- WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);
- // Then, get the chain and inject the WriteRequest into it
- IoFilterChain filterChain = getFilterChain();
- filterChain.fireFilterWrite(writeRequest);
- // TODO : This is not our business ! The caller has created a
- // FileChannel,
- // he has to close it !
- if (openedFileChannel != null) {
- // If we opened a FileChannel, it needs to be closed when the write
- // has completed
- final FileChannel finalChannel = openedFileChannel;
- writeFuture.addListener(new IoFutureListener<WriteFuture>() {
- public void operationComplete(WriteFuture future) {
- try {
- finalChannel.close();
- } catch (IOException e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- }
- }
- });
- }
- // Return the WriteFuture.
- return writeFuture;
- }
- public void fireFilterWrite(WriteRequest writeRequest) {
- callPreviousFilterWrite(tail, session, writeRequest);
- }
- private void callPreviousFilterWrite(Entry entry, IoSession session, WriteRequest writeRequest) {
- try {
- IoFilter filter = entry.getFilter();
- NextFilter nextFilter = entry.getNextFilter();
- filter.filterWrite(nextFilter, session, writeRequest);
- } catch (Exception e) {
- writeRequest.getFuture().setException(e);
- fireExceptionCaught(e);
- } catch (Error e) {
- writeRequest.getFuture().setException(e);
- fireExceptionCaught(e);
- throw e;
- }
- }
- @Override
- public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
- nextFilter.filterWrite(session, writeRequest);
- }
- 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);
- }
- }
- public void write(S session, WriteRequest writeRequest) {
- WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
- writeRequestQueue.offer(session, writeRequest);
- if (!session.isWriteSuspended()) {
- this.flush(session);
- }
- }
AbstractPollingIoProcessor$flush
- public final void flush(S session) {
- // add the session to the queue if it's not already
- // in the queue, then wake up the select()
- if (session.setScheduledForFlush(true)) {
- flushingSessions.add(session);
- wakeup();
- }
- }
至此,MINA中主要的服务端源码分析结束了,注意我们只分析了NioSocketAcceptor部分的源码,没有涉及NioSocketConnector部分,其实NioSocketConnector部分的源码和NioSocketAcceptor部分基本上是类似的分析过程,在这里我就不细细分析了,下一篇我会对MINA框架做一个小结,包括它里面涉及到的一些线程模型结构;