redis的C客户端---hiRedis使用

redis的C客户端—hiRedis使用

1. 客户端通信协议

Redis 制定了 **RESP(REdis Serialization Protocol,Redis 序列 化协议)**实现客户端与服务端的正常交互,这种协议简单高效,既能够被机器解析,又容易被人类识别。

1.1 发送命令格式

RESP 的规定一条命令的格式如下,CRLF 代表"\r\n"。

*<参数数量> CRLF 
$<参数1的字节数量> CRLF 
<参数1> CRLF
...
$<参数N的字节数量> CRLF 
<参数N> CRLF

例子:输入set hello world

*3    ---参数个数为3
$3    ---SET占3个字节
SET 
$5 
hello 
$5 
world

有一点要注意的是,上面只是格式化显示的结果,实际传输格式为如下代码:

*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$5\r\nworld\r\n

1.2 返回结果格式

Redis 的返回结果类型分为以下五种:

  • 状态回复:在 RESP 中第一个字节为"+"。
  • 错误回复:在 RESP 中第一个字节为"-"。
  • 整数回复:在 RESP 中第一个字节为":"。
  • 字符串回复:在 RESP 中第一个字节为"$"。
  • 多条字符串回复:在 RESP 中第一个字节为"*"。

平时使用redis-cli 没有出现相应字符,使用因为redis-cli.c文件对返回的结果进行了处理:

static sds cliFormatReplyTTY( redisReply *r, char *prefix) 
{ 
    sds out = sdsempty(); 
    switch (r-> type) 
    { 
        case REDIS_ REPLY_ ERROR: 
        // 处理 错误 回复 
        case REDIS_ REPLY_ STATUS: 
        // 处理 状态 回复 
        case REDIS_ REPLY_ INTEGER: 
        // 处理 整数 回复 
        case REDIS_ REPLY_ STRING: 
        // 处理 字符串 回复 
        case REDIS_ REPLY_ NIL: 
        // 处理 空 
        case REDIS_ REPLY_ ARRAY: 
        // 处理 多条 字符串 回复 
    }    
    return out; 
}

使用nc等命令可以得到真实的结果:

$ nc 127.0.0.1 6379
SET hello world
+OK

GET hello
$5
world

GET bad_key
$-1
  • 有一点需要注意,无论是字符串回复还是多条字符串回复,如果有 nil 值, 那么会返回$-1。

2. C 客户端 hiRedis

2.1 hiredis的安装

2.2 Synchronous API

/**Connecting*/
redisContext *redisConnect(const char *ip, int port);
redisContext *redisConnectWithTimeout(const char *ip, int port, timeval tv);

/**Sending commands*/
void *redisCommand(redisContext *c, const char *format, ...);
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

/*Cleaning up*/
void freeReplyObject(void *reply);
void redisFree(redisContext *c);
2.2.1 Connecting
redisContext *redisConnect(const char *ip, int port);
redisContext *redisConnectWithTimeout(const char *ip, int port, timeval tv);

参数说明:

  • ip:为redis数据库的IP地址,可以是远程的,也可以是本地的127.0.0.1
  • port:为redis数据监听的端口号,redis默认监听的端口号为6379
  • tv:连接请求超时时间

返回值:

  • redisContext 中的err为返回的错误码(正确则返回0),errstr为错误描述。
typedef struct redisContext {
    int err; /* Error flags, 0 when there is no error */
    char errstr[128]; /* String representation of error when applicable */
    int fd;
    int flags;
    char *obuf; /* Write buffer */
    redisReader *reader; /* Protocol reader */
    enum redisConnectionType connection_type;
    struct timeval *timeout;
    struct {
        char *host;
        char *source_addr;
        int port;
    } tcp;
    struct {
        char *path;
    } unix_sock;
} redisContext;

设置错误的非零常量有:

  • REDIS_ERR_IO:创建连接时出现 I/O 错误,尝试写入套接字或从套接字读取。
  • REDIS_ERR_EOF:服务器关闭导致空的读取的连接。
  • REDIS_ERR_PROTOCOL:解析协议时出错。
  • REDIS_ERR_OTHER:任何其他错误。目前,仅当指定的连接主机名无法解析时才使用。
//使用示例
redisContext *context = redisConnect("127.0.0.1", 6379);
if (context == NULL || context->err) {
    if (context) {
        printf("Error: %s\n", context->errstr);
        // handle error
    } else {
        printf("Can't allocate redis context\n");
    }
}

注意事项:

  • redisContext is not thread-safe.
2.2.2 Sending commands
void *redisCommand(redisContext *context, const char *format, ...);

参数:

  • context:是一个reidsConnect函数返回的一个对象。
  • 这个函数是一个带有不定参数的。可以按着format格式给出对应的参数,这就和printf函数类似。

返回值:

  • 失败时返回NULL,成功时返回值是一个void类型的指针,实际为指向一个redisReply类型的指针。
/* This is the reply object returned by redisCommand() */
typedef struct redisReply {
    /*命令执行结果的返回类型*/
    int type; /* REDIS_REPLY_* */
    /*存储执行结果返回为整数*/
    long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
    /*字符串值的长度*/
    size_t len; /* Length of string */
    /*存储命令执行结果返回是字符串*/
    char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
    /*返回结果是数组的大小*/
    size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
    /*存储执行结果返回是数组*/
    struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;

redisReply中的type说明返回的类型:

  • REDIS_REPLY_STATUS:
    • 返回命令执行的状态, The status string can be accessed using reply->str. The length of this string can be accessed using reply->len.比如set foo bar 返回的状态为OK,存储在str当中 reply->str == “OK”,reply -> len == 2,为"OK"的长度。
  • REDIS_REPLY_ERROR:
    • 命令执行错误,错误信息存放在 reply->str当中。reply -> len 指定错误信息的长度。
  • REDIS_REPLY_INTEGER
    • 返回值为整数,The integer value can be accessed using the reply->integer field of type long long.
  • REDIS_REPLY_NIL
    • 返回值为空表示执行结果为空。
  • REDIS_REPLY_STRING
    • 返回值是字符串,字符串储存在redis->str当中,字符串长度为redis->len。
  • REDIS_REPLY_ARRAY
    • 返回值是数组,数组大小存在reply->elements里面,数组值存储在reply->element[i]里面。数组里面存储的是指向redisReply的指针,数组里面的返回值可以通过reply->element[i]->str来访问,数组的元素是type==REDIS_REPLY_STRING的redisReply对象指针。
2.2.3 Cleaning up
void freeReplyObject(void *reply);
void redisFree(redisContext *c);
  • Replies should be freed using the freeReplyObject() function. Note that this function will take care of freeing sub-reply objects contained in arrays and nested arrays, so there is no need for the user to free the sub replies (it is actually harmful and will corrupt the memory).
  • redisFree 函数会立即断开socket连接,并释放分配的资源

注意:

  • Important: the current version of hiredis (0.10.0) frees replies when the asynchronous API is used. This means you should not call freeReplyObject when you use this API. The reply is cleaned up by hiredis after the callback returns. This behavior will probably change in future releases, so make sure to keep an eye on the changelog when upgrading .

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值