上一篇文章分析到Acceptor中的processHandles,该函数是处理客户端请求的核心函数,定义在Acceptor中,
private void processHandles(Iterator<H> handles) throws Exception {
while (handles.hasNext()) {
H handle = handles.next();
handles.remove();
S session = accept(processor, handle);
if (session == null) {
continue;
}
initSession(session, null, null);
session.getProcessor().add(session);
}
}
accept用于构造一个Session,定义在NioSocketAcceptor中,传入的参数processor是前面在构造函数中构造的SimpleIoProcessorPool,handle就是ServerSocketChannel,
protected NioSession accept(IoProcessor<NioSession> processor, ServerSocketChannel handle) throws Exception {
SocketChannel ch = handle.accept();
return new NioSocketSession(this, processor, ch);
}
这里就是获取客户端的连接SocketChannel,然后构造一个NioSocketSession,该构造函数就是简单的赋值,这里不往下看了,重点是在构造NioSocketSession时,创建了一个DefaultIoFilterChain,后面要重点用到这个Filter链。
回到processHandles,接下来调用initSession进行初始化,然后注册该NioSocketSession。这里getProcessor返回前面创建的SimpleIoProcessorPool,其add函数如下
public final void add(S session) {
getProcessor(session).add(session);
}
这里的getProcessor返回前面在SimpleIoProcessorPool构造函数中创建的NIOProcessor,然后调用其add函数,
public final void add(S session) {
newSessions.add(session);
startupProcessor();
}
这里首先将前面创建的NioSocketSession添加进newSessions中,然后调用startupProcessor开始处理。
startupProcessor定义在AbstractPollingIoProcessor中,
private void startupProcessor() {
Processor processor = processorRef.get();
if (processor == null) {
processor = new Processor();
if (processorRef.compareAndSet(null, processor)) {
executor.execute(new NamePreservingRunnable(processor, threadName));
}
}
}
这里就是尝试获取一个Processor,如果没有,就创建一个新的Processor线程,用于处理刚刚的NioSocketSession,因此下面开始分析Processor的run函数,
public void run() {
int nSessions = 0;
lastIdleCheckTime = System.currentTimeMillis();
for (;;) {
try {
long t0 = System.currentTimeMillis();
int selected = select(SELECT_TIMEOUT);
long t1 = System.currentTimeMillis();
long delta = (t1 - t0);
if ((selected == 0) && !wakeupCalled.get() && (delta < 100)) {
if (isBrokenConnection()) {
wakeupCalled.getAndSet(false);
continue;
} else {
registerNewSelector();
}
wakeupCalled.getAndSet(false);
continue;
}
nSessions += handleNewSessions();
updateTrafficMask();
if (selected > 0) {
process();
}
long currentTime = System.currentTimeMillis();
flush(currentTime);
nSessions -= removeSessions();
notifyIdleSessions(currentTime);
if (nSessions == 0) {
processorRef.set(null);
if (newSessions.isEmpty() && isSelectorEmpty()) {
break;
}
if (!processorRef.compareAndSet(null, this)) {
break;
}
}
if (isDisposing()) {
for (Iterator<S> i = allSessions(); i.hasNext();) {
scheduleRemove(i.next());
}
wakeup();
}
} catch (Exception e) {
}
}
}
每个NIOProcessor会重新构造一个Selector,第一次执行该函数时,由于selected =0,delta<100(无事件),但是由于wakeupCalled被初始化为true,因此直接执行到handleNewSessions。handleNewSessions添加需要处理的Session,然后调用process进行处理,处理完毕后调用flush向客户端发送数据,接着调用removeSessions移除相应的Session,最后调用notifyIdleSessions处理Idle状态的Session,下面重点分析handleNewSessions、flush和removeSessions三个函数,其余的函数可以参照源码自行分析。
handleNewSessions定义在AbstractPollingIoProcessor中,
private int handleNewSessions() {
int addedSessions = 0;
for (S session = newSessions.poll(); session != null; session = newSessions.poll()) {
if (addNow(session)) {
addedSessions++;
}
}
return addedSessions;
}
该函数从newSessions获取注册的NioSocketSession,然后调用addNow将该NioSocketSession注册到Selector中。addNow定义在AbstractPollingIoProcessor中,
private boolean addNow(S session) {
boolean registered = false;
try {
init(session);
registered = true;
IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
chainBuilder.buildFilterChain(session.getFilterChain());
IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
listeners.fireSessionCreated(session);
} catch (Exception e) {
}
return registered;
}
init定义在NIOProcessor中,该函数的主要作用就是往Selector中注册OP_READ事件。
protected void init(NioSession session) throws Exception {
SelectableChannel ch = (SelectableChannel) session.getChannel();
ch.configureBlocking(false);
session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
}
session.getService()返回NioSocketAcceptor,查看上一章的构造函数,可以知道,这里getFilterChainBuilder返回的是DefaultIoFilterChainBuilder(在AbstractIoService类中),而session.getFilterChain()返回的是DefaultIoFilterChain(在NioSession构造函数中),因此下面看DefaultIoFilterChainBuilder的buildFilterChain函数,
public void buildFilterChain(IoFilterChain chain) throws Exception {
for (Entry e : entries) {
chain.addLast(e.getName(), e.getFilter());
}
}
这里就不往下看了,简而言之就是构造一个监听器的链表。
回到run函数中,接下来执行updateTrafficMask,定义在AbstractPollingIoProcessor中,该函数的作用就是重新更新Selector监听的事件,例如当用户不需要读数据时,就将读事件OP_READ从Selector中删除,以减少Selector监听的事件数量。再往下就是调用process处理事件了,该函数放在下一章分析。再接下来的flush用于发送数据,
flush定义在AbstractPollingIoProcessor中,
private void flush(long currentTime) {
do {
S session = flushingSessions.poll();
if (session == null) {
break;
}
session.unscheduledForFlush();
SessionState state = getState(session);
switch (state) {
case OPENED:
try {
boolean flushedAll = flushNow(session, currentTime);
if (flushedAll && !session.getWriteRequestQueue().isEmpty(session)
&& !session.isScheduledForFlush()) {
scheduleFlush(session);
}
} catch (Exception e) {
}
break;
case CLOSING:
break;
case OPENING:
scheduleFlush(session);
return;
default:
throw new IllegalStateException(String.valueOf(state));
}
} while (!flushingSessions.isEmpty());
}
flushingSessions中保存了需要发送数据的Session,该函数首先依次从flushingSessions取出NioSocketSession,然后调用unscheduledForFlush设置其scheduledForFlush标志位,表是是否允许flush,接着调用getState获取该Session的状态,这里首先假设该Session处于OPENED状态,则调用flushNow,
flushNow定义在AbstractPollingIoProcessor中,
private boolean flushNow(S session, long currentTime) {
final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();
final WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
final int maxWrittenBytes = session.getConfig().getMaxReadBufferSize()
+ (session.getConfig().getMaxReadBufferSize() >>> 1);
int writtenBytes = 0;
WriteRequest req = null;
try {
setInterestedInWrite(session, false);
do {
req = session.getCurrentWriteRequest();
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()) {
writtenBytes += localWrittenBytes;
setInterestedInWrite(session, true);
return false;
}
} else if (message instanceof FileRegion) {
localWrittenBytes = writeFile(session, req, hasFragmentation, maxWrittenBytes - writtenBytes,
currentTime);
if ((localWrittenBytes > 0) && (((FileRegion) message).getRemainingBytes() > 0)) {
writtenBytes += localWrittenBytes;
setInterestedInWrite(session, true);
return false;
}
} else {
}
if (localWrittenBytes == 0) {
setInterestedInWrite(session, true);
return false;
}
writtenBytes += localWrittenBytes;
if (writtenBytes >= maxWrittenBytes) {
scheduleFlush(session);
return false;
}
if (message instanceof IoBuffer) {
((IoBuffer) message).free();
}
} while (writtenBytes < maxWrittenBytes);
} catch (Exception e) {
}
return true;
}
首先获得hasFragmentation用于判断传输的数据是否可分割,然后设置本次传输的最大字节数maxWrittenBytes为读缓存最大字节数的1.5倍,然后调用setInterestedInWrite暂时关闭NIO中的写监听事件,暂停写(因为现在要往缓存中写入数据了),再接着从WriteRequest(req)中获取需要写入的数据,然后判断该数据是普通的数据还是文件,如果是普通数据,则调用writeBuffer执行写操作,如果是文件,则调用writeFile,这两个函数都返回写入的字节数,用于判断是否可写,如果数据全部写入,则调用free释放该缓存。writeBuffer和writeFile就不往下看代码了,简单来说就是获得NIO中的Channel,然后把数据写到Channel中,可以查看网上很多关于NIO的资料。
回到flush函数中,后面的if的意思是,如果写缓存中还有空间并且还有数据需要写入,则调用scheduleFlush继续讲Session中的数据填入写缓存中。
往上回到run函数中,由于处理完了相应的事件,并且把需要发送的数据添加进缓存中,接下来就调用removeSessions移除需要移除的Session,定义在AbstractPollingIoProcessor中,
private int removeSessions() {
int removedSessions = 0;
for (S session = removingSessions.poll(); session != null; session = removingSessions.poll()) {
SessionState state = getState(session);
switch (state) {
case OPENED:
if (removeNow(session)) {
removedSessions++;
}
break;
case CLOSING:
break;
case OPENING:
newSessions.remove(session);
if (removeNow(session)) {
removedSessions++;
}
break;
default:
throw new IllegalStateException(String.valueOf(state));
}
}
return removedSessions;
}
需要移除的Session会保存在removingSessions中,这里依次取出该NioSocketSession,然后判断状态,调用removeNow移除该Session,这里就不往下看了。
到这里,processHandles函数就分析完了,下一章将会重点分析process函数,该函数是处理客户端请求的主要函数。