resp
redis客户端使用一个叫做RESP的协议,这里是redis关于此协议的官方界面链接:官网
- 优点:简单好实现,快速进行解析,肉眼可读。

- 传输层这里基于TCP,但和TCP又没有强耦合。

- 请求和响应的模型是一问一答的形式。

- 客户端给服务器发送的是bulk string形式的redis命令,服务器的返回值取决于command的形式,不同的command,返回值不一样。

redis-plus-plus
编写redis客户端服务器,主要使用的是redis-plus-plus库,如果打不开,可以使用watti:redis-plus-plus
- 如果想要安装redis-plus-plus的话,需要先安装hiredis,因为redis-plus-plus是依赖hiredis的
hiredis可以通过源码安装:

- 也可以通过包管理器安装:
bash
apt install libhiredis-dev #Ubuntu下的安装方式
- 接下来安装redis-plus-plus本体:
bash
git clone https://github.com/sewenew/redis-plus-plus.git
cd redis-plus-plus
mkdir build
cd build
cmake ..
make
sudo make install #把库拷贝到系统中
cd ..
- tip:如果没有办法clone,提示GnuTLS recv error (-110): The TLS connection was non-properly terminated,可以使用以下命令。
bash
apt-get install gnutls-bin
git config --global http.sslVerify false
git config --global http.postBuffer 1048576000
- 使用redis-plus-plus链接到redis服务器。
首先需要找到redis++的头文件和静态库文件的位置。

使用ping命令测试一下连通性。
cpp
#include<sw/redis++/redis++.h>
#include<string>
#include<iostream>
using std::cout;
using std::endl;
using std::string;
int main()
{
//创建一个redis对象
sw::redis::Redis redis("tcp://127.0.0.1:6379");
//通过ping让客户端给服务器发一个ping,然后服务器返回一个pong
string result=redis.ping();
cout<<result<<endl;
return 0;
}
- 使用makefile编译文件
cpp
helloworld:helloworld.cc
g++ -o $@ $^ -std=c++17 /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
.PHONY:clean
clean:
rm -f helloworld
#请根据自己的情况选择库路径
这样就跑通了

通用命令
get和set
set
StringView和c++里的string很像,但不可写,所以效率比string高。
OptionalString可以表示非法值/无效值,如果直接使用string来表示,是不太方便表示nil这个值的,如果使用string*来表示,可以通过返回nullptr表示nil,但又涉及到内存归谁管的问题。

cpp
#include<sw/redis++/redis++.h>
#include<string>
#include<iostream>
using std::cout;
using std::endl;
using std::string;
void test(sw::redis::Redis& redis)
{
//清空数据库
redis.flushall();
//使用set指令
redis.set("key1","value1");
redis.set("key2","value2");
redis.set("key3","value3");
}
int main()
{
//创建一个redis对象
sw::redis::Redis redis("tcp://127.0.0.1:6379");
test(redis);
return 0;
}
get

cpp
#include<sw/redis++/redis++.h>
#include<string>
#include<iostream>
using std::cout;
using std::endl;
using std::string;
void test(sw::redis::Redis& redis)
{
//清空数据库
redis.flushall();
//使用set指令
redis.set("key1","value1");
redis.set("key2","value2");
redis.set("key3","value3");
//使用get指令,找存在的key
auto value1=redis.get("key1");
cout<<"value1="<<value1.value()<<endl;
auto value2=redis.get("key2");
cout<<"value2="<<value2.value()<<endl;
auto value3=redis.get("key3");
cout<<"value3="<<value3.value()<<endl;
//找不存在的key
auto value4=redis.get("key4");
cout<<"value4="<<value4.value()<<endl;
}
int main()
{
//创建一个redis对象
sw::redis::Redis redis("tcp://127.0.0.1:6379");
test(redis);
return 0;
}
运行后:key1到key3都是正常的,但key4抛出异常状态,因为key4不存在,value4其实是optional的非法状态,对于非法状态的optional进行取值,就会抛出异常,如果我们想处理这种情况,可以使用try-catch,或者访问value之前判定一下。

exists和del
exists :判断一个元素在不在数据库里面,返回值是long long类型,表示存在的参数类型。

