Netty服务端
package com.demo.study.socket.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class EchoServer {
public static void main(String[] args) throws Exception {
Integer PORT = 8088;
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new EchoServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
//阻塞主线程,直到网络服务被关闭
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
NioEventLoopGroup的创建
MultithreadEventExecutorGroup
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
//创建步骤1--线程创建器
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//创建步骤2--构造NioEventLoop
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
//创建步骤3--线程选择器
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
主要做了三件事:
- new ThreadPerTaskExecutor()[线程创建器]
- 每次执行任务时都会创建一个线程实体
- NioEventLoop线程命名规则nioEventLoop-1-xx
- for(){newChild()} [构造NioEventLoop]
- 保存线程执行器ThreadPerTaskExecutor
- 创建一个MpscQueue
- 创建一个selector
- chooserFactory.newChooser() [线程选择器]
- isPowerOfTwo() -- 判断是不是2的次幂
- 是--执行PowerOfTwoEventExecutorChooser(优化);index++ & (length-1)
- 否--执行GenericEventExecutorChooser(普通); abs(index++ % (length)
NioEventLoop的启动
通过 ServerBootstrap的bind方法。
- AbstractBootstrap的bind方法
- initAndRegister() //初始化ServerSocketChannel对象,并注册到Selector中
- doBind0()//ip端口绑定
initAndRegister方法:
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();//创建通道
init(channel);
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
ChannelFuture regFuture = config().group().register(channel);//注册通道
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
// i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
// added to the event loop's task queue for later execution.
// i.e. It's safe to attempt bind() or connect() now:
// because bind() or connect() will be executed *after* the scheduled registration task is executed
// because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}
注释:ChannelFuture regFuture = config().group().register(channel);其实调用的是NioEventLoopGroup 的register方法,这里的channel 就是NioServerSocketChannel。(服务端注册的channel)
查看NioEventLoopGroup的register 方法:在其父类 MultithreadEventLoopGroup中找到了register 方法。
@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
next()方法,其实返回的就是NioEventLoop
@Override
public EventLoop next() {
return (EventLoop) super.next();
}
向上找:
public interface EventExecutorChooserFactory {
/**
* Returns a new {@link EventExecutorChooser}.
*/
EventExecutorChooser newChooser(EventExecutor[] executors);
/**
* Chooses the next {@link EventExecutor} to use.
*/
@UnstableApi
interface EventExecutorChooser {
/**
* Returns the new {@link EventExecutor} to use.
*/
EventExecutor next();
}
}
查看这个方法的实现类: DefaultEventExecutorChooserFactory类中的 PowerOfTwoEventExecutorChooser 和 GenericEventExecutorChooser 其实就是在NioEventLoopGroup中选择一个合适的NioEventLoop进行注册。(注册到SingleThreadEventLoop)
调用next()方法获取到了NioEventLoop之后再次调用register 方法,因为是NioEventLoop对象调用的,所以我们去NioEventLoop类中找 register 方法,结果在他的父类SingleThreadEventLoop中找到了register 方法,调用的是下面的方法:
@Override
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
unsafe方法:因为这个channel就是NioServerSocketChannel,所以去这个类找unsafe方法,结果在NioServerSocketChannel类的父类 AbstractNioChannel找到了该方法。
@Override
public NioUnsafe unsafe() {
return (NioUnsafe) super.unsafe();
}
向上找,在父类 AbstractChannel找到了
@Override
public Unsafe unsafe() {
return unsafe;
}
在这个类的构造方法中:调用了newUnsafe方法
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
protected abstract AbstractUnsafe newUnsafe();
这个抽象方法有很多实现类,回到之前,因为是NioServerSocketChannel调用了unsafe方法 ,所以去NioServerSocketChannel找该方法,如果没有,逐级向上找newUnsafe方法,结果在NioServerSocketChannel的父类 AbstractNioMessageChannel中找到该方法,其实是 unsafe 就是 NioMessageUnsafe的对象。
@Override
protected AbstractNioUnsafe newUnsafe() {
return new NioMessageUnsafe();
}
所以就是NioMessageUnsafe这个类的对象调用了register 方法,在这个类中找。在他的父类 AbstractUnsafe找到了register的具体实现。
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "eventLoop");
if (isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
if (!isCompatible(eventLoop)) {
promise.setFailure(
new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
}
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
logger.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
主要调用了register0方法, register0方法主要调用了doRegister方法。(将Channel 和NioEventLoop里面的Selector进行绑定)
protected void doRegister() throws Exception {
// NOOP
}
找它的实现类:在 AbstractNioChannel中。
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);//将java中的ServerSocketChannel注册到EventLoop中的Selector
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
至此为止,注册完成。
doBind0方法
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
它的实现类是: AbstractChannel类的bind办法
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
绑定完毕。