Netty -- 应用场景 -- 基本构成

1、配置依赖

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>5.0.0.Alpha2</version>
</dependency>

2、服务端

  • ChannelInitializer 中,也是一个 Handler,重写了 channelRegistered 方法,在 channel 注册的时候,调用 initChannel 方法后将自己从 pipeline 中移除
  • ChannelHandlerAdapter 中,实现了简单的将事件传递给下一个 ChannelHandler 方法的实现,使用的类似 fire 开头的方法,其中 In 和 Out 的继承类,没有重写任何方法
  • ChannelHandlerContext 主要用于写出站数据,两种写的方式:直接写到 Channel 和 写到 ChannelHandlerContext 对象中
package com.sample.modules.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;

public class NettyServer {

    /**
     * 监听服务器ip和端口
     */
    private String host;
    private int port;

    public NettyServer(String host, int port){
        this.host = host;
        this.port = port;
    }

    public void listen() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //添加业务逻辑处理单元
                        }
                    });

            ChannelFuture f = b.bind(new InetSocketAddress(host, port)).sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception{
        new NettyServer("localhost", 8000).listen();
    }
}

3、客户端

package com.sample.modules.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class NettyClient {

    private String host;
    private int port;

    public NettyClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public  void start()  {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .option(ChannelOption.SO_KEEPALIVE,true)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //添加业务逻辑处理单元
                        }
                    });

            ChannelFuture f = b.connect(host,port);
            f.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new NettyClient("localhost", 8000).start();
    }
}

4、业务逻辑处理单元

// 出站10
pipeline.addLast("server10", new ChannelOutboundHandlerAdapter(){
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("out 10");
        // 最终将数据发送出去
        ctx.writeAndFlush(msg);
    }
});

// 出站11
pipeline.addLast("server11", new ChannelOutboundHandlerAdapter(){
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("out 11");
        // 出站数据继续传递
        ctx.writeAndFlush(msg);
    }
});

// 入站1
pipeline.addLast("server1", new SimpleChannelInboundHandler<ByteBuf>(){
    @Override
    protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("in 1: "+msg.toString(CharsetUtil.UTF_8));
        // 入站数据继续传递
        ReferenceCountUtil.retain(msg);
        ctx.fireChannelRead(msg);
        
        // 从当前 handler 往前传递,经过出站11和出站10
        ctx.writeAndFlush(Unpooled.copiedBuffer("aa".getBytes()));
        // 从尾部 handler 往前传递,经过出站12、出站11和出站10
        ctx.channel().writeAndFlush(Unpooled.copiedBuffer("aa".getBytes()));
    }
});

// 出站12
pipeline.addLast("server12", new ChannelOutboundHandlerAdapter(){
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("out 12");
        // 出站数据继续传递
        ctx.writeAndFlush(msg);
    }
});

// 入站2
pipeline.addLast("server2", new SimpleChannelInboundHandler<ByteBuf>(){
    @Override
    protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("in 2: "+msg.toString(CharsetUtil.UTF_8));
        // 入站数据继续传递
        ReferenceCountUtil.retain(msg);
        ctx.fireChannelRead(msg);
    }
});

// 入站3
pipeline.addLast("server3", new SimpleChannelInboundHandler<ByteBuf>(){
    @Override
    protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("in 3: "+msg.toString(CharsetUtil.UTF_8));
    }
});

5、注意事项

  • 如果一个消息被消费或丢弃了,并且没有传递给 pipeline 中的下一个 handler,那么需要调用 ReferenceCountUtil.release(msg) 进行释放
  • 引用计数: 一旦消息被编码或解码,就会被 ReferenceCountUtil.release(message) 调用自动释放,如果需要保留引用以便稍后使用,那么可以调用 ReferenceCountUtil.retail(message) 增加该引用计数,防止该消息被释放

6、解码器 -- ByteToMessageDecoder

  • 将字节解码为消息
  • 由于不知道远程节点是否会一次性的发完一个完整的数据,所有需要对入站数据进行缓冲,直到数据准备好
package com.vim.test.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

public class ToIntegerDecoder extends ByteToMessageDecoder{
    
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> list) throws Exception {
        if(in.readableBytes() >= 4){
            list.add(in.readInt());
        }
    }
}

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值