cpp
void test1(sw::redis::Redis& redis)
{
//清空数据库
redis.flushall();
//使用exists
redis.set("key","value");
//如果元素存在
auto ret=redis.exists("key");
cout<<ret<<endl;
//如果元素不存在
ret=redis.exists("key1");
cout<<ret<<endl;
}
int main()
{
//创建一个redis对象
sw::redis::Redis redis("tcp://127.0.0.1:6379");
test1(redis);
return 0;
}

如果我们想判定多个key,可以使用列表。
cpp
void test1(sw::redis::Redis& redis)
{
//清空数据库
redis.flushall();
//使用exists
redis.set("key","value");
redis.set("key1","value1");
redis.set("key2","value2");
ret=redis.exists({"key1","key2","key3"});
cout<<ret<<endl;
}

del :用于删除元素,这里也是可以使用列表同时删除多个key的,返回值表示删除的个数。

cpp
void test1(sw::redis::Redis& redis)
{
//清空数据库
redis.flushall();
//使用exists
redis.set("key","value");
redis.set("key1","value1");
redis.set("key2","value2");
auto ret=redis.exists({"key1","key2","key3"});
cout<<"exists"<<ret<<endl;
ret=redis.del("key");
cout<<"del"<<ret<<endl;
ret=redis.exists({"key1","key2","key"});
cout<<"exists"<<ret<<endl;
ret=redis.del({"key1","key2"});
cout<<"del"<<ret<<endl;
ret=redis.exists({"key1","key2","key"});
cout<<"exists"<<ret<<endl;
}

keys
keys是用于查询库里的多个值。

keys的第一个参数是模式,第二个参数是一个插入迭代器,所以我们需要事先准备一个保存结果的容器,接下来再创建一个插入迭代器指向容器的位置。
cpp
void test2(sw::redis::Redis& redis)
{
redis.flushall();
redis.set("key1","111");
redis.set("key2","222");
redis.set("key3","333");
redis.set("key4","444");
vector<string> result;
auto it=std::back_inserter(result);
redis.keys("*",it);
for(auto x:result)
{
cout<<x<<" ";
}
cout<<endl;
}

我们知道迭代器一般有五种,输入迭代器,输出迭代器,单项迭代器,双向迭代器和随机访问迭代器,插入迭代器本质上就是一种输出迭代器,主要的功能就是把另外一个迭代器赋值给插入迭代器。
另外一个迭代器赋值给插入迭代器的作用是:比如说插入迭代器back_insert_iterator是it1,普通迭代器是it2,将it2赋值给it1后,相当于就是获取it2指向的元素,然后按照it当前的位置和动作将元素插入(比如说,插入迭代器是back_insert_iterator的话,那么就是执行将it2指向的元素插入it1指向的容器末尾,相当于调用一次pushback),这样可以实现解耦合的目标(keys和c++迭代器的解耦合)
ttl和expire
expire :给一个key设置过期时间,第二个参数chrono::seconds主要是为了让看代码的人更清楚单位。

cpp
void test3(sw::redis::Redis& redis)
{
redis.flushall();
redis.set("key1","111");
redis.expire("key1",std::chrono::seconds(3));
auto ret=redis.exists("key1");
cout<<"exists"<<ret<<endl;
sleep(4);
ret=redis.exists("key1");
cout<<"exists"<<ret<<endl;
}

c++标准库里也提供了一个函数叫sleep_for,因为不同的操作系统里提供了不同的sleep函数,所以使用标准库的函数可以有更好的兼容性。
ttl :用来看过期时间。

cpp
void test3(sw::redis::Redis& redis)
{
redis.flushall();
redis.set("key1","111");
redis.expire("key1",std::chrono::seconds(3));
auto ret=redis.ttl("key1");
cout<<"ttl"<<ret<<endl;
sleep(2);
ret=redis.ttl("key1");
cout<<"ttl"<<ret<<endl;
}

type
用于获取一个key对应的value的类型。

cpp
void test4(sw::redis::Redis& redis)
{
redis.flushall();
redis.set("key1","111");
auto ret=redis.type("key1");
cout<<"type:"<<ret<<endl;
}
