Netty
Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.
-
Unified API for various transport types - blocking and non-blocking socket
-
Based on a flexible and extensible event model which allows clear separation of concerns
-
Highly customizable thread model - single thread, one or more thread pools such as SEDA
-
True connectionless datagram socket support (since 3.1)
Hello World
从最简单的 Discard 开始。
- jar 引入
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.17.Final</version>
</dependency>
Server
- DiscardServerHandler.java
服务端的处理器。直接忽略信息。
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* Handles a server-side channel.
*/
public class DiscardServerHandler extends SimpleChannelInboundHandler<Object> {
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
// discard
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
- DiscardServer.java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
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;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/**
* Discards any incoming data.
*/
public final class DiscardServer {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8009"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
} else {
sslCtx = null;
}
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new DiscardServerHandler());
}
});
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
运行 main()
可以启动服务。日志如下:
十一月 16, 2017 8:19:59 下午 io.netty.handler.logging.LoggingHandler channelRegistered
信息: [id: 0xbd9cae9f] REGISTERED
十一月 16, 2017 8:19:59 下午 io.netty.handler.logging.LoggingHandler bind
信息: [id: 0xbd9cae9f] BIND: 0.0.0.0/0.0.0.0:8009
十一月 16, 2017 8:19:59 下午 io.netty.handler.logging.LoggingHandler channelActive
信息: [id: 0xbd9cae9f, L:/0:0:0:0:0:0:0:0:8009] ACTIVE
Client
- DiscardClientHandler.java
客户端处理器代码。
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* Handles a client-side channel.
*/
public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> {
private ByteBuf content;
private ChannelHandlerContext ctx;
@Override
public void channelActive(ChannelHandlerContext ctx) {
this.ctx = ctx;
// Initialize the message.
content = ctx.alloc().directBuffer(DiscardClient.SIZE).writeZero(DiscardClient.SIZE);
// Send the initial messages.
generateTraffic();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
content.release();
}
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
// Server is supposed to send nothing, but if it sends something, discard it.
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
long counter;
private void generateTraffic() {
// Flush the outbound buffer to the socket.
// Once flushed, generate the same amount of traffic again.
ctx.writeAndFlush(content.retainedDuplicate()).addListener(trafficGenerator);
}
private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
generateTraffic();
} else {
future.cause().printStackTrace();
future.channel().close();
}
}
};
}
- DiscardClient.java
客户端代码。
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
/**
* Keeps sending random data to the specified address.
*/
public final class DiscardClient {
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8009"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
}
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
p.addLast(new DiscardClientHandler());
}
});
// Make the connection attempt.
ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
运行 main()
方法,此时在服务器端会新增日志如下:
十一月 16, 2017 8:22:17 下午 io.netty.handler.logging.LoggingHandler channelRead
信息: [id: 0xbd9cae9f, L:/0:0:0:0:0:0:0:0:8009] READ: [id: 0xb998910b, L:/127.0.0.1:8009 - R:/127.0.0.1:64593]
十一月 16, 2017 8:22:17 下午 io.netty.handler.logging.LoggingHandler channelReadComplete
信息: [id: 0xbd9cae9f, L:/0:0:0:0:0:0:0:0:8009] READ COMPLETE
netty 学习路线
netty 是进阶的必备技能。
java nio
java 并发
jmm
实战
比如手写 grpc/dubbo 的等框架,深入理解实现机制。