「java」从websocket服务器的启动分析netty3.10源码

**

1.首先是创建bootstrap对象

**
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
创建bootstrap对象的时候先创建一个频道工厂ChannelFactory,它会初始化boss线程和多个worker线程。

public NioServerSocketChannelFactory(
Executor bossExecutor, int bossCount, WorkerPool workerPool) {
this(new NioServerBossPool(bossExecutor, bossCount, null), workerPool);
}

worker线程的初始化方法在NioWorkerPool的构造函数调用

NioServerBossPool的初始化方法会创建NioWorker对象,每个worker对象都会创建一个死锁检测worker线程,worker对象的数量由用户定义

NioServerBoss构造方法会调用AbstractNioSelector.openSelector(determiner)方法打开多路复用器,同时调用DeadLockProofWorker.start()创建一个死锁检测worker线程,在这个线程中会通过用户设置的执行器executor跑NioWorker对象(它是个runable)。

NioServerBossPool的构造方法最后调用waitForWorkerThreads()方法等待所有的worker线程初始化完毕,这是通过闭锁来进行判断的,闭锁的完成条件是NioWorker对象的父方法run()运行起来后调用startupLatch.countDown()方法。

boss线程的初始化和worker差不多

**

2.绑定本地地址

**

public Channel bind(final SocketAddress localAddress) {
//bind的异步操作结果对象(里面会创建一个新的频道)
ChannelFuture future = bindAsync(localAddress);

//阻塞到绑定结束 Wait for the future.
future.awaitUninterruptibly();
if (!future.isSuccess()) {
    future.getChannel().close().awaitUninterruptibly();
    throw new ChannelException("Failed to bind to: " + localAddress, future.getCause());
}

return future.getChannel();

}

public ChannelFuture bindAsync(final SocketAddress localAddress) {
if (localAddress == null) {
throw new NullPointerException(“localAddress”);
}
//本质是一个频道处理器(专用于绑定频道到指定的本地地址)
Binder binder = new Binder(localAddress);//绑定者
//获取用户设置的父频道处理器
ChannelHandler parentHandler = getParentHandler();
//新建一个默认管道作为boss管道
ChannelPipeline bossPipeline = pipeline();
//添加绑定者到boss管道中
bossPipeline.addLast(“binder”, binder);
//用户设置了父频道处理器就加到boss管道中
if (parentHandler != null) {
bossPipeline.addLast(“userHandler”, parentHandler);
}

//通过用户设置的频道工厂创建一个持有boss管道的频道
Channel channel = getFactory().newChannel(bossPipeline);

//结果future
final ChannelFuture bfuture = new DefaultChannelFuture(channel, false);
//添加回调以得到结果
binder.bindFuture.addListener(new ChannelFutureListener() {
    public void operationComplete(ChannelFuture future) throws Exception {
        if (future.isSuccess()) {
            bfuture.setSuccess();
        } else {
            // Call close on bind failure
            bfuture.getChannel().close();
            bfuture.setFailure(future.getCause());
        }
    }
});
return bfuture;

}
在通过频道工厂NioServerSocketChannelFactory创建频道对象Channel的时候,NioServerSocketChannel的构造函数最后会调用fireChannelOpen(this)方法

public static void fireChannelOpen(Channel channel) {
// Notify the parent handler.
if (channel.getParent() != null) {
fireChildChannelStateChanged(channel.getParent(), channel);
}

channel.getPipeline().sendUpstream(
        new UpstreamChannelStateEvent(
                channel, ChannelState.OPEN, Boolean.TRUE));

}
可以看到在这里管道pipeline的sendUpstream()方法被调用,它会让管道持有的处理器handler对象顺着链表依次执行handleUpstream()方法。

而Binder是第一个注册的,所以它当然是第一个执行sendUpstream()方法(这是Binder父类SimpleChannelUpstreamHandler的方法)。最后会调用Binder的channelOpen()方法

