netty学习(入门篇)
netty诞生简介
2002年之前,那时候java还没有nio的概念,没有channel,没有缓冲区,io模式是同步阻塞的,想要编写高性能的服务器几乎是不可能的,那时候基本上服务器都是由c,c++编写的,直到jdk1.4java第一次支持了nio,这个类库为java通信模式带来了翻天覆地的变化,从那一年开始java慢慢在服务器开发占据了一席之地,但是nio编程也有很大的缺陷,代码复杂度很高,门槛很高,扩展性复用性都不是很好而且还有seletor空轮询bug,不过现在好像已经修复的差不多了。nio是同步非阻塞io,jdk1.7对nio进行了升级成aio异步非阻塞,主要是提供了基于文件的异步io操作和网络套接字的异步io操作。鉴于nio编程的复杂性,不稳定性,就有人帮我们造轮子了,netty是jboss提供一个高性能的异步的非阻塞的基于事件驱动的网络通讯框架,使用netty我们可以快速开发出稳定高效的服务器。
当然,所有这些io都是基于操作系统的io模型来实现的
select,poll,epoll模型在我之前的并发编程专栏里有专门的文章说明,之前花了半个月学习io模型对我帮助很大,虽然刚开始接触netty,但感觉一点都不难理解
netty服务器
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws InterruptedException {
new EchoServer(9999).start();
}
private void start() throws InterruptedException {
// 入门案例使用Reactor单线程模型
// 接收客户端的TCP连接;向通信对端发送消息请求或者应答消息;
EventLoopGroup group = new NioEventLoopGroup();
try {
//服务器启动类,把所有组件串起来
ServerBootstrap server = new ServerBootstrap();
server.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
//Handler主要是做编解码和业务逻辑处理
//为什么要做编解码,因为数据在网络上都是字节传输的(也可以说二进制,只不过粒度小点而已)
//而我们接收数据期望收到的可不是字节,而是基本数据类型或者对象。所以要做编解码
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//这里是拦截链模式,解码器(入站)->编码器(出站)->业务逻辑处理
socketChannel.pipeline().addLast("decoder", new StringDecoder());
socketChannel.pipeline().addLast("encoder", new StringEncoder());
socketChannel.pipeline().addLast(new EchoServerHandler());
}
});
ChannelFuture future = server.bind().sync();
System.out.println(EchoServer.class.getName() + " started and listen on " + future.channel().localAddress());
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Server received: " + msg); //2
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
//冲刷所有待审消息到远程节点。关闭通道后,操作完成
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
netty客户端
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
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast("decoder", new StringDecoder());
ch.pipeline().addLast("encoder", new StringEncoder());
ch.pipeline().addLast(new EchoClientHandler());
}
});
ChannelFuture future = b.connect().sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoClient("localhost", 9999).start();
}
}
@ChannelHandler.Sharable
public class EchoClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush("Netty rocks!\r\n");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Client received: " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}