Netty入门 && 第一个Netty程序

忘是亡心i 2022-12-27 07:43 265阅读 0赞

1 为什么要用 Netty

(1) 虽然 JAVA NIO 框架提供了 多路复用 IO 的支持,但是并没有提供上层“信息格式”的良好封装。例如前两者并没有提供针对 Protocol Buffer、JSON 这些信息格式的封装,但是Netty 框架提供了这些数据格式封装(基于责任链模式的编码和解码功能)。

(2) NIO 的类库和 API 相当复杂,使用它来开发,需要非常熟练地掌握 Selector、ByteBuffer、ServerSocketChannel、SocketChannel 等,需要很多额外的编程技能来辅助使用 NIO,例如,因为 NIO 涉及了 Reactor 线程模型,所以必须必须对多线程和网络编程非常熟悉才能写出高质量的 NIO 程序。

(3) 要编写一个可靠的、易维护的、高性能的 NIO 服务器应用。除了框架本身要兼容实现各类操作系统的实现外。更重要的是它应该还要处理很多上层特有服务,例如:客户端的权限、还有上面提到的信息格式封装、简单的数据读取,断连重连,半包读写,心跳等等,
这些 Netty 框架都提供了响应的支持。

2 Netty简介

2.1 EventLoop(Group) 、Channel

Channel 是 Java NIO 的一个基本构造。它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一
个或者多个不同的 I/O 操作的程序组件)的开放连接,如读操作和写操作。目前,可以把 Channel 看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。EventLoop 暂时可以看成一个线程、EventLoopGroup 自然就可以看成线程组。
在这里插入图片描述

2.2 事件和 ChannelHandler、ChannelPipeline

Netty 使用不同的事件来通知我们状态的改变或者是操作的状态。这使得我们能够基于已经发生的事件来触发适当的动作。Netty 事件是按照它们与入站或出站数据流的相关性进行分类的。可能由入站数据或者相关的状态更改而触发的事件包括:连接已被激活或者连接失活;数据读取;用户事件;错误事件。

出站事件是未来将会触发的某个动作的操作结果,这些动作包括:打开或者关闭到远程节点的连接;将数据写到或者冲刷到套接字。每个事件都可以被分发给 ChannelHandler 类中的某个用户实现的方法。Netty 提供了大量预定义的可以开箱即用的 ChannelHandler 实现,包括用于各种协议(如 HTTP 和 SSL/TLS)的 ChannelHandler。
在这里插入图片描述

3 第一个 Netty 程序

3.1 EchoServerHandler

  1. public class EchoServerHandler extends ChannelInboundHandlerAdapter {
  2. @Override
  3. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  4. ByteBuf byteBuf = (ByteBuf) msg;
  5. System.out.println("Server accept: " + byteBuf.toString(CharsetUtil.UTF_8));
  6. ctx.writeAndFlush(byteBuf);
  7. ctx.close();
  8. }
  9. @Override
  10. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  11. cause.printStackTrace();
  12. ctx.close();
  13. }
  14. }

3.2 EchoServer

  1. public class EchoServer {
  2. public static void main(String[] args) throws InterruptedException {
  3. //服务器启动
  4. ServerBootstrap bootstrap = new ServerBootstrap();
  5. //线程组
  6. EventLoopGroup group = new NioEventLoopGroup();
  7. try {
  8. //配置启动器
  9. bootstrap.group(group)
  10. //channel
  11. .channel(NioServerSocketChannel.class)
  12. //启动端口
  13. .localAddress(new InetSocketAddress(8888))
  14. //handler
  15. .childHandler(new ChannelInitializer<SocketChannel>() {
  16. @Override
  17. protected void initChannel(SocketChannel socketChannel) throws Exception {
  18. socketChannel.pipeline().addLast(new EchoServerHandler());
  19. }
  20. });
  21. //绑定服务器,sync阻塞完成
  22. ChannelFuture channelFuture = bootstrap.bind().sync();
  23. System.out.println("EchoServer started");
  24. //阻塞线程知道服务器channel close
  25. channelFuture.channel().closeFuture().sync();
  26. } finally {
  27. //退出,释放线程池
  28. group.shutdownGracefully();
  29. }
  30. }
  31. }

3.3 EchoClientHandler

  1. public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
  2. @Override
  3. protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
  4. System.out.println("client accept " + byteBuf.toString(CharsetUtil.UTF_8));
  5. }
  6. @Override
  7. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  8. ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8));
  9. }
  10. }

3.4 EchoClient

  1. public class EchoClient {
  2. public static void main(String[] args) {
  3. //客户端启动
  4. Bootstrap bootstrap = new Bootstrap();
  5. //线程组
  6. EventLoopGroup group = new NioEventLoopGroup();
  7. try {
  8. bootstrap.group(group)
  9. .channel(NioSocketChannel.class)
  10. .remoteAddress(new InetSocketAddress("127.0.0.1", 8888))
  11. .handler(new ChannelInitializer<SocketChannel>() {
  12. @Override
  13. protected void initChannel(SocketChannel socketChannel) throws Exception {
  14. socketChannel.pipeline().addLast(new EchoClientHandler());
  15. }
  16. });
  17. //等待链接完成
  18. ChannelFuture channelFuture = bootstrap.connect().sync();
  19. //阻塞当前线程,直到channel关闭
  20. channelFuture.channel().closeFuture().sync();
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. } finally {
  24. //退出,释放线程池
  25. group.shutdownGracefully();
  26. }
  27. }
  28. }

3.5 测试结果

在这里插入图片描述
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,265人围观)

还没有评论,来说两句吧...

相关阅读