private final class Binder extends SimpleChannelUpstreamHandler {

private final SocketAddress localAddress;
private final Map<String, Object> childOptions =
    new HashMap<String, Object>();
private final DefaultChannelFuture bindFuture = new DefaultChannelFuture(null, false);
Binder(SocketAddress localAddress) {
    this.localAddress = localAddress;
}

@Override
public void channelOpen(
        ChannelHandlerContext ctx,
        ChannelStateEvent evt) {

    try {
        evt.getChannel().getConfig().setPipelineFactory(getPipelineFactory());

        // Split options into two categories: parent and child.
        Map<String, Object> allOptions = getOptions();
        Map<String, Object> parentOptions = new HashMap<String, Object>();
        for (Entry<String, Object> e: allOptions.entrySet()) {
            if (e.getKey().startsWith("child.")) {
                childOptions.put(
                        e.getKey().substring(6),
                        e.getValue());
            } else if (!"pipelineFactory".equals(e.getKey())) {
                parentOptions.put(e.getKey(), e.getValue());
            }
        }

        // Apply parent options.
        evt.getChannel().getConfig().setOptions(parentOptions);
    } finally {
        //调用下一个handler的sendUpstream()方法
        ctx.sendUpstream(evt);
    }
    //调用频道Channel的bind()方法绑定本地地址
    evt.getChannel().bind(localAddress).addListener(new ChannelFutureListener() {
        public void operationComplete(ChannelFuture future) throws Exception {
            if (future.isSuccess()) {
                bindFuture.setSuccess();
            } else {
                bindFuture.setFailure(future.getCause());
            }
        }
    });
}

可以看到方法的结尾会调用频道Channel的bind()方法绑定本地地址。最后他会调用ChannelPipelin的sendDownStream()方法。

public void sendDownstream(ChannelEvent e) {
DefaultChannelHandlerContext tail = getActualDownstreamContext(this.tail);
if (tail == null) {
try {
getSink().eventSunk(this, e);
return;
} catch (Throwable t) {
notifyHandlerException(e, t);
return;
}
}

sendDownstream(tail, e);

}

如果有DownstreamHandler,它会让管道持有的处理器handler对象顺着链表依次执行handleDownstream()方法。而没有的时候就是执行ChannelSink的eventSunk()方法。这个sink是ChannelFactory创建channel创建的NioServerSocketPipelineSink。

public void eventSunk(
ChannelPipeline pipeline, ChannelEvent e) throws Exception {
Channel channel = e.getChannel();
if (channel instanceof NioServerSocketChannel) {
handleServerSocket(e);
} else if (channel instanceof NioSocketChannel) {
handleAcceptedSocket(e);
}
}

接着调用handleServerSocket()方法处理绑定地址事件BOUND

private static void handleServerSocket(ChannelEvent e) {
if (!(e instanceof ChannelStateEvent)) {
return;
}

ChannelStateEvent event = (ChannelStateEvent) e;
NioServerSocketChannel channel =
    (NioServerSocketChannel) event.getChannel();
ChannelFuture future = event.getFuture();
ChannelState state = event.getState();
Object value = event.getValue();

switch (state) {
case OPEN:
    if (Boolean.FALSE.equals(value)) {
        ((NioServerBoss) channel.boss).close(channel, future);
    }
    break;
case BOUND:
    if (value != null) {
        ((NioServerBoss) channel.boss).bind(channel, future, (SocketAddress) value);
    } else {
        ((NioServerBoss) channel.boss).close(channel, future);
    }
    break;
default:
    break;
}

}
最终调用到Boss的bind()方法,注册一个任务到boss对象的任务队列。这个任务会放到任务线程中进行处理。
void bind(final NioServerSocketChannel channel, final ChannelFuture future,
final SocketAddress localAddress) {
registerTask(new RegisterTask(channel, future, 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());
    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);
    }
}

}
可以看到它是通过nio的SelectableChannel绑定本地端口,有兴趣可以去了解下jdk的nio是怎么实现的。

public void run() {
boolean bound = false;
boolean registered = false;
try {
//通过nio的SelectableChannel绑定本地端口
channel.socket.socket().bind(localAddress, channel.getConfig().getBacklog());
bound = true;

    future.setSuccess();
    //绑定完本地地址后在发一个BOUND事件给上行处理器
    fireChannelBound(channel, channel.getLocalAddress());
    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);
    }
}

}
至此服务器基本启动完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值