作者:孤独烟

来自:http://rjzheng.cnblogs.com/

引言

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


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

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

确实,本质原理就是如上面那句话所说。博主也是以这种思路,去看了一下JAVA端的开源组件jedis的源码,然后取其精华,写了一个段能操作redis的demo,希望大家能有所收获。
jedis的github地址为:
https://github.com/xetorthio/jedis
有兴趣的童鞋,也可以自行去阅读。需要说明的是,这毕竟不是源码分析系列文章,不是带你去看jedis的源码。只是借鉴思路,写一个能操作redis的程序。

正文

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


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

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

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

 1import java.io.IOException; 2import java.io.InputStreamReader; 3import java.io.Reader; 4import java.net.ServerSocket; 5import java.net.Socket; 6 7public class SocketServer { 8 9    public static void main(String[] args) throws IOException {10        ServerSocket server = new ServerSocket(6379);11        Socket socket = server.accept();12        byte[] chars = new byte[64];13        socket.getInputStream().read(chars);14        System.out.println(new String(chars));15    }16}

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

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

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

3、看看socket监听到的数据

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

1*32$33SET4$35eat6$137I 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 " " (CRLF).

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

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

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

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

1*22$33GET4$35eat

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

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

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

 1import java.io.IOException; 2import java.io.InputStream; 3import java.io.OutputStream; 4import java.net.Socket; 5import java.net.UnknownHostException; 6public class RedisClient { 7    private Socket socket;                                      8    private OutputStream outputStream; 9    private InputStream inputStream;1011    public RedisClient(String host, int port){12        try {13            this.socket = new Socket(host,port);14            this.outputStream = this.socket.getOutputStream();15            this.inputStream = this.socket.getInputStream();16        } catch (IOException e) {17            // TODO Auto-generated catch block18            e.printStackTrace();19        }20    }2122    public String set(final String key, String value) {23        StringBuilder sb = new StringBuilder();24        //虽然输出的时候,会被转义,然而我们传送的时候还是要带上25        sb.append("*3").append("
");26        sb.append("$3").append("
");27        sb.append("SET").append("
");28        sb.append("$").append(key.length()).append("
");29        sb.append(key).append("
");30        sb.append("$").append(value.length()).append("
");31        sb.append(value).append("
");32        byte[] bytes= new byte[1024];33        try {34            outputStream.write(sb.toString().getBytes());35            inputStream.read(bytes);36        } catch (IOException e) {37            // TODO Auto-generated catch block38            e.printStackTrace();39        }40        return new String(bytes);41    }4243    public static void main(String[] args) {44        RedisClient redisClient = new RedisClient("127.0.0.1", 6379);45        String result = redisClient.set("eat", "please eat");46        System.out.println(result);     47    }48}

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

1+OK

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

总结

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

长按订阅同类文章

一起搬砖的点个赞

自己动手写一个能操作redis的客户端相关推荐

  1. java 手编线程池_死磕 java线程系列之自己动手写一个线程池

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...

  2. 学习较底层编程:动手写一个C语言编译器

    动手编写一个编译器,学习一下较为底层的编程方式,是一种学习计算机到底是如何工作的非常有效方法. 编译器通常被看作是十分复杂的工程.事实上,编写一个产品级的编译器也确实是一个庞大的任务.但是写一个小巧可 ...

  3. 自己动手写一个 strace

    这次主要分享一下一个动手的东西,就是自己动手写一个 strace 工具. 用过 strace 的同学都知道,strace 是用来跟踪进程调用的 系统调用,还可以统计进程对 系统调用 的统计等.stra ...

  4. java 同步锁_死磕 java同步系列之自己动手写一个锁Lock

    问题 (1)自己动手写一个锁需要哪些知识? (2)自己动手写一个锁到底有多简单? (3)自己能不能写出来一个完美的锁? 简介 本篇文章的目标一是自己动手写一个锁,这个锁的功能很简单,能进行正常的加锁. ...

  5. 自己动手写一个推荐系统,推荐系统小结,推荐系统:总体介绍、推荐算法、性能比较, 漫谈“推荐系统”, 浅谈矩阵分解在推荐系统中的应用...

    自己动手写一个推荐系统 废话: 最近朋友在学习推荐系统相关,说是实现完整的推荐系统,于是我们三不之一会有一些讨论和推导,想想索性整理出来. 在文中主要以工程中做推荐系统的流程着手,穿插一些经验之谈,并 ...

  6. 动手写一个Caffe层:矩阵相乘Matmul

    动手写一个Caffe层:矩阵相乘Matmul 背景 实现 前向传播实现 后向传播实现 backward推导 小结 背景 最近在研究chainer网络的caffe实现,顺便也体验一下caffe.对于ca ...

  7. 自己动手写一个操作系统——MBR(2)

    前言 上篇文章<自己动手写一个操作系统--MBR(1)>,我们使用 dd 生成了一个 512 字节的镜像,并用 vim 将其最后两个字节修改成了 55 AA,以此来完成了 MBR 的构建. ...

  8. 自己动手写一个简单的bootloader

    自己动手写一个简单的bootloader 15年10月31日19:44:27 (一) start.S 写这一段代码前,先要清楚bootloader开始的时候都做什么了.无非就是硬件的初始化,我们想要写 ...

  9. 自己动手写一个分库分表中间件(三)数据源路由实现

    相关文章: 自己动手写一个分库分表中间件(一)思考 自己动手写一个分库分表中间件(二)数据源定义和分片代理层设计 排查项目中读写分离失效原因 小议 Java 内省机制 注:本文内容暂不涉及事务相关的问 ...

最新文章

  1. 世界人口钟实时数据_中美面积人口数据对比,2020年8月,值得了解的细节
  2. ccf-csp #201709-2 公共钥匙盒
  3. 双指针解决数组排序问题
  4. groupby的用法
  5. SpringMVC常用的视图接口分类及实现类
  6. ceph中查看一个rbd的image的真实存储位置
  7. Boost.Bind的基础使用
  8. Google回应全球宕机:磁盘满了;摩拜App昨晚正式停止服务;Docker Desktop 3.0.0发布|极客头条...
  9. VS2015 LINK : warning LNK4068: 未指定 /MACHINE;默认设置为 X86
  10. vs13配置matlab,VS配置电脑系统变量(VS2013+matlab2018a)
  11. oracle 限制条数的查询
  12. Unsupervised Domain Adaptation by Backpropagation
  13. iOS数据持久化设计探讨(NSCache,PINCache,YYCache,CoreData,FMDB,WCDB,Realm)
  14. 《手Q Android线程死锁监控与自动化分析实践》
  15. 今日头条校招真题——字典序
  16. Scratch 3.0建站指南(一)
  17. 蚂蚁调度AntJob-分布式任务调度系统
  18. Python(1)自动发送邮件
  19. TopCoder教程
  20. 2022年100家公司真实的面试题笔试题汇总

热门文章

  1. UVA699 下落的树叶 The Falling Leaves(二叉树的递归遍历建树)
  2. python0b1010_笔记-python-字符串格式化-format()
  3. es文件ftp服务器,es文件夹 ftp服务器
  4. Aggregation,Composition和Dependency
  5. Linux编写一个C程序HelloWorld
  6. ArcGIS Server 内存占用相关
  7. could not load inserted library: /usr/lib/libgmalloc.dylib
  8. yum源及yum仓库服务搭建讲解
  9. 分享:Arcadia 0.12.1 发布,Ruby 集成开发环境
  10. 年薪50万,副职级别!注册安全工程师的前途如此光明?