如何编写入门级redis客户端
概述
Redis是开源的、基于内存的数据结构存储系统,可用作数据库、缓存以及消息代理方面。Redis支持许多种数据结构,并内置了丰富的诸如冗余、脚本、事务、持久化等功能,深受业界喜爱,被各种业务系统广泛使用。为了方便使用,Redis官网推荐了针对各种编程语言的多种客户端,支持java、c#、python、c++等主流编程语言。那么大家会问,既然Redis客户端已经这么丰富了,为什么还要尝试自己编写客户端?我的看法是,知己知彼,自己尝试制作Redis客户端,不仅可以加深对Redis的了解,而且可以通晓Redis客户端的原理,为今后的更好地使用、乃至定制改造Redis作好充分准备。
知识准备
要想亲自开发Redis客户端,需要以下知识: 1、网络编程基础 2、熟悉Redis协议 3、了解Redis的基本操作 另外文中的例子将会采用java编写,因此最好有基本的java编程知识。
面向对象
Redis Protocal
Redis协议被称为:RESP (REdis Serialization Protocol),客户端通过TCP协议连接到客户端的6379端口(默认端口)。 RESP协议是在Redis1.2中引入的,不过现在已经是Redis2.0中的标准协议了。所以你应该再Redis客户端中实现这个协议。
RESP描述
RESP其实是一个序列化协议,支持简单字符串、错误、整数、整块字符串和数组。数据类型依赖头文字,分别表示如下: 简单字符串的头文字是“+” 错误的头文字是“-” 整数的头文字是“:” 整块字符串的头文字是“$” 数组的头文字是“*”
RESP在请求-响应模型中的用法
-客户端向Redis服务器发送命令,命令的格式是仅以RESP整块字符串构成的数组。。 -服务器端根据命令的结果,选择适宜的一种RESP类型返回
简单字符串 简单字符串是以半角加号开头,后跟随着不含回车换行的字符串,然后以回车换行结尾。 举例如下:+OKrn 简单字符串是非二进制安全的,如果需要二进制安全,可使用“整块字符串”。
错误 错误和简单字符串类似,但头文字换成半角减号了。后面跟随的文字,可以视为错误消息内容。 举例如下:
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value
整数 整数与简单字符串类似,头文字为半角冒号。 举例如下:
:0rn
:1000rn
整块字符串 整块字符串可以用来标示二进制安全的、最大512MB长度的字符串。它以$符号开头,后跟随实际字符串长度,以回车换行结尾,后跟随实际字符串,再最终以回车换行结尾。 举例如下:
$6rnfoobarrn
空字符串表现形式如下:$0rnrn
nil表现形式如下:$-1rnrn
数组 数组以半角星号开头,后接数组中元素个数,然后以回车换行结尾,然后后接各个元素。 举例如下:
空数组:*0rn
包含两个整块字符串的数组:*2rn$3rnfoorn$3rnbarrn
包含三个整数的数组:*3rn:1rn:2rn:3rn
Redis客户端代码实现
要实现和Redis服务端通信,首先需要与Redis服务端建立TCP通信连接,然后使用上述的RESP协议,将想要执行的Redis命令发送至服务端,并等待服务端响应,然后接收到响应结果,展示给用户。
以下代码实现了一个简单的获取info的操作。
public class App
{
public static void main( String[] args )
{
//定义redis服务端默认端口
int port = 6379;
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
try {
//创建tcp连接
socket = new Socket("localhost", port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
//传送info命令
//客户端向Redis服务器发送命令,以RESP整块字符串数组的形式
out.println("*1rn$4rninforn");
System.out.println("Redis command wat sent successfully.");
//接收服务器的回复
CharBuffer response = CharBuffer.allocate(1024);
int readedLen = in.read(response);
String responseBody = response.flip().toString();
//输出服务器的回复
System.out.println(responseBody);
}
catch(Exception e) {
e.printStackTrace();
}
finally {
//最后关闭相关的流
if (out != null){
out.close();
out = null;
}
if (in != null) {
try {
in.close();
}
catch(IOException e){
e.printStackTrace();
}
in = null;
}
if (socket != null) {
try {
socket.close();
}
catch(IOException e){
e.printStackTrace();
}
socket = null;
}
}
}
}
运行后,系统将会在命令行界面输出info的执行结果。
- 《Redis设计与实现》读书笔记(三十五) ——Redis 二进制位数组及SWAR汉明重量算法
- Android TabWidget底部显示
- 《Redis设计与实现》读书笔记(三十六) ——Redis 慢查询日志实现
- 概率学中的随机变量与分布
- 神马?SQL竟然可以解脑筋急转弯的题目?
- android中一些特殊字符(如:←↑→↓等箭头符号)的Unicode码值
- 基于SpringBoot的任务管理平台v1.0正式发布
- 大数据系统的Lambda架构
- AKKA中的事件流
- Java初涉感悟
- Android 6.0 Permission权限与安全机制
- SpringBoot工作机制
- Android权限管理PermissionsDispatcher2.3.2使用+原生6.0权限使用
- SpringBoot中的IoC
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Tomcat在idea中乱码
- Typecho博客开启gizp压缩
- SpringBoot日志功能
- JavaWeb使用response的中文乱码问题
- 《机器学习》-- 第六章 支持向量机
- Java并发编程的艺术[1]
- Java并发编程的艺术[2]
- Spark UDF实现demo
- Spring boot 开发中热部署配置(只需两步)
- 纯Java搭建SpringMVC项目
- 整理一下Spring整合Junit4单元测试方法
- spring 到底注入接口还是实现类?
- 韩松团队新作 | MCUNet | IoT设备+微型机器学习时代已经到来了
- SpringMVC在web.xml中的配置(引入springmvc)
- springmvc使用DELETE|PUT请求