不正经的开头
本文首先会介绍Netty的基本API,然后在实现一个小应用,那我们开始吧,是不是有点小激动呢 [滑稽]
本文主要从以下几个方面:
ChannelHandler
的作用和它的方法- 服务端编写
- Handler
- BootStrap
- 客户端的编写
- Handler
- BootStrap
- 运行结果
1.ChannelHandler
的API
之前我们也介绍过了ChannelHandler,此处详细介绍它的方法以及用途。它是一个接口,它的实现负责接收并响应事件。
我们比较常用的是ChannelInboundHandlerAdapter
它是一个实现了ChannelHandler
接口的类,一般也够我们用了,当然可以自己写一个类继承它,扩充自己的功能。
一些常用的方法:
channelRead()
对于每个传入的消息都要调用channelReadComplete()
通知ChannelInboundHandler
最后一次对channelRead()
的调用时是当前批次中的最后一条消息exceptionCaught()
读取操作期间,抛出异常时调用
再说一次,ChannelHandler
负责接收并响应事件,即来了一个事件,它执行对应的方法。哎妈呀,我太机智了~
2.服务端编写
有了上面的基础就可以开始了
一个小插曲:Netty服务器结构
- 至少一个
ChannelHandler
:该组件实现了服务器接收的数据的处理,即它的业务逻辑 - 引导:这是配置服务器的启动代码。将服务器绑定到他要监听链接请求的端口上,配置Channel,将有关的消息通知给
ChannelHanler
Server端代码:
public class ServerDemo {
private int prot;
public ServerDemo(int prot) {
this.prot = prot;
}
public static void main(String[] args) throws InterruptedException {
new ServerDemo(9111).satart();
}
public void satart() throws InterruptedException {
final ServerHandller serverHandller = new ServerHandller();
//创建ServerBootstrap实例
ServerBootstrap boot = new ServerBootstrap();
//创建一个EventLoopGroup
EventLoopGroup group = new NioEventLoopGroup();
//指定实例来接受和处理新的连接。
boot.group(group)
//指定使用NIO Channel传输
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(prot))
//当一个新的连接被接受时,一个新的子Channel会被创建,
// ChannelInitializer会把serverHandller的实例加入到该Channel的ChannelPipeLine
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(serverHandller);
}
});
try {
//异步绑定到服务器,调用sync方法阻塞当前线程,直到绑定完成
ChannelFuture future = boot.bind().sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
group.shutdownGracefully().sync();
}
}
}
ServerHandler代码:
public class ServerHandller extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object o) {
ByteBuf in = (ByteBuf)o;
System.out.println("Server Receive:"+in.toString(CharsetUtil.UTF_8));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.writeAndFlush((Unpooled.copiedBuffer("Thanks ~", CharsetUtil.UTF_8)));
/*ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);*/
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
总结一下
ServerHandler
实现了业务逻辑- 创建
ServerBootStrap
实例,引导以及绑定服务器 - 创建
EventLoopGroup
实例,进行事件的处理,如连接、读取、写入 - 用一个
ServerHandler
实例初始化每一个新的Channel
3.客户端
编写客户端也包括业务逻辑和引导,和服务器中一样。
3.1.ChannelHandler
实现客户端的业务逻辑
介绍一个抽象类SimpleChannelInboundHandler
,有点和ChannelInboundHandlerAdapter
类似,它可以用来处理客户的业务逻辑。直接上代码
public class ClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
//当被通知Channel是活跃的时候,发送一条消息
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty is No.1", CharsetUtil.UTF_8));
}
@Override
//接收消息时会调用该方法
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println("Client Recived:"+msg.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
3.3.客户端
public class ClientDemo {
private final String host = "127.0.0.1";
private final int port = 9999;
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
//创建Bootstrap
Bootstrap bootstrap = new Bootstrap();
try {
//指定EventLoopGroup处理客户端事件
bootstrap.group(group)
//适用于Nio传输的Channel类型
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
//在创建Chann时,向ChannelPipeline添加一个ClientHandler实例
.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ClientHandler());
}
});
//连接到服务器,阻塞直到连接完成
ChannelFuture future = bootstrap.connect().sync();
//阻塞到Channel关闭
future.channel().closeFuture().sync();
}catch (Exception e) {
e.printStackTrace();
}finally {
//关闭线程池并释放资源
group.shutdownGracefully().sync();
}
}
public void main(String args[]) throws Exception {
new ClientDemo().start();
}
}
总结一下:
- 实例化了
NioEventLoopGroup
实例,被用来处理创建新的连接以及数据的出入 - 实例化
InetSocketAddress
用来连接到服务器 - 当有连接建立,
ClientHandler
的实例会被加到ChannelPipeline
中 - 正式连接到服务器
Bootstrap.connect()
运行结果:
Server端输出:Server Receive:Netty is No.1
Client端输出:Client Recived:Thanks ~
下一篇:http://blog.csdn.net/theludlows/article/details/79463635