服务端
Netty的服务器其中之一便是TCP服务器。想要创建TCP服务器你必须:
- 创建一个EventLoopGroup
- 创建和配置ServerBootstrap
- 创建一个ChannelInitializer
- 启动服务器
下面是一个完整的使用Netty创建TCP服务器的代码例子:
EventLoopGroup group = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(group);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.localAddress(new InetSocketAddress("localhost", 9999));
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new HelloServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind().sync();
channelFuture.channel().closeFuture().sync();
} catch(Exception e){
e.printStackTrace();
} finally {
group.shutdownGracefully().sync();
}
上面代码中的过程被分解为更小的步骤,并在接下来的部分中单独描述。
创建EventLoopGroup
创建Netty TCP服务端的第一步是创建EventLoopGroup。因为我们的例子中使用了Java NIO,所以我们创建了NioEventLoopGroup。下面是创建EventLoopGroupde的代码:
EventLoopGroup group = new NioEventLoopGroup();
创建和配置ServerBootstrap
创建Netty TCP服务端的第二部是创建并配置ServerBootstrap。下面是相关代码:
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(group);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.localAddress(new InetSocketAddress("localhost", 9999));
第一步是创建一个ServerBootstrap实例。
第二步是将EventLoopGroup设置到ServerBootstrap实例中。
第三步是将NioServerSocketChannel类的实例设置到ServerBootstrap实例中。这是非常必要的,因为例子中使用NioEventLoopGroup。
第四步是将本地IP地址或者域名和TCP端口号设置到ServerBootstrap实例中。用于Netty服务器的启动。
创建ChannelInitializer
第三步引导Netty TCP服务器是创建ChannelInitializer并将它附加到ServerBootstrap实例中。ChannelInitializer所有的TCP入站的socket连接。
创建并添加ChannelInitializer如下代码:
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new HelloServerHandler());
}
});
Netty的ChannelInitializer类是一个抽象类。每当TCP服务器接受新的TCP连接时,它的方法initChannel()被调用。正如你所看到的,它会添加一个新的HelloServerHandler(一个ChannelHandler)到每个新的SocketChannel中。也可能在所有新的SocketChannel实例中重用相同的ChannelHandler,而不是这里每次都要创建一个新的。
正如你所看见的,ServerBootstrap使用childHandler()方法将ChannelInitializer添加到ServerBootstrap中。
启动服务
引导一个Netty TCP服务器的最后一步就是启动服务器了。下面的代码完成了TCP服务器的启动:
ChannelFuture channelFuture = serverBootstrap.bind().sync();
serverBootstrap.bind()方法返回一个ChannelFuture,可以用于知道服务器绑定的完成(绑定到本地地址和TCP端口)。通过调用ChannelFuture的sync()方法,主线程在继续操作之前,会创建一个直到服务器启动的等待。顺便说一下,sync()方法同样会返回一个ChannelFuture。
HelloServerHandler
HelloServerHandler通过ChannelInitializer被添加到每个SocketChannel中,它是用来处理从客户端接受到的数据的组件。下面是HelloServerHandler的示例代码:
public class HelloServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf inBuffer = (ByteBuf) msg;
String received = inBuffer.toString(CharsetUtil.UTF_8);
System.out.println("Server received: " + received);
ctx.write(Unpooled.copiedBuffer("Hello " + received, CharsetUtil.UTF_8));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
每当从SocketChannel接收到数据时,就会调用channelRead()方法。正如你在代码中所看到的,每当客户端向服务端发送数据,channelRead()方法都会返回带有"Hello+"的响应。
当没有更多数据从SocketChannel读取数据时,调用channelReadComplete()方法。
如果在接收或发送来自SocketChannel的数据时抛出异常,则调用exceptionCaught()方法。在这里,您可以决定应该发生什么,比如关闭连接,或者响应错误代码等等。
原文链接:http://tutorials.jenkov.com/netty/netty-tcp-server.html