Netty学习——入门实例之实现丢弃协议和Echo协议

Demo使用的Netty版本:

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.74.Final</version>
</dependency>

丢弃协议(Discard Protocol)

什么是丢弃协议?

丢弃协议是很简单的协议,它是一种丢弃任何收到的数据并且不会有任何响应的协议。下面通过Netty来实现。

编写处理收到数据时的处理类

package vip.huhailong.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        try{
            while (buf.isReadable()){
                System.out.print((char)buf.readByte());
                System.out.flush();
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
代码解析
  1. DiscardServerHandler类继承了ChannelInboundHandlerAdapter,它是ChannelInboundHandler接口的一个实现。ChannelInboundHandler提供了可以覆盖各种事件处理的方法。
  2. channelRead()方法是重写的一个方法,从客户端接收到新的数据时就会调用该方法,上面代码中在接收消息后会打印该消息。
  3. 要实现丢弃协议需要丢弃收到的数据,ByteBuf是一个引用计数对象,必须通过release()方法显示的释放,通常的做法是使用try/finally块种在try中处理完消息后在finally中通过ReferenceCountUtil.release(Object msg)方法来释放。
  4. exceptionCaught()在Netty由于I/O或处理时间时抛出异常时被调用,上面代码中在发生异常时会打印堆栈信息以及关闭关联的Channel。

编写启动服务

package vip.huhailong.server;

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;
import vip.huhailong.handler.DiscardServerHandler;

public class DiscardServer {

    private int port;

    public DiscardServer(int port){
        this.port = port;
    }

    public void run() throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try{
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new DiscardServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true);
            ChannelFuture future = b.bind(port).sync();
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new DiscardServer(port).run();
    }
}
代码解析
  1. NioEventLoopGroup是一个处理I/O操作的多线程事件循环,Netty为不同类型的传输提供了各种EventLoopGroup实现,在这个例子中为了实现一个服务端的应用程序,因此需要使用俩个NioEventLoopGroup,第一个,bossGroup用来接受传入的连接。第二个,workerGroup是当bossGroup一旦接受连接并将接受的连接注册到worker中就会处理接受连接的流量。使用多少线程以及它们如何映射到创建的Channel取决于EventLoopGroup的实现。
  2. ServerBootstrap是一个设置服务器的辅助类,它可以简化通过Channel这种繁琐的方式创建服务器的过程。
  3. 上面代码中channel(NioServerSocketChannel.class)是通过指NioServerSocketChannel类来实例化一个新的Channel来接受传入的连接。
  4. ChannelInitializer是一个特殊的处理程序,目的是用来帮助用户配置新的Channel。像上述代码中我们添加了自己的DiscardServerHanlder类来实现丢弃协议的处理。
  5. option()方法和childOption()方法的区别,option()方法用于接受传入NioServerSocketChannelchildOption()用于父ServerChannel接受的Channels,在上面的程序中为NioSocketChannel

运行结果

在这里插入图片描述

Echo协议

什么是Echo协议?

echo协议和上面的丢弃协议唯一的区别就是当服务器收到消息后会将消息返回客户端,它的实现也和丢弃协议一样很简单,只需要在上面的丢弃协议代码中简单的修改就可以实现。

修改处理类

将丢弃协议服务器中的DiscardServerHandler中的代码修改为如下:

package vip.huhailong.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

public class DiscardServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.write(msg);
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

主要是修改了方法channelRread,删除之前方法中的代码,添加ChannelHandlerContext中的write和flush来实现echo协议。

代码解析
  1. ChannelHandlerContext对象提供了各种操作来帮助我们触法各种I/O事件和操作。这里我们调用write(Object)方法是将接收到的消息逐字写入。请注意,这里没有像丢弃协议那样显示的进行释放,这是因为当消息被写入网络时,Netty会自动为我们释放它。
  2. ctx.write(Object)不会将消息写入通道中,它是被缓冲到内部,然后由ctx.flush()方法刷新到通道中,或者我们也可以直接调用方法ctx.writeAndFlush(msg),效果和上面是一样的。

当我们再次通过telnet测试时会发现发送的内容会回显到telnet客户端中。表明echo协议成功。

参考链接:https://netty.io/wiki/user-guide-for-4.x.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@胡海龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值