搞懂Netty(三)-写一个Discard服务器
创始人
2025-01-20 11:33:57
0

在这里插入图片描述

在这篇文章,我实现一个最简单的协议-DISCARD协议。它把收到的请求数据立即抛弃,而且不做任何回复。
我们知道,Netty是一个事件驱动的网络程序框架,因此我们先从编写我们自己的事件处理器开始。

编写事件处理器

package netty.example.discard;  import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;  public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)      @Override     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // (2)         // Discard the received data silently.         ((ByteBuf)msg).release(); // (3)     }      @Override     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // (4)         // Close the connection when an exception is raised.         cause.printStackTrace();         ctx.close();     } } 
  1. DiscardServerHandler继承ChannelInboundHandlerAdapterChannelInboundHandlerAdapter简单实现了接口ChannelInboundHandler中的所有方法。ChannelInboundHandler提供了很多种可被重写的事件处理方法。由于我们的程序简单,我们只需继承ChannelInboundHandlerAdapter,然后重学我们需要自定义的方法即可。
  2. 这里我们重写了channelRead()方法。当有客户端发来请求的时候,这个方法会被调用,请求携带的数据会作为参数传进来。在这里,收到的数据的类型是ByteBuf
  3. 鉴于我们实现的是DISCARD协议,这里忽略收到的数据。另外需要注意的是,ByteBuf是携带引用计数的,需要显示的调用release()释放引用计数。我们在编写处理器是,要时刻想着返回前要释放传进来的任何带引用计数的对象。通常情况下, channelRead() 方法会遵循如下方式编写:
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) {     try {         // Do something with msg     } finally {         ReferenceCountUtil.release(msg);     } } 
  1. 当I/O发生错误,或者事件处理器执行过程中发生错误,会触发exceptionCaught()方法,该方法携带一个Throwable的参数。通常情况下,异常信息写到日志,关闭关联的channel。当然,根据具体情况会有不同的实现。比如,返回一个带有错误码的响应信息。
    当目前为止,一切都很好,我们已经实现了一半的需求。接下来,我们编写main()方法启动服务器。

编写main()方法启动服务器

package netty.example.discard;  import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;  public class DiscardServer {      private int port;      public DiscardServer(int port) {         this.port = port;     }      public void run() throws Exception {         EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)         EventLoopGroup workerGroup = new NioEventLoopGroup();         try {             ServerBootstrap b = new ServerBootstrap(); // (2)             b.group(bossGroup, workerGroup)                     .channel(NioServerSocketChannel.class) // (3)                     .childHandler(new ChannelInitializer() { // (4)                         @Override                         protected void initChannel(SocketChannel socketChannel) throws Exception {                             socketChannel.pipeline().addLast(new DiscardServerHandler());                         }                     })                     .option(ChannelOption.SO_BACKLOG, 128) // (5)                     .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)              // 绑定端口并等待连接             ChannelFuture f = b.bind(port).sync(); // (7)              // 阻塞直到 server socket 关闭。             f.channel().closeFuture().sync();         } finally {             workerGroup.shutdownGracefully();             bossGroup.shutdownGracefully();         }     }      public static void main(String[] args) throws Exception {         int port = 8080;         if (args.length > 0) {             port = Integer.parseInt(args[0]);         }          new DiscardServer(port).run();     } } 
  1. NioEventLoopGroup是一个多线程的,处理I/O的事件循环。Netty为不同的传输类型提供了很多种 EventLoopGroup的实现。我们这里因为实现的是服务器端,因此需要两个 NioEventLoopGroup,第一个称之为’boss’,负责接受连接。第二个称之为’worker’,负责已创建的并注册到worker的连接的数据交换。不同的 EventLoopGroup的实现决定使用多少线程以及哪个线程如何分配到创建的Channel
  2. ServerBootstrap是一个helper class,负责配置启动服务器。
  3. 这里,我们指定NioServerSocketChannel用于实例化Channel以接受新的连接。
  4. 这里指定的处理器被已已创建的连接使用。ChannelInitializer是一个特殊的处理器,用于配置 ChannelPipeline,增加新的处理器,如DiscardServerHandler。随着程序的复杂度的增加,在 ChannelPipeline加入更多的处理器,你可能会把这个匿名类抽出来成为top-level的类。
  5. 你可以为不同的Channel实现配置响应的选项。我们正在写基于TCP/IP的服务器,因此我们可以设置socket选项:tcpNoDelaykeepAlive。参考apidocs ChannelOption和特定的ChannelConfig 实现。
  6. option() 用于接受连接的NioServerSocketChannelchildOption() 用于已经被ServerChannel创建连接的Channel,即NioSocketChannel
  7. 最后,绑定端口并启动服务。这里我们绑定机器所有网卡的8080端口,你可以多次调用bind(),绑定不同的地址。
    到这,恭喜你,你已经完成了第一个基于Netty的网络程序。

相关内容

热门资讯

黑科技辅助!wpk辅助神器(透... 黑科技辅助!wpk辅助神器(透视)软件透明辅助挂(本来是真的有挂)-哔哩哔哩是一款可以让一直输的玩家...
5分钟了解“创思维正版辅助器下... 5分钟了解“创思维正版辅助器下载”详细透视开挂辅助安装-哔哩哔哩;一、创思维正版辅助器下载有挂的是的...
两分钟科普!wpk真吗,哈糖大... 两分钟科普!wpk真吗,哈糖大菠萝可以开挂吗,曝光教程(发现有挂)-哔哩哔哩哈糖大菠萝可以开挂吗辅助...
第一分钟了解(昆仑大厅)外挂辅... 第一分钟了解(昆仑大厅)外挂辅助插件(透视)详细教程(2022已更新)(哔哩哔哩);亲真的是有正版授...
黑科技辅助!wpk俱乐部长期盈... 黑科技辅助!wpk俱乐部长期盈利打法(透视)软件透明挂黑科技(切实存在有挂)-哔哩哔哩;1、让任何用...
第6分钟了解“功夫川嘛辅助器”... 第6分钟了解“功夫川嘛辅助器”详细透视开挂辅助器-哔哩哔哩;人气非常高,ai更新快且高清可以动的一个...
第五分钟辅助!xpoker辅助... 第五分钟辅助!xpoker辅助,德州透视插件,攻略教程(有挂方法)-哔哩哔哩德州透视插件辅助器中分为...
两分钟了解(皮皮跑胡子)外挂透... 两分钟了解(皮皮跑胡子)外挂透明挂辅助工具(辅助挂)透明挂教程(2020已更新)(哔哩哔哩);皮皮跑...
黑科技辅助!微扑克可以加入俱乐... 您好,微扑克可以加入俱乐部这款游戏可以开挂的,确实是有挂的,需要了解加微【136704302】很多玩...
8分钟了解“掌中乐游戏中心辅助... 8分钟了解“掌中乐游戏中心辅助器”详细透视开挂辅助脚本-哔哩哔哩;1、这是跨平台的掌中乐游戏中心辅助...