搭建第一个Netty应用程序
本篇文章主要记录如何搭建一个简单的Netty服务器和客户端。
依赖环境:
- Java 8
- Netty4
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.11.Final</version>
</dependency>
</dependencies>
编写Echo服务器
所有的Netty服务器都需要以下两个部分。
- 至少一个ChannelHandler:用来处理业务逻辑
- 引导:配置服务器启动代码,将服务器绑定到监听连接请求的端口上。
EchoServerHandler类:用来处理核心业务逻辑
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext context, Object msg) {
ByteBuf in = (ByteBuf) msg;
System.out.println("server received: " + in.toString(CharsetUtil.UTF_8));
context.write(in);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext context, Throwable couse) {
couse.printStackTrace();
context.close();
}
}
EchoServer类:配置服务器,并将入站消息通知给EchoServerHandler实例。
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws Exception {
System.err.println("Usage: " + EchoServer.class.getSimpleName() + "<port>");
int port = 8999;
new EchoServer(port).start();
}
public void start() throws Exception{
final EchoServerHandler serverHandler = new EchoServerHandler();
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group).channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(serverHandler);
}
});
ChannelFuture future = b.bind().sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}
服务器主要的代码组件
- EchoServerHandler实现业务逻辑
- main()引导服务器
引导过程:
- 创建一个ServerBootstap实例以引导和绑定服务器;
- 创建并分配一个NioEventLoopGroup实例以进行事件的处理,如接受新连接以及读写数据;
- 指定服务器绑定的本地的InetSocketAddress;
- 使用一个Handler实例初始化新的Channel;
- 调用ServerBootstap.bind()方法以绑定服务器;
编写Echo客户端
Echo客户端:
- 连接服务器
- 发送一个或多个消息
- 对于每个消息,等待并接受从服务器发回的相同的消息
- 关闭连接
ChannelHandler类:实现客户端逻辑
- channelActive()和服务器建立连接后调用
- channelRead()从服务器接受到一条信息后调用
- exceptionCaught()处理过程中出现异常时被调用
@ChannelHandler.Sharable
public class EchoClientHandle extends SimpleChannelInboundHandler<ByteBuf>{
@Override
public void channelActive(ChannelHandlerContext context) {
context.writeAndFlush(Unpooled.copiedBuffer("Netty rocks", CharsetUtil.UTF_8));
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println("Client received: " + byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext context, Throwable cause) {
cause.printStackTrace();
context.close();
}
}
EchoClient类:引导客户端
public class EchoClient {
// 使用的是服务器的地址
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception{
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new EchoClientHandle());
}
});
ChannelFuture future = b.connect().sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoClient("localhost", 8999).start();
}
}
GitHub地址:https://github.com/huangbuhuan/netty-demo
参考连接
- 《Netty In Action》