Netty实战:模拟Redis的客户端

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Netty实战:模拟Redis的客户端

Netty:模拟Redis的客户端

因为redis是部署在服务器上的 我们只需要模拟客户端发送请求即可所以只需要编写客户端的代码就可以了

前置知识

编写前我们需要知道 redis的请求规范

Redis 的通信 是需要遵循 RESP 协议的

例子:

set hello 123
*3\r\n $3 \r\n set \r\n hello \r\n 123

建立 channel 通道后 发送命令给服务端 此时是写数据【输出】 在出战handler里增加逻辑 当接受响应后 此时数据需要【输入】 存入栈 handler 中 在入栈handler 里增加逻辑

Netty中 Redis 命令对应的类型

  • 单行
  • 错误
  • 整形数字
  • 批量回复
  • 多个批量回复

客户端

我们只需要编写客户端。请求搭建redis的服务器接受和传输数据即可就可以了

客户端还是常见的写法

public class RedisClient {
    private static final String HOST = "xxxxxxxxx";
    private static final int PORT = 6379;
    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(bossGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        //  调用netty 提供的支持netty 协议的编解码器
                        //    RedisBulkStringAggregator 和 RedisarrayAggregator 是协议中两种特殊格式的聚合器
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new RedisDecoder());
                        pipeline.addLast(new RedisBulkStringAggregator());
                        pipeline.addLast(new RedisArrayAggregator());
                        pipeline.addLast(new RedisEncoder());
                        // 我们自己的处理器
                        pipeline.addLast(new RedisClientHandler());
                    }
                });
        try {
            ChannelFuture syncFuture = bootstrap.connect(HOST, PORT).sync();
            System.out.println("enter redis commands");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            for (; ; ) {
                String input = bufferedReader.readLine();
                //退出任务
                if ("quit".equals(input)) {
                    syncFuture.channel().close().sync();
                    break;
                }
                syncFuture.channel().writeAndFlush(input).sync();
            }
            syncFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
        }
    }
}

处理器

因为要读取和写入 所以我们需要集成混合处理器类 : ChannelDuplexHandler

我们需要判断五种请求类型 所以先封装一个类别输出的方法

RedisMessage Netty提供的redis的信息对象,以下五种类型都来自于它

private void printRedisResponse(RedisMessage msg) {
        if (msg instanceof SimpleStringRedisMessage) {
            SimpleStringRedisMessage tmpMsg = (SimpleStringRedisMessage) msg;
            System.out.println(tmpMsg.content());
        } else if (msg instanceof ErrorRedisMessage) {
            ErrorRedisMessage tmpMsg = (ErrorRedisMessage) msg;
            System.out.println(tmpMsg.content());
        } else if (msg instanceof IntegerRedisMessage) {
            IntegerRedisMessage tmpMsg = (IntegerRedisMessage) msg;
            System.out.println(tmpMsg.value());
        } else if (msg instanceof FullBulkStringRedisMessage) {
            FullBulkStringRedisMessage tmpMsg = (FullBulkStringRedisMessage) msg;
            if (tmpMsg.isNull()) {
                return;
            }
            System.out.println(tmpMsg.content().toString(CharsetUtil.UTF_8));
        } else if (msg instanceof ArrayRedisMessage) {
            ArrayRedisMessage tmpMsg = (ArrayRedisMessage) msg;
            for (RedisMessage child : tmpMsg.children()) {
                printRedisResponse(child);
            }
        }
        // 如果都是不是应该抛出异常
    }

写命令

// 写
    // 出栈handler 的常用方法
    //需要处理redis 命令
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        // 键盘传入的字符串 如 : keys *
        String commandStr = (String) msg;
        // 通过空格来分离出命令
        String[] commandArr = commandStr.split("\\s+");
        // 接受redis 命令的列表  RedisMessag保存命令的内容
        List<RedisMessage> redisMessageList = new ArrayList<>(commandArr.length);
        for (String cmdStr : commandArr) {
            FullBulkStringRedisMessage message = new FullBulkStringRedisMessage(
                    ByteBufUtil.writeUtf8(ctx.alloc(), cmdStr));
            redisMessageList.add(message);
        }
        //将分离的命令 合并成一个完整的命令
        RedisMessage request = new ArrayRedisMessage(redisMessageList);
        //写入通道
        ctx.write(request, promise);
    }

读取命令

// 读取
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    // 此时接受的时候这个值 就是我们存储redismessage 的对象
    RedisMessage redisMessage = (RedisMessage) msg;
    // 返回的结果是不同类型 分开进行处理
    printRedisResponse(redisMessage);
    //    内存管理使用了 引用计数的方式 所以我们需要释放资源
    ReferenceCountUtil.release(redisMessage);
}

演示效果

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
NoSQL Redis 数据安全/隐私保护
Redis 最流行的图形化界面下载及使用超详细教程(带安装包)! redis windows客户端下载
文章提供了Redis最流行的图形化界面工具Another Redis Desktop Manager的下载及使用教程,包括如何下载、解压、连接Redis服务器以及使用控制台和查看数据类型详细信息。
149 6
Redis 最流行的图形化界面下载及使用超详细教程(带安装包)! redis windows客户端下载
|
2月前
|
网络协议 前端开发
netty的TCP服务端和客户端实现
本文介绍了使用Netty框架实现TCP服务端和客户端的步骤,包括添加Netty依赖、编写服务端和客户端的代码,涉及NioEventLoopGroup、ServerBootstrap、Bootstrap、ChannelInitializer等核心组件,以及如何启动服务端监听和客户端连接。
161 4
|
2月前
|
NoSQL Redis 数据库
Redis 图形化界面下载及使用超详细教程(带安装包)! redis windows下客户端下载
文章提供了Redis图形化界面工具的下载及使用教程,包括如何连接本地Redis服务器、操作键值对、查看日志和使用命令行等功能。
143 0
Redis 图形化界面下载及使用超详细教程(带安装包)! redis windows下客户端下载
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:优化百万数据查询的实战经验
【10月更文挑战第13天】 在处理大规模数据集时,传统的关系型数据库如MySQL可能会遇到性能瓶颈。为了提升数据处理的效率,我们可以结合使用MySQL和Redis,利用两者的优势来优化数据查询。本文将分享一次实战经验,探讨如何通过MySQL与Redis的协同工作来优化百万级数据统计。
63 5
|
2月前
使用Netty实现文件传输的HTTP服务器和客户端
本文通过详细的代码示例,展示了如何使用Netty框架实现一个文件传输的HTTP服务器和客户端,包括服务端的文件处理和客户端的文件请求与接收。
46 1
使用Netty实现文件传输的HTTP服务器和客户端
|
2月前
|
NoSQL 网络协议 算法
Redis 客户端连接
10月更文挑战第21天
33 1
|
2月前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
91 2
|
2月前
|
存储 消息中间件 NoSQL
Redis 入门 - C#.NET Core客户端库六种选择
Redis 入门 - C#.NET Core客户端库六种选择
64 8
|
3月前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
3月前
|
缓存 NoSQL 应用服务中间件
Redis实战篇
Redis实战篇