iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >自己动手写一个能操作redis的客户端
  • 178
分享到

自己动手写一个能操作redis的客户端

2023-06-05 06:06:12 178人浏览 八月长安
摘要

作者:孤独烟 来源:微信订阅号(程序员孤独烟)原文链接:https://mp.weixin.qq.com/s/IBynkex-FHhvJ3tmizvJhA 引言redis大家在项目中经常会使用到。官网也提供了多语言的客户端供大家操作Redi

作者:孤独烟 来源:微信订阅号(程序员孤独烟)

原文链接:https://mp.weixin.qq.com/s/IBynkex-FHhvJ3tmizvJhA

引言

redis大家在项目中经常会使用到。官网也提供了多语言的客户端供大家操作Redis,如下图所示

自己动手写一个能操作redis的客户端

但是,大家有思考过,这些语言操作redis背后的原理么?其实,某些大神会说

只要按照redis的协议,发送指定数据给redis,监听返回值即可。


确实,本质原理就是如上面那句话所说。博主也是以这种思路,去看了一下JAVA端的开源组件jedis的源码,然后取其精华,写了一个段能操作redis的demo,希望大家能有所收获。


jedis的GitHub地址为:
https://github.com/xetorthio/jedis


有兴趣的童鞋,也可以自行去阅读。需要说明的是,这毕竟不是源码分析系列文章,不是带你去看jedis的源码。只是借鉴思路,写一个能操作redis的程序。

正文

首先,我先说一下操作思路,如下图所示

自己动手写一个能操作redis的客户端

说明一下,上面的第四步,就是我们自己要写的操作redis的小demo。

1、先写一个Socket监听6379端口

这个程序很easy,度娘一下出来一大把

import java.io.IOException;import java.io.InputStreamReader;import java.io.Reader;import java.net.ServerSocket;import java.net.Socket;public class SocketServer {    public static void main(String[] args) throws IOException {        ServerSocket server = new ServerSocket(6379);        Socket socket = server.accept();        byte[] chars = new byte[64];        socket.getInputStream().read(chars);        System.out.println(new String(chars));    }}

2、采用开源客户端,操作一次redis

我这里用的是JAVA语言的jedis,大家自己也可以用其他的任意语言组件,目的是为了采集客户端在操作redis时,发送出的数据

import redis.clients.jedis.Jedis;public class RedisTest {    public static void main(String[] args) {        Jedis jedis = new Jedis("127.0.0.1", 6379);        jedis.set("eat", "I want to eat");    }}

3、看看socket监听到的数据

在这里运行一下第二步的代码,查看第一步的代码输出的数据,如下所示

*3$3SET$3eat$13I want to eat

那么,这组数据是什么含义呢?
我们去官网进行查询。原来,redis的客户端和服务端采取了一种RESP协议。相应文档地址如下
Https://redis.io/topics/protocol
RESP设计巧妙,它的前景在于下面三个方面:

  • Simple to implement.

  • Fast to parse.

  • Human readable.

那么+、-、*、:、$这些符号是什么意思呢?
官网有这么一段话

In RESP, the type of some data depends on the first byte:  For Simple Strings the first byte of the reply is "+"
 For Errors the first byte of the reply is "-"
 For Integers the first byte of the reply is ":"
 For Bulk Strings the first byte of the reply is "$"
 For Arrays the first byte of the reply is "*"
 Additionally RESP is able to represent a Null value using a special variation of Bulk Strings or Array as specified later.
 In RESP different parts of the protocol are always terminated with "\r\n" (CRLF).

翻译过来
(1)简单字符串Simple Strings, 以 "+"加号 开头
(2)错误Errors, 以"-"减号 开头
(3)整数型Integer, 以 ":" 冒号开头
(4)大字符串类型Bulk Strings, 以 "$"美元符号开头,长度限制512M
(5)组类型Arrays,以 "*"星号开头
并且,协议的每部分都是以 "\r\n" (CRLF) 结尾的。

