那,我们就从 Echo 与 Http 开始,入门 Netty 吧! 首先,我的韩国欧巴把我放在 https://netty.io 上,如果要见我那你得去下载页面找到我,然后把我配置到 项目 中。不然你用 Maven 帮助你把我从另外一个地方出来帮你也行,别忘了我的版本号是3个点。 二话不说,先来个我需要的几个小家伙的介绍: 如果要搞个自定义协议的服务器端,要知道这几个 Bigman ,大人物 skr,skr,skr。
- EventLoopGroup:任务分组,最多可以使用两组(是的,你没看错)
- ServerBootstrap:Server 运作组织类,指挥部
- SocketChannel:工作频道
- ChannelHandler/ChannelInboundHandler:提供各种事件处理
- group():指定 事件循环 组
- channel():指定 SocketChannel 类
- handler:也是指定事件(对于 第一个 EventLoopGroup)
- childHandler:指定事件处理
- option():链接选项
- childOption():链接选项
package com.codimiracle.practice;Handler 代码:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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 {
private int port;
private EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) {
EchoServer server = new EchoServer(3400);
server.start();
}
private void start() {
NioEventLoopGroup majorEventLoopGroup = new NioEventLoopGroup();
NioEventLoopGroup seniorEventLoopGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
try {
serverBootstrap
.group(majorEventLoopGroup, seniorEventLoopGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new LoggingHandler(LogLevel.INFO))
.addLast(new EchoService());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture channelFuture = serverBootstrap.bind(this.port).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
majorEventLoopGroup.shutdownGracefully();
seniorEventLoopGroup.shutdownGracefully();
}
}
}
package com.codimiracle.practice;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class EchoService extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 内部缓存写入
ctx.write(msg);
// 把缓存发出
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
- EventLoopGroup:任务分组,最多一个
- Bootstrap:连长
- SocketChannel:是的还是它
- ChannelHandler/ChannelInboundHandler:没错,也是它
package com.codimiracle.practice;Client Handler 代码:
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class EchoClient {
private String host;
private int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void connect() {
NioEventLoopGroup clientEventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap
.group(clientEventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new LoggingHandler(LogLevel.INFO))
.addLast(new EchoServiceProxy());
}
});
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
clientEventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
EchoClient client = new EchoClient("localhost", 3400);
client.connect();
}
}
package com.codimiracle.practice;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class EchoServiceProxy extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello world\n".getBytes()));
}
}
我的三个模式
排队打饭(排队模式 OIO/BIO,后来放弃了)- 点单自领(NIO模式)
包厢等吃(AIO模式,后来移除了)
我的三种 Reactor
Reactor更像是一种事件的派发机制,但这些派发机制与响应的 IO 模式相关联。- ThreadPreConnection:使用 new NioEventLoopGroup(1) 创建,即可使用单 Reactor 单线程模式
- Reactor:使用 new NioEventLoopGroup() 创建,即可使用单 Reactor 多线程模式
- Proactor:使用两个 NioEventLoopGroup() 对象,即可创建主从 Reactor 多线程模式