[MINA2.0源码](四)客户端完成建立连接

一、NioSocketConnector发起连接后,在其父类AbstractPollingIoConnector的多线程内部类Connector中,会监听通道上的OP_CONNECT事件:int selected=select(timeOut);服务端完成连接后,这里往下执行

if (selected > 0) {
    nHandles -= processConnections(selectedHandles());
}

processConnections处理事件。

private int processConnections(Iterator<H> handlers) {
    int nHandles = 0;

    // Loop on each connection request
    while (handlers.hasNext()) {
        H handle = handlers.next();
        handlers.remove();

        ConnectionRequest connectionRequest = getConnectionRequest(handle);

        if (connectionRequest == null) {
            continue;
        }

        boolean success = false;
        try {
            if (finishConnect(handle)) {
                T session = newSession(processor, handle);
                initSession(session, connectionRequest, connectionRequest.getSessionInitializer());
                // Forward the remaining process to the IoProcessor.
                session.getProcessor().add(session);
                nHandles++;
            }
            success = true;
        } catch (Throwable e) {
            connectionRequest.setException(e);
        } finally {
            if (!success) {
                // The connection failed, we have to cancel it.
                cancelQueue.offer(connectionRequest);
            }
        }
    }
    return nHandles;
}

1、finishConnect(handle)在NioSocketConnector

protected boolean finishConnect(SocketChannel handle) throws Exception {
  if (handle.finishConnect()) {
    SelectionKey key = handle.keyFor(selector);
				
    if (key != null) {
      key.cancel();
    }
				
    return true;
  }
				
  return false;
}

SocketChannel.finishConnect()阻塞着完成channel的连接。接下来初始化session的内容和服务端初始化Session是一样的。

2、T session = newSession(processor, handle);封装一个NioSocketSession
3、initSession(session, future, sessionInitializer);设置session的参数
4、session.getProcessor().add(session);AbstractPollingIoProcessor内部类Processor.run()。

private int handleNewSessions() {
  int addedSessions = 0;
				
  for (S session = newSessions.poll(); session != null; session = newSessions.poll()) {
    if (addNow(session)) {
    // A new session has been created
    addedSessions++;
    }
  }
				
  return addedSessions;
}

AbstractPollingIoProcessor.addNow():

private boolean addNow(S session) {
  boolean registered = false;
				
  try {
    init(session);
    registered = true;
				
    // Build the filter chain of this session.
    IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
    chainBuilder.buildFilterChain(session.getFilterChain());
				
    // DefaultIoFilterChain.CONNECT_FUTURE is cleared inside here
    // in AbstractIoFilterChain.fireSessionOpened().
    // Propagate the SESSION_CREATED event up to the chain
    IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
    listeners.fireSessionCreated(session);
  } catch (Throwable e) {
    ExceptionMonitor.getInstance().exceptionCaught(e);
				
    try {
      destroy(session);
    } catch (Exception e1) {
      ExceptionMonitor.getInstance().exceptionCaught(e1);
    } finally {
      registered = false;
    }
  }
				
  return registered;
}

listeners.fireSessionCreated(session);IoServiceListenerSupport类

public void fireSessionCreated(IoSession session) {
    boolean firstSession = false;

    if (session.getService() instanceof IoConnector) {
        synchronized (managedSessions) {
            firstSession = managedSessions.isEmpty();
        }
    }

    // If already registered, ignore.
    if (managedSessions.putIfAbsent(session.getId(), session) != null) {
        return;
    }

    // If the first connector session, fire a virtual service activation event.
    if (firstSession) {
        fireServiceActivated();
    }

    // Fire session events.
    IoFilterChain filterChain = session.getFilterChain();
    filterChain.fireSessionCreated();
    filterChain.fireSessionOpened();

    int managedSessionCount = managedSessions.size();

    if (managedSessionCount > largestManagedSessionCount) {
        largestManagedSessionCount = managedSessionCount;
    }

    cumulativeManagedSessionCount++;

    // Fire listener events.
    for (IoServiceListener l : listeners) {
        try {
            l.sessionCreated(session);
        } catch (Throwable e) {
            ExceptionMonitor.getInstance().exceptionCaught(e);
        }
    }
}

