Netty
1.Netty怎样切换三种经典的i/o模式
BIO 阻塞 排队打饭模式 JDK1.4 之前
NIO 非阻塞 点单等待被叫模式 JDK1.4 java.nio
AIO 异步 包厢模式 JDK1.7 回调
阻塞与非阻塞:是否等待数据就绪
同步与异步:数据就绪后谁来操作的问题 异步由服务方在数据完成后进行回调操作数据
Netty为什么仅保留了对NIO的支持
Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!
Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!
1.1怎么切换
1.2切换原理 泛型 反射 工厂
1.3服务器开发为什么不需要切换客户端对应的socket
什么是reactor及三种版本?
image.png
开发模式:
image.png
Reactor是一种开发模式,模式的核心流程:
注册时间--->监听(扫描)时间是否发生--->事件发生后进行相应的处理
image.png
image.png
image.png
image.png
image.png
image.png
netty如何支持主从reactor模式的?
EchoServer
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);//main reactor
EventLoopGroup workerGroup = new NioEventLoopGroup(); //sub reactor
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) //set main sub reactor
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(serverHandler);
}
});
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable
volatile EventLoopGroup group;
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);
ObjectUtil.checkNotNull(childGroup, "childGroup");
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = childGroup;
return this;
}
//绑定main group
ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) { .... }
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
}
ServerBootStrap
@Override
@SuppressWarnings("unchecked")
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
setAttributes(child, childAttrs);
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
两种socketChannel(ServerSocketChannel、SocketChannel) 绑定到两个不同的group
为什么说netty的main reactor大多并不能用到一个线程组,只能用线程组里的一个?
服务器地址绑定的时候调用一次
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
....
}
netty给channel分配NIO event loop的规则是什么?
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
因为数字在电脑中是以[补码]的形式存在的
比如
a = 10
仅以8位举例
正数
a 原码 0000 1010 [补码]与原码相等 0000 1010
负数 补码为 它绝对值的[反码]最后+1
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
@Override
public EventExecutor next() {
// 递增 取模 取正值
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
通用模式的NIO实现多路复用器是怎么跨平台的?
JDK
什么是粘包和半包?常用解决方法、Netty对三种常用封帧方式的支持
粘包:一个包发送多个消息。 半包:消息被拆分多个包发送。
粘包的主要原因:发送方每次写入数据小于套接字缓冲区大小;读取数据不够及时
半包:发送方数据大于套接字大小;发送数据大于协议MTU时,必须拆包
根本原因:TCP是一个流式协议,消息没有边界。UDP就没有这个问题。
20191016200816.png image.png
解码的核心工作流程是什么?
channelRead(... ...)
解码中两种数据积累器(cumulator)的区别?
内存复制与组合
三种解码器的常用额外控制参数有哪些?
以上解码器(ByteToMeaageDecoder)主要是为了解决粘包与半包问题,得到一个正确的字节数组;
二次解码器(MessageToMessageDecoder)(序列化与反序列化相关)
keepalive与idle检测
为什么需要keepalive、怎样设计keepalive、为什么还需要应用层keepalive、idle检测是什么、netty如何开启keepalive与idle检测
image.png image.png
为什么需要应用层keepalive
image.png
image.png image.png
image.png
image.png
image.png