mina研究一
Apache Mina IoAcceptor与IoConnector简介
Apache mina是一个介于应用程序与网络之间的NIO框架,它使程序员从繁琐的网络操作中解脱出来,花更多的时间在业务处理上。
如下图所示,mina分为三层
1、IOService层:处理IO操作
2、IOFilter层:过滤器链,日志处理、字节变换、对象转换等操作
3、IOHandler层:真正的处理业务逻辑的地方
IOService层根据不同的角色又分为IOAcceptor和IOConnector,分别用于接受连接与请求连接操作。
IOAcceptor
上图是IOAcceptor的类图,IOAcceptor相当于是对ServerSocketChannel的封装,最重要的两个操作是绑定与接受连接,IOService接口中有多个重载的bind方法
- public interface IoAcceptor extends IoService {
- void bind() throws IOException;
- void bind(SocketAddress localAddress) throws IOException;
- void bind(SocketAddress firstLocalAddress, SocketAddress... addresses) throws IOException;
- void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException;
- }
- protected final Set<SocketAddress> bindInternal(
- List<? extends SocketAddress> localAddresses) throws Exception {
- // Create a bind request as a Future operation. When the selector
- // have handled the registration, it will signal this future.
- AcceptorOperationFuture request = new AcceptorOperationFuture(
- localAddresses);
- // adds the Registration request to the queue for the Workers
- // to handle
- registerQueue.add(request);
- // creates the Acceptor instance and has the local
- // executor kick it off.
- startupAcceptor();
- // As we just started the acceptor, we have to unblock the select()
- // in order to process the bind request we just have added to the
- // registerQueue.
- wakeup();
- // Now, we wait until this request is completed.
- request.awaitUninterruptibly();
- if (request.getException() != null) {
- throw request.getException();
- }
- // Update the local addresses.
- // setLocalAddresses() shouldn't be called from the worker thread
- // because of deadlock.
- Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
- for (H handle:boundHandles.values()) {
- newLocalAddresses.add(localAddress(handle));
- }
- return newLocalAddresses;
- }
主要干了以下几件事情:
1、将绑定请求放入registerQueue中
2、启动Acceptor,从Acceptor类的run方法可以看到,这一步会阻塞在Acceptor选择器的选择操作中
3、调用wakeup让选择器返回
4、等待请求处理完成,这一步会阻塞在ready变量中,当ready变量为true时才会返回,当接受连接后ready会被设置为true.
现在重点看一下Acceptor的run方法
- public void run() {
- ......
- while (selectable) {
- try {
- int selected = select();
- nHandles += registerHandles();
- if (nHandles == 0) {
- acceptorRef.set(null);
- if (registerQueue.isEmpty() && cancelQueue.isEmpty()) {
- assert (acceptorRef.get() != this);
- break;
- }
- if (!acceptorRef.compareAndSet(null, this)) {
- assert (acceptorRef.get() != this);
- break;
- }
- assert (acceptorRef.get() == this);
- }
- if (selected > 0) {
- processHandles(selectedHandles());
- }
- // check to see if any cancellation request has been made.
- nHandles -= unregisterHandles();
- } catch (...) {
- ...
- }
- // Cleanup all the processors, and shutdown the acceptor. set ready=true
- }
- protected ServerSocketChannel open(SocketAddress localAddress)
- throws Exception {
- // Creates the listening ServerSocket
- ServerSocketChannel channel = ServerSocketChannel.open();
- boolean success = false;
- try {
- // This is a non blocking socket channel
- channel.configureBlocking(false);
- // Configure the server socket,
- ServerSocket socket = channel.socket();
- // Set the reuseAddress flag accordingly with the setting
- socket.setReuseAddress(isReuseAddress());
- // and bind.
- socket.bind(localAddress, getBacklog());
- // Register the channel within the selector for ACCEPT event
- channel.register(selector, SelectionKey.OP_ACCEPT);
- success = true;
- } finally {
- if (!success) {
- close(channel);
- }
- }
- return channel;
- }
(2)、从(1)中可以知道selector上注册了ServerSocketChannel的OP_ACCEPT键,注册后nHandles==0,selected==0,进行下一次循环,同样是阻塞在select方法上
(3)、当连接到来时,select方法返回,selected>0,执行processHandles方法
- private void processHandles(Iterator<H> handles) throws Exception {
- while (handles.hasNext()) {
- H handle = handles.next();
- handles.remove();
- // Associates a new created connection to a processor,
- // and get back a session
- S session = accept(processor, handle);
- if (session == null) {
- break;
- }
- initSession(session, null, null);
- // add the session to the SocketIoProcessor
- session.getProcessor().add(session);
- }
- }
- protected void init(NioSession session) throws Exception {
- SelectableChannel ch = (SelectableChannel) session.getChannel();
- ch.configureBlocking(false);
- session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ,
- session));
- }
整个Acceptor的实现就讲解完了,总结一下:Acceptor线程专门负责接受连接,在其上有一个selector,轮询是否有连接建立上来,当有连接建立上来,调用ServerSocketChannel.accept方法来接受连接,这个方法返回一个session对象,然后将这个session对象加入processor中,由processor遍历每个session来完成真正的IO操作。processor上也有一个selector与一个Processor线程,selector用于轮询session,Processor线程处理每个session的IO操作。
IOConnector
IOConnector的类图如下:
IOConnector的设计与IOAcceptor几乎完全一样,唯一不同的是与Acceptor线程对应的是Connector线程,在完成连接操作后也是扔了一个session对象到Processor中。
关于Processor与Session后续再分析......