package org.jboss.netty.channel.socket.nio;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.util.ThreadNameDeterminer;
import org.jboss.netty.util.ThreadRenamingRunnable;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Executor;
import static org.jboss.netty.channel.Channels.*;
/**
* �������ר�Ŵ�������������һ��Excutor���й���
* Boss implementation which handles accepting of new connections
*/
public final class NioServerBoss extends AbstractNioSelector implements Boss {
NioServerBoss(Executor bossExecutor) {
super(bossExecutor);
}
NioServerBoss(Executor bossExecutor, ThreadNameDeterminer determiner) {
super(bossExecutor, determiner);
}
void bind(final NioServerSocketChannel channel, final ChannelFuture future,
final SocketAddress localAddress) {
// ���������������
registerTask(new RegisterTask(channel, future, localAddress));
}
@Override
protected void close(SelectionKey k) {
NioServerSocketChannel ch = (NioServerSocketChannel) k.attachment();
close(ch, succeededFuture(ch));
}
void close(NioServerSocketChannel channel, ChannelFuture future) {
boolean bound = channel.isBound();
try {
channel.socket.close();
// ������Щȡ���� SelectionKey��������������
increaseCancelledKeys();
if (channel.setClosed()) {
future.setSuccess();
if (bound) {
fireChannelUnbound(channel);
}
fireChannelClosed(channel);
} else {
future.setSuccess();
}
} catch (Throwable t) {
future.setFailure(t);
fireExceptionCaught(channel, t);
}
}
/**
* ����Ҫ������AbstractNioSelector��run��������á�
*/
@Override
protected void process(Selector selector) {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
return;
}
for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
SelectionKey k = i.next();
i.remove(); //
// �õ���������ͨ��
NioServerSocketChannel channel = (NioServerSocketChannel) k.attachment();
try {
// accept connections in a for loop until no new connection is ready
for (;;) {
SocketChannel acceptedSocket = channel.socket.accept();
// ������ģʽ
if (acceptedSocket == null) {
break;
}
// ����������ĵ�������ô�ͷַ���worker����
registerAcceptedChannel(channel, acceptedSocket, thread);
}
} catch (CancelledKeyException e) {
// Raised by accept() when the server socket was closed.
k.cancel();
channel.close();
} catch (SocketTimeoutException e) {
// Thrown every second to get ClosedChannelException
// raised.
} catch (ClosedChannelException e) {
// Closed as requested.
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn( "Failed to accept a connection.", t);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// Ignore
}
}
}
}
/**
* ������������ַַ���һ��worker������
*/
private static void registerAcceptedChannel(NioServerSocketChannel parent, SocketChannel acceptedSocket,
Thread currentThread) {
try {
ChannelSink sink = parent.getPipeline().getSink();
ChannelPipeline pipeline = parent.getConfig().getPipelineFactory().getPipeline();
//����һ���߳��������������ͨ�� acceptedSocket
NioWorker worker = parent.workerPool.nextWorker();
worker.register(new NioAcceptedSocketChannel(
parent.getFactory(), pipeline, parent, sink
, acceptedSocket,
worker, currentThread), null);
} catch (Exception e) {
if (logger.isWarnEnabled()) {
logger.warn( "Failed to initialize an accepted socket.", e);
}
try {
acceptedSocket.close();
} catch (IOException e2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to close a partially accepted socket.",e2);
}
}
}
}
@Override
protected int select(Selector selector) throws IOException {
// Just do a blocking select without any timeout
// as this thread does not execute anything else.
return selector.select();
}
/**
* ����Ĵ���ÿ��boss ����
*/
@Override
protected ThreadRenamingRunnable newThreadRenamingRunnable(int id, ThreadNameDeterminer determiner) {
return new ThreadRenamingRunnable(this,
"New I/O server boss #" + id, determiner);
}
@Override
protected Runnable createRegisterTask(Channel channel, ChannelFuture future) {
return new RegisterTask((NioServerSocketChannel) channel, future, null);
}
private final class RegisterTask implements Runnable {
private final NioServerSocketChannel channel;
private final ChannelFuture future;
private final SocketAddress localAddress;
public RegisterTask(final NioServerSocketChannel channel, final ChannelFuture future,
final SocketAddress localAddress) {
this.channel = channel;
this.future = future;
this.localAddress = localAddress;
}
public void run() {
boolean bound = false;
boolean registered = false;
try {
//��ײ�İ���
channel.socket.socket().bind(localAddress, channel.getConfig().getBacklog());
bound = true;
future.setSuccess();
fireChannelBound(channel, channel.getLocalAddress());
// �����socket����Selector������ע�IJ�������������ĵ����Ϊ���Ǽ�������
channel.socket.register(selector, SelectionKey.OP_ACCEPT, channel);
registered = true;
} catch (Throwable t) {
future.setFailure(t);
fireExceptionCaught(channel, t);
} finally {
if (!registered && bound) {
close(channel, future);
}
}
}
}
}