OK,那我们刚才的那一串的数据的意思就是(没有看到""\r\n",是因为已经转义了,所以无法看到):

*3   数组包含3个元素,分别是SET、eat、I want to eat$3   是一个字符串,且字符串长度为3SET  字符串的内容$3   是一个字符串,且字符串长度为3eat  字符串的内容$13  是一个字符串,且字符串长度为13I want to eat 字符串的内容

提问,如果是get命令,那么传输的RESP的内容长什么样?
比如有一个命令get eat,那么此时的内容如下所示

*2$3GET$3eat

没有\r\n是因为已经转义了,所以没看到。其他的命令,可以自行测试

4、尝试构造一样的数据操作redis

OK,经过上面的铺垫。我们如果要对redis做一个set操作,则构造set命令的RESP协议内容,并且利用socket编程,将这串内容发送给redis即可。这里用java的socket编程实现,用其他语言也是一样的。
我们有一个类 RedisClient.java
代码如下

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.net.UnknownHostException;public class RedisClient {    private Socket socket;                                         private OutputStream outputStream;    private InputStream inputStream;    public RedisClient(String host, int port){        try {            this.socket = new Socket(host,port);            this.outputStream = this.socket.getOutputStream();            this.inputStream = this.socket.getInputStream();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    public String set(final String key, String value) {        StringBuilder sb = new StringBuilder();        //虽然输出的时候,会被转义,然而我们传送的时候还是要带上\r\n        sb.append("*3").append("\r\n");        sb.append("$3").append("\r\n");        sb.append("SET").append("\r\n");        sb.append("$").append(key.length()).append("\r\n");        sb.append(key).append("\r\n");        sb.append("$").append(value.length()).append("\r\n");        sb.append(value).append("\r\n");        byte[] bytes= new byte[1024];        try {            outputStream.write(sb.toString().getBytes());            inputStream.read(bytes);        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return new String(bytes);    }    public static void main(String[] args) {        RedisClient redisClient = new RedisClient("127.0.0.1", 6379);        String result = redisClient.set("eat", "please eat");        System.out.println(result);         }}

上面的public String set(final String key, String value)方法中,显示了,我们假如需要对redis进行set操作,需要传输的RESP协议的内容。记住,一定要带\r\n字符作为结尾
OK,运行上述代码,你会发现你可以往redis中set数据了,并且控制台输出如下

+OK

提问,你自己会封装get命令么?

总结

本文以一种循序渐进的方式带领大家写了一个能操作redis的demo,希望大家有所收获。

--结束END--

本文标题: 自己动手写一个能操作redis的客户端

本文链接: https://www.lsjlt.com/news/241625.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++ 生态系统中流行库和框架的贡献指南
    作为 c++++ 开发人员,通过遵循以下步骤即可为流行库和框架做出贡献:选择一个项目并熟悉其代码库。在 issue 跟踪器中寻找适合初学者的问题。创建一个新分支,实现修复并添加测试。提交...
    99+
    2024-05-14
    框架 c++ 流行库 git
  • C++ 生态系统中流行库和框架的社区支持情况
    c++++生态系统中流行库和框架的社区支持情况:boost:活跃的社区提供广泛的文档、教程和讨论区,确保持续的维护和更新。qt:庞大的社区提供丰富的文档、示例和论坛,积极参与开发和维护。...
    99+
    2024-05-14
    生态系统 社区支持 c++ overflow 标准库
  • c++中if elseif使用规则
    c++ 中 if-else if 语句的使用规则为:语法:if (条件1) { // 执行代码块 1} else if (条件 2) { // 执行代码块 2}// ...else ...
    99+
    2024-05-14
    c++
  • c++中的继承怎么写
    继承是一种允许类从现有类派生并访问其成员的强大机制。在 c++ 中,继承类型包括:单继承:一个子类从一个基类继承。多继承:一个子类从多个基类继承。层次继承:多个子类从同一个基类继承。多层...
    99+
    2024-05-14
    c++
  • c++中如何使用类和对象掌握目标
    在 c++ 中创建类和对象:使用 class 关键字定义类,包含数据成员和方法。使用对象名称和类名称创建对象。访问权限包括:公有、受保护和私有。数据成员是类的变量,每个对象拥有自己的副本...
    99+
    2024-05-14
    c++
  • c++中优先级是什么意思
    c++ 中的优先级规则:优先级高的操作符先执行,相同优先级的从左到右执行,括号可改变执行顺序。操作符优先级表包含从最高到最低的优先级列表,其中赋值运算符具有最低优先级。通过了解优先级,可...
    99+
    2024-05-14
    c++
  • c++中a+是什么意思
    c++ 中的 a+ 运算符表示自增运算符,用于将变量递增 1 并将结果存储在同一变量中。语法为 a++,用法包括循环和计数器。它可与后置递增运算符 ++a 交换使用,后者在表达式求值后递...
    99+
    2024-05-14
    c++
  • c++中a.b什么意思
    c++kquote>“a.b”表示对象“a”的成员“b”,用于访问对象成员,可用“对象名.成员名”的语法。它还可以用于访问嵌套成员,如“对象名.嵌套成员名.成员名”的语法。 c++...
    99+
    2024-05-14
    c++
  • C++ 并发编程库的优缺点
    c++++ 提供了多种并发编程库,满足不同场景下的需求。线程库 (std::thread) 易于使用但开销大;异步库 (std::async) 可异步执行任务,但 api 复杂;协程库 ...
    99+
    2024-05-14
    c++ 并发编程
  • 如何在 Golang 中备份数据库?
    在 golang 中备份数据库对于保护数据至关重要。可以使用标准库中的 database/sql 包,或第三方包如 github.com/go-sql-driver/mysql。具体步骤...
    99+
    2024-05-14
    golang 数据库备份 mysql git 标准库
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作