netty的简单例子学习记录

netty的简单例子学习记录(若有发现错误的地方希望可以留言指出互相学习哈哈)

传输编码解码参考了https://blog.csdn.net/qq_22200097/article/details/83042424 , 稳 , 稳在哪里 , 稳在可以是传入class的 , 感觉比较舒胡.哈哈

例子主要是实现server和client的通讯 , 传输pojo对象

涉及的类先说下

NormalServernetty服务端
NormalServerHandler  extends ChannelInboundHandlerAdapter 
NormalClientnetty客户端
NormalClientHandler  extends ChannelInboundHandlerAdapter 
RpcDecoder extends ByteToMessageDecoder解码(为何是类名是Rpc,因为我主要是想用netty实现rpc异步调用哈哈)
RpcEncoder extends MessageToByteEncoder编码
  

RpcDecoder

import java.util.List;

import com.alibaba.fastjson.JSON;

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

public class RpcDecoder extends ByteToMessageDecoder {
    //目标对象类型进行解码
    private Class<?> target;
    public RpcDecoder(Class target) {
        this.target = target;
    }
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() < 4) { //不够长度丢弃
            return;
        }
        in.markReaderIndex(); //标记一下当前的readIndex的位置
        int dataLength = in.readInt(); // 读取传送过来的消息的长度。ByteBuf 的readInt()方法会让他的readIndex增加4
 
        if (in.readableBytes() < dataLength) { //读到的消息体长度如果小于我们传送过来的消息长度,则resetReaderIndex. 这个配合markReaderIndex使用的。把readIndex重置到mark的地方
            in.resetReaderIndex();
            return;
        }
        byte[] data = new byte[dataLength];
        in.readBytes(data);
 
        Object obj = JSON.parseObject(data, target); //将byte数据转化为我们需要的对象
        out.add(obj);
    }
}

RpcEncoder

import java.util.List;

import com.alibaba.fastjson.JSON;

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

public class RpcDecoder extends ByteToMessageDecoder {
    //目标对象类型进行解码
    private Class<?> target;
    public RpcDecoder(Class target) {
        this.target = target;
    }
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() < 4) { //不够长度丢弃
            return;
        }
        in.markReaderIndex(); //标记一下当前的readIndex的位置
        int dataLength = in.readInt(); // 读取传送过来的消息的长度。ByteBuf 的readInt()方法会让他的readIndex增加4
 
        if (in.readableBytes() < dataLength) { //读到的消息体长度如果小于我们传送过来的消息长度,则resetReaderIndex. 这个配合markReaderIndex使用的。把readIndex重置到mark的地方
            in.resetReaderIndex();
            return;
        }
        byte[] data = new byte[dataLength];
        in.readBytes(data);
 
        Object obj = JSON.parseObject(data, target); //将byte数据转化为我们需要的对象
        out.add(obj);
    }
}

NormalServerHandler

channelRead方法是接收到客户端发过来的消息 , 我直接转成User是因为在客户端编码User后发过来 , 并且在服务端解码User转成User

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import xuyingwx.netty.example.pojo.ResponseData;
import xuyingwx.netty.example.pojo.User;

public class NormalServerHandler  extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
        String userStr = ((User)msg).toString();
        System.out.println("server收到:"+userStr);
        ResponseData res = new ResponseData();
        res.setSuccess(true);
        res.setData(userStr);
        ctx.writeAndFlush(res);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}
 

NormalServer

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 io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import xuyingwx.netty.example.normal.decoder.RpcDecoder;
import xuyingwx.netty.example.normal.encoder.RpcEncoder;
import xuyingwx.netty.example.pojo.ResponseData;
import xuyingwx.netty.example.pojo.User;

public class NormalServer {
    public static void main(String[] args) {
        int port = 8080;
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(
//                            //如果不使用ObjectDecoder时https://blog.csdn.net/qq_22200097/article/details/83042424
//                            //添加对象解码器 负责对序列化POJO对象进行解码 设置对象序列化最大长度为1M 防止内存溢出
//                              //设置线程安全的WeakReferenceMap对类加载器进行缓存 支持多线程并发访问  防止内存溢出 
//                             new ObjectDecoder(
//                                     1024*1024,
//                                     ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())
//                                     ),
//                             new ObjectEncoder(),
                             new RpcDecoder(User.class), // 解码客户端发送来的User
                             new RpcEncoder(ResponseData.class), // 编码返回对象再发送会客户端
                             new NormalServerHandler()
                     );
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
    
            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); // (7)
    
            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        }catch (Exception e) {
            
        }finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

NormalClientHandler

channelActive连上server后会进入这个方法 , 这里是连上server后会直接发送一个User给服务端

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import xuyingwx.netty.example.pojo.ResponseData;
import xuyingwx.netty.example.pojo.User;

public class NormalClientHandler  extends ChannelInboundHandlerAdapter{
    private ChannelHandlerContext ctx;
    @Override
    public void channelActive(final ChannelHandlerContext ctx) { // (1)
        System.out.println("进入channelActive");
        User user = new User();
        user.setId("1");
        user.setName("nameasd");
        ChannelFuture f = ctx.writeAndFlush(user);
        System.out.println("准备编码");
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
        ResponseData responseData = (ResponseData)msg;
        System.out.println("client收到:"+responseData);
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
    
    public void send() {
        User user = new User();
        user.setId("1");
        user.setName("nameasd");
        ChannelFuture f = ctx.writeAndFlush(user);
    }
}

NormalClient

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import xuyingwx.netty.example.normal.decoder.RpcDecoder;
import xuyingwx.netty.example.normal.encoder.RpcEncoder;
import xuyingwx.netty.example.pojo.ResponseData;
import xuyingwx.netty.example.pojo.User;

public class NormalClient {
    public static void main(String[] args) throws Exception {
        String host = "localhost";
        int port = 8080;
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
             Bootstrap b = new Bootstrap(); // (1)
                b.group(workerGroup); // (2)
                b.channel(NioSocketChannel.class); // (3)
                b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
                b.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(
//                                //添加对象解码器 负责对序列化POJO对象进行解码 设置对象序列化最大长度为1M 防止内存溢出
//                                 //设置线程安全的WeakReferenceMap对类加载器进行缓存 支持多线程并发访问  防止内存溢出 
//                                new ObjectDecoder(
//                                         1024*1024,
//                                         ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())
//                                         ),
//                                new ObjectEncoder(),
                                new RpcDecoder(ResponseData.class),
                                new RpcEncoder(User.class),
                                new NormalClientHandler()
                        );
                    }
                });
                
                // Start the client.
                ChannelFuture f = b.connect(host, port).sync(); // (5)
                // Wait until the connection is closed.
                f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
        System.out.println("clientmain");
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值