搞懂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的网络程序。

相关内容

热门资讯

近年来!wepoker透视辅助... 近年来!wepoker透视辅助下载,新道游辅助软件,窍要教程(有挂方针)1、上手简单,内置详细流程视...
值得注意的是!大菠萝免费辅助,... 值得注意的是!大菠萝免费辅助,相约十三水破解,绝活儿教程(有挂教程)1、任何相约十三水破解透视是真的...
出乎意料的是!wpk真的有透视... 出乎意料的是!wpk真的有透视嘛,人皇辅助软件下载,绝活儿教程(有挂方法)1、人皇辅助软件下载公共底...
攻略辅助挂!hhpoker脚本... 攻略辅助挂!hhpoker脚本下载,雀友会广东潮汕苹果,秘籍教程(有挂详情)1、进入游戏-大厅左侧-...
教程辅助挂!pokemmo脚本... 教程辅助挂!pokemmo脚本辅助器,打哈儿脚本,绝活儿教程(有挂方针)1、打哈儿脚本免费辅助多个强...
近年来!aapoker俱乐部靠... 近年来!aapoker俱乐部靠谱吗,福建十三时辅助,办法教程(有挂详细)福建十三时辅助脚本下载中分为...
教程辅助挂!哈糖大菠萝助手,闲... 教程辅助挂!哈糖大菠萝助手,闲逸斗地主辅助,项目教程(有挂方略)1、在闲逸斗地主辅助插件功能辅助器技...
推出新举措!hhpoker有透... 推出新举措!hhpoker有透视功能吗,微乐脚本,窍要教程(有挂分享)1、许多玩家不知道微乐脚本辅助...
近日!pokemmo手机辅助软... 近日!pokemmo手机辅助软件,福建天天开心辅助工具视频,演示教程(有挂存在)福建天天开心辅助工具...
这一现象值得深思!wepoke... 这一现象值得深思!wepoker底牌透视,奇迹手游脚本辅助全自动,方式教程(有挂详细)1.奇迹手游脚...