netty 第一款Netty应用程序
- 创建项目
mvn archetype:generate -DgroupId=org.xtxg -DartifactId=netty-frame-helloworld-server
- 引入pom
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.23.Final</version>
</dependency>
3.编写Server引导类
- 引导过程步骤如下
- 创建一个ServerBootstrap的实例以引导和绑定服务器;
- 创建并分配一个NioEventLoopGroup实例以进行事件的处理,如接受新连接以及读/写数据;
- 指定服务器绑定的本地的InetSocketAddress;
- 使用一个EchoServerHandler的实例初始化每一个新的Channel;
- 调用ServerBootstrap.bind()方法以绑定服务器。
- ChannelHandler和业务逻辑
因为你的Echo服务器会响应传入的消息,所以它需要实现ChannelInboundHandler接口,用来定义响应入站事件的方法。这个简单的应用程序只需要用到少量的这些方法,所以继承Channel-InboundHandlerAdapter类也就足够了,它提供了ChannelInboundHandler的默认实现。
- 我们感兴趣的方法是:
- channelRead()——对于每个传入的消息都要调用;
- channelReadComplete()——通知ChannelInboundHandler最后一次对channelRead()的调用是当前批量读取中的最后一条消息;
- exceptionCaught()——在读取操作期间,有异常抛出时会调用
代码如下
EventLoopGroup group = new NioEventLoopGroup(); // 1.创建EventLoopGroup对象
try {
ServerBootstrap bootstrap = new ServerBootstrap(); // 2.创建BootStrap
bootstrap.group(group)
.channel(NioServerSocketChannel.class) // 3.指定NIO方式传输Channel
.localAddress(new InetSocketAddress(port)) // 4.使用指定的端口设置套接字地址
.childHandler(new ChannelInitializer<SocketChannel>() { // 添加一个EchoServerHandle到Channel的ChannelPipline
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() { // 因为你的Echo服务器会响应传入的消息,所以它需要实现ChannelInboundHandler接口,用来定义响应入站事件的方法。这个简单的应用程序只需要用到少量的这些方法,所以继承Channel-InboundHandlerAdapter类也就足够了,它提供了ChannelInboundHandler的默认实现
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in = (ByteBuf) msg;
System.out.println("服务端接收到信息 " + in.toString(CharsetUtil.UTF_8));// 将消息记录到控制台
ctx.write(in); // 将接受到信息写个发送者,而不冲刷出站消息
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
// .addListener(ChannelFutureListener.CLOSE);// 将未决信息冲刷至远程节点,并且关闭Channel
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();// d打印异常栈
ctx.close();// 关闭Channel
}
});
}
});
ChannelFuture future = bootstrap.bind().sync();// 6.异步绑定服务器;调用sync()方法阻塞等待直到绑定完成
future.channel().closeFuture().sync();// 7.获取Channel的CloseFuture,并且阻塞当前线程直到它完成
} finally {
group.shutdownGracefully().sync(); // 8.关闭EventGroup,释放所有的资源
}
4.编写client类
1.编写client引导类
1. 为初始化客户端,创建了一个Bootstrap实例;
2. 为进行事件处理分配了一个NioEventLoopGroup实例,其中事件处理包括创建新的连接以及处理入站和出站数据;
3. 为服务器连接创建了一个InetSocketAddress实例;
4. 当连接被建立时,一个EchoClientHandler实例会被安装到(该Channel的)ChannelPipeline中;
5. 在一切都设置完成后,调用Bootstrap.connect()方法连接到远程节点;
- 编写ChannelHandler实现客户端逻辑
扩展SimpleChannelInboundHandler类以处理所有必须的任务,要求重写下面的方法- channelActive()——在到服务器的连接已经建立之后将被调用;
- channelRead0()[5]——当从服务器接收到一条消息时被调用;
- exceptionCaught()——在处理过程中引发异常时被调用。
- 代码如下
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.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 SimpleChannelInboundHandler<ByteBuf>() {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("你好,世界!", CharsetUtil.UTF_8));// 当被通知Channel是活跃的时候,发送一条消息
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println("客户端收到:" + byteBuf.toString(CharsetUtil.UTF_8)); // 接收消息转储
Thread.sleep(1000);
byteBuf.retain();
channelHandlerContext.writeAndFlush(byteBuf);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 发生异常时,记录错误并关闭
cause.printStackTrace();
ctx.close();
}
});
}
});
ChannelFuture future = bootstrap.connect().sync();// 连接到远程节点,阻塞等待直到连接完成
future.channel().closeFuture().sync();// 阻塞,直到Channel关闭
} finally {
group.shutdownGracefully().sync();
}
本章节详细代码,见 netty-frame-helloworld-server模块:https://gitee.com/gtxg/netty-learn.git