filterChain.fireSessionCreated();DefaultIoFilterChain类

public void fireSessionCreated() {
    Entry head = this.head;
    callNextSessionCreated(head, session);
}

DefaultIoFilterChain.callNextSessionCreated():遍历过滤器链的sessionCreated方法

private void callNextSessionCreated(Entry entry, IoSession session) {
    try {
        IoFilter filter = entry.getFilter();
        NextFilter nextFilter = entry.getNextFilter();
        filter.sessionCreated(nextFilter, session);
    } catch (Throwable e) {
        fireExceptionCaught(e);
    }
}

最终会执行到内置末位过滤器TailFilter.sessionCreated():

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);
        }
    }
}

session.getHandler().sessionCreated(session);此方法是调用业务类handler.sessionCreated方法,一些初始化的内容可以再此方法中实现。
future.setSession(session);DefaultConnectFuture类:

public void setSession(IoSession session) {
  if (session == null) {
    throw new IllegalArgumentException("session");
  }
  setValue(session);
}

setValue():

public void setValue(Object newValue) {
   synchronized (lock) {
     // Allow only once.
     if (ready) {
       return;
     }
				
     result = newValue;
     ready = true;
     if (waiters > 0) {
       lock.notifyAll();
     }
   }
				
   notifyListeners();
}

将ready值设为true。这个值与接下来的一步有关。

二、future.awaitUninterruptibly();这使程序阻塞等待连接的建立后再执行之后的的session = future.getSession();
从上一步可以知道,客户端发起connect后需要等服务端响应请求已建立了,才会接着初始化session等,
而在channel上等待OP_CONNECT事件是在AbstractPollingIoConnector类的多线程内部类Connector中执行。
意味着Connector在监听,例子中的代码还并发着往下执行。所以就用这个方法将业务代码兜住。
直到连接建立,session初始化完成,用于判断是否完成的开关就是上一步的DefaultConnectFuture

父类DefaultIoFuture.ready的这个字段。

future.awaitUninterruptibly();DefaultConnectFuture类

public IoFuture awaitUninterruptibly() {
    try {
        await0(Long.MAX_VALUE, false);
    } catch (InterruptedException ie) {
        // Do nothing : this catch is just mandatory by contract
    }

    return this;
}

await0()

private boolean await0(long timeoutMillis, boolean interruptable) throws InterruptedException {
    long endTime = System.currentTimeMillis() + timeoutMillis;

    if (endTime < 0) {
        endTime = Long.MAX_VALUE;
    }

    synchronized (lock) {
        if (ready) {
            return ready;
        } else if (timeoutMillis <= 0) {
            return ready;
        }

        waiters++;

        try {
            for (;;) {
                try {
                    long timeOut = Math.min(timeoutMillis, DEAD_LOCK_CHECK_INTERVAL);
                    lock.wait(timeOut);
                } catch (InterruptedException e) {
                    if (interruptable) {
                        throw e;
                    }
                }

                if (ready) {
                    return true;
                }

                if (endTime < System.currentTimeMillis()) {
                    return ready;
                }
            }
        } finally {
            waiters--;
            if (!ready) {
                checkDeadLock();
            }
        }
    }
}

synchronized (lock)和wait()方法配合同步修改ready的开关。这个lock就是DefaultIoFuture对象,在其初始化是设值的。

public DefaultIoFuture(IoSession session) {
    this.session = session;
    this.lock = this;
}

lock.wait(timeOut);方法是这个线程wait一段时间,并暂时释放lock对象即DefaultIoFuture对象。
让DefaultConnectFuture.setValue()方法,在session初始化完成后被调用时,有机会对ready开关进行同步修改,将其标记为true。使得await0()下次再判断ready时即可返回,让业务接着执行future.getSession()。
客户端和服务端建立连接的过程何其相似。服务端启动后绑定OP_ACCEPT,监听客户端建立连接的请求。
客户端发送建立连接的请求后绑定OP_CONNECT,监听服务端完成建立连接的请求。
而双方在收到消息后都会交由NioProcessor建立session,绑定OP_READ,并监听通道上对方传过来的数据。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值