Netty实战第二章主要通过讲解EchoClient、EchoServer构建了一个基于Netty的应用。
在client端,1 , EventLoopGroup实例化一个对象。2 ,实例化一个bootstrap对象,作为netty高性能服务器的启动器。3 , 将EventLoopGroup实例group进bootStrap实例 4 , 申明连接的I/O类别为NioChannelSocket。5 , 申明连接的远程地址和端口号。6 , 将channelHandler添加入pipeline中,channelHandler处理请求。
import java.net.InetSocketAddress;
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;
public class EchoClientCopy {
private String host;
private int port;
public EchoClientCopy(String host , int port){
this.host = host;
this.port = port;
}
public void start()
throws Exception{
EventLoopGroup group = new NioEventLoopGroup();// 创建EventLoopGroup处理客户端事件。
try{
Bootstrap b = new Bootstrap();// 创建客户端启动器
b.group(group)// 指定EventLoopGroup处理客户端请求。
.channel(NioSocketChannel.class)// 指定NioSocketChannel,支持Nio操作,适用于Nio的传输Channel。
.remoteAddress(new InetSocketAddress(this.host , this.port))// 指定远程地址
.handler(new ChannelInitializer<SocketChannel>(){// 在创建handler时
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub// 创建handler时,向pipeline添加channelHandler实例。
ch.pipeline().addLast(// 当连接成功时,自动调用handler中的channelActive。
new EchoClientHandlerCopy());
}
});
ChannelFuture f = b.connect().sync();// 连接到新的节点,同步阻塞等待。
// 阻塞,直到关闭。
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception{
if (args.length != 2){
System.err.println("Usage: " + EchoClientCopy.class.getSimpleName() +
" <host> <port>");
}
final String host = args[0];
final int port = Integer.parseInt(args[1]);
new EchoClientCopy(host , port).start();
}
}
clientHandler主要有三个方法:channelActive、channelRead0、exceptionCaught。
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
public class EchoClientHandlerCopy
extends SimpleChannelInboundHandler<ByteBuf>{
@Override
public void channelActive(ChannelHandlerContext ctx)// 当连接的时候,调用channelActive
throws Exception{
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!",// 发送消息到服务器。
CharsetUtil.UTF_8));
}
@Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) // 当接收到服务器消息时,调用channelRead0。
throws Exception {
System.out.println("reveive message:" + msg.toString(CharsetUtil.UTF_8));
}
@Override
//发生异常,关闭channel,并且打印错误。
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause){
ctx.close();
cause.printStackTrace();
}
}
在netty构建的server端:1 , 实例化一个EventLoopGroup对象。2 , 实例化一个ServerBootstrap对象。3, 将EventLoopGroup group到ServerBootstarp中。4 , 申明I/O类型为NioServerSocketchannel。5 , 申明服务器端口号。6 , 将channelHandler加入pipeline中。
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 java.net.InetSocketAddress;
import io.netty.bootstrap.ServerBootstrap;
public class EchoServerCopy {
private int port;
public EchoServerCopy(int port){
this.port = port;
}
public void start()throws Exception{
// 1 , 创建EventLoop,为channel
EventLoopGroup group = new NioEventLoopGroup();
try{
ServerBootstrap bootstrap = new ServerBootstrap();
// 2 , 为serverBootstrap添加group。
bootstrap.group(group)
// 3 , 指定NIO传输channel
.channel(NioServerSocketChannel.class)
// 4 , 使用指定的套接字设置端口号。
.localAddress(new InetSocketAddress(this.port))
// 5 , 为Channel添加handler,将channelhandler添加到指定的pipeline中。
.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(
new EchoServerHandlerCopy());
}
});
// 6,异步绑定服务器,调用sync方法阻塞直到绑定成功。
ChannelFuture f = bootstrap.bind().sync();
System.out.println(
EchoServerCopy.class.getName() +
"started and listenering the connection:" + f.channel().localAddress()
);
// 7,获取Channel的closeFuture,并且阻塞当前进程直到完成。
f.channel().closeFuture().sync();
} finally{
// 8 , 关闭EventLoopGroup,释放资源。
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception{
if (args.length != 0){
System.err.println(EchoServerCopy.class.getName());
}
final int port = Integer.parseInt(args[0]);
new EchoServerCopy(port).start();
}
}
serverChannelHandler主要了三分方法:1 , channelRead方法,接收到客户端请求消息的时候。2 , channelReadComplete读取完客户端发送的消息的时候。 3 , exceptionCaught 发生异常的时候。
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
public class EchoServerHandlerCopy extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg){
//接收客户端的消息。
ByteBuf buf = (ByteBuf) (msg);
System.out.println("server accepte message:" + buf.toString(CharsetUtil.UTF_8));
// 将消息发送到客户端。
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception{// 当读取完channel中的数据时
// 冲刷消息,并且关闭连接。
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause){
cause.printStackTrace();// 打印出错信息。
ctx.close();// 关闭channel。
}
}