Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
官方原文
Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.
Netty 是一个基于NIO的客户-服务器端编程框架,使用Netty 可以确保你快速、简单的开发出一个网络应用,例如实现了某种协议的客户-服务端应用。Netty极大程度的简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
官方原文
Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.
设计
易用
性能
安全
了解了Netty的基本概念之后,通过一个简单的sample来了解如何使用Netty提供的API构建自己的应用程序。
1.开发环境
2.添加Maven依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.34.Final</version>
</dependency>
在作者写作本文时,Maven中央仓库中Netty 最新版本为5.0.0.Alpha2,release版本为4.0.34.Final,故后期所有Netty版本皆使用4.0.34.Final版本。
3.server端
HelloWorldServer.java
package com.ricky.codelab.netty.ch1;
import com.ricky.codelab.netty.util.Constant;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/** * Hello world Server. * @author Ricky * */
public class HelloWorldServer {
private int port;
public HelloWorldServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); // (2)
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3)
.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder(), new StringDecoder(), new HelloWorldServerHandler());
}
});
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(port).sync(); // (7)
// 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();
}
}
public static void main(String[] args) throws Exception {
new HelloWorldServer(Constant.PORT).run();
}
}
HelloWorldServerHandler.java
package com.ricky.codelab.netty.ch1;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/** * Handles a server-side channel. */
public class HelloWorldServerHandler extends ChannelInboundHandlerAdapter { // (1)
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
System.out.println("server receive:"+msg);
ctx.writeAndFlush("Hello [from server]");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
4.client端
HelloWorldClient.java
package com.ricky.codelab.netty.ch1;
import com.ricky.codelab.netty.util.Constant;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/** * Hello world Client. * @author Ricky * */
public class HelloWorldClient {
private String host;
private int port;
public HelloWorldClient(String host, int port) {
this.host = host;
this.port = port;
}
public void send() throws InterruptedException {
Bootstrap bootstrap = new Bootstrap();
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder(), new StringDecoder(), new HelloWorldClientHandler());
}
});
ChannelFuture future = bootstrap.connect(host, port).sync();
future.channel().closeFuture().sync();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new HelloWorldClient(Constant.HOST, Constant.PORT).send();
}
}
HelloWorldClientHandler.java
package com.ricky.codelab.netty.ch1;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/** * Handles a client-side channel. */
public class HelloWorldClientHandler extends ChannelInboundHandlerAdapter { // (1)
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// Send the message to Server
super.channelActive(ctx);
System.out.println("client send message");
ctx.writeAndFlush("Hello world![from client]");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
System.out.println("client receive:" + msg);
ctx.close();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
在Netty中通信都是基于流来传递的,即以byte的形式传递。所以,我们需要将需要传递的String转换成byte数组。
在Netty4中提供了StringEncoder和StringDecoder来达到这一目的,类似的还有ObjectEncoder和ObjectDecoder来将Object转换为byte数组。
先启动HelloWorldServer.java,然后启动HelloWorldClient.java,此时在控制台就能看到打印的输出了。
上述源代码均已上传到GitHub,需要下载源代码的童鞋点此进行下载。