【netty in action】学习笔记-第二章 编写你的第一个netty程序
这一章简略粗犷,整个章节都是讲一个例子,例子很简略,然而麻雀虽小五脏俱全。通过这个示例你会对编写基于netty的应用程序有个直观的意识。
我先上代码,前面再剖析。
先看看服务端的示例,
public class EchoServer { public int port; public EchoServer(int port) { this.port = port; } public void start() { EventLoopGroup group = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(group) .channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoServerHandler()); } }); ChannelFuture f = b.bind().sync(); System.out.println(EchoServer.class.getName() + "started and listen on " + f.channel().localAddress()); f.channel().closeFuture().sync(); }catch (Exception e) { }finally { group.shutdownGracefully(); } } public static void main(String[] args) { new EchoServer(8888).start(); }}
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(Unpooled.copiedBuffer("netty rocks", CharsetUtil.UTF_8)); } @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf msg) throws Exception { ByteBuf recieveMsg=(ByteBuf) msg; String result = ByteBufUtil.hexDump(recieveMsg).toUpperCase();//将bytebuf中的可读字节 转换成16进制数字符串 String result2 = ByteBufUtil.hexDump(msg.readBytes(msg.readableBytes())); //看下两种形式输入的后果有什么区别 System.out.println("client received:" + result); System.out.println("client received:" + result2); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}
而后是客户端的示例,
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 InterruptedException { 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 protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoClientHandler()); } }); ChannelFuture f = b.connect().sync(); f.channel().closeFuture().sync(); }catch (Exception e) { }finally { group.shutdownGracefully().sync(); } } public static void main(String[] args) { String host = "127.0.0.1"; int port = 8888; new EchoClient(host, port).start(); }}
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.write(Unpooled.copiedBuffer("netty rocks", CharsetUtil.UTF_8)); } @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf msg) throws Exception { ByteBuf recieveMsg=(ByteBuf) msg; String result = ByteBufUtil.hexDump(recieveMsg).toUpperCase();//将bytebuf中的可读字节 转换成16进制数字符串 String result2 = ByteBufUtil.hexDump(msg.readBytes(msg.readableBytes())); //看下两种形式输入的后果有什么区别 System.out.println("client received:" + result); System.out.println("client received:" + result2); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}
这个代码是能够运行的。你能够本人跑一下。
上面就来解释下下面这些代码。当然这里只做简略的解释,因为每个概念在前面的章节都有具体的形容。
Bootstrap
用来启动服务,客户端和服务端都应用这个。区别在于服务端应用的是ServerBootstrap
。这两个类都是继承自AbstractBootstrap
这个抽象类。
NioEventLoopGroup
用来解决多个连贯,能够把它了解为线程池。
NioServerSocketChannel
当然就是netty里最外围的概念channel。这里咱们指定channel的类型。当然这里你能够指定OioServerSocketChannel
,示意阻塞的IO channel。
咱们通过childHandler
指定业务解决外围逻辑的handler,这些handler是以链的形式治理的。ChannelPipeline
是这个链的名字。这其实也是设计模式中的责任链模式。
接着咱们通过bind
办法绑定服务器,sync
示意这是一个阻塞的同步调用,在绑定胜利之前都会期待。
EchoServerHandler
和EchoClientHandler
是咱们业务解决类,他们的设计办法就是咱们后面章节说到的回调。看房办法的名字也能猜出一二。咱们须要继承ChannelInboundHandlerAdapter
表明这是一个入口处的解决类。(进口和入口的前面会具体阐明)。
channelRead
办法在服务端(客户端)收到数据时被调用,exceptionCaught
是异样产生时调用。
须要留神的是,在接收数据的时候,channelRead
(channelRead0)可能会调用屡次,比方接管5个字节,第一次收到3个,第二次收到2个。这其实是netty外面拆包,粘包的概念,这个在前面的章节也会讲到,这里不多说。只管会呈现拆包,粘包的状况,然而netty能保障在TCP协定下,数据接管的程序和发送的程序是统一的。(这个也是netty很多自带的解码器解决粘包